001 -

• | Table of Contents
• | Index
• | Examples
DB2® Universal Database™ for OS/390™ v7.1 Application Certification Guide
By Susan Lawson
Publisher | : Prentice Hall PTR
Pub Date | : November 26, 2002
ISBN | : 0-13-100771-8
Pages | : 624
Slots | : 2

IBM's definitive DB2 UDB V7.1 application development reference and exam study guide for the OS/390 and z/OS platforms.

  • An official IBM self-study guide for the DB2 UDB V7.1 Family Application Development Exam (#514)

  • Expert DB2 programming tips, techniques, and guidelines from application development experts

  • Covers data structures, SQL, stored procedures, programming/language environments, debugging, tuning, and more

  • CD-ROM contains complete DB2 application development sample exam

  • The definitive, authoritative guide to DB2 OS/390 application development certification

  • Covers data structures, SQL, stored procedures, programming/language environments, debugging, tuning, and much more

  • Includes a full section on object-relational programming and other advanced techniques

  • Sample test questions help you prepare for the IBM DB2 UDB V7.1 Family Application Development Exam (#514)

IBM DB2 UDB Version 7.1 for OS/390 and z/OS delivers unparalleled performance, scalability, and reliability in today's enterprise business environments. Now, there's a complete, authoritative guide to developing applications with DB2 UDB V7.1 in both OS/390 and z/OS environmentsand preparing for the IBM DB2 UDB V7.1 Family Application Development Exam (#514).

This comprehensive day-to-day guide to DB2 UDB application development is also the only book that delivers the depth of knowledge professionals need to pass IBM's challenging application development exam for the OS/390 and z/OS platforms.

IBM Gold Consultant Susan Lawson presents hundreds of useful tips, practical techniques, and expert guidelines for every facet of DB2 UDB application development and every stage of the development process for both OS/390 and z/OS platforms. Coverage includes:

  • Foundations for effective DB2 development, including an overview of the DB2 UDB product family and DB2 for OS/390 data structures

  • SQL: basic concepts and coding techniques through advanced OLAP features, star schemas, and star joins

  • Stored procedures, including the SQL procedure language and IBM's Stored Procedure Builder

  • Best practices for application testing, debugging, and performance tuning

  • The full range of DB2 development tools, including ODBC/CLI, Java(tm), COBOL, C, C++, REXX, CAF, CICS, and RRSAF

  • Object-relational programming, including user-defined functions, user-defined data types, and triggers

  • In-depth coverage of locking and concurrency

Whether you're developing for DB2 UDB V7.1 in an OS/390 or z/OS environment, managing DB2 UDB V7.1 application development, preparing for DB2 UDB V7.1 Family Application Development, or all three, DB2 UDB for OS/390 Version 7.1 Application Certification Guide will be your single


ProQuest Information and Learning - DB2® Universal Database™ for OS/390™ v7.1 Application Certification Guide

ProQuest Information and Learning Company
Home Desktop Bookshelf Recent Searches Recent Pages Logout

About Safari | Terms of Service | Privacy Policy | Contact Us | Help | Submit a Problem
Copyright © 2002 Safari Tech Books Online. All rights reserved.
75 Arlington Street, Floor 3
Boston, MA 02116
1-800-889-3358


001 -

• | Table of Contents
• | Index
• | Examples
DB2® Universal Database™ for OS/390™ v7.1 Application Certification Guide
By Susan Lawson
Publisher | : Prentice Hall PTR
Pub Date | : November 26, 2002
ISBN | : 0-13-100771-8
Pages | : 624
Slots | : 2

Copyright
IBM DB2 Certification Guide Series
Acknowledgments
Preface
 | Part 1: Introduction to DB2 UDB for OS/390 and z/OS
 | Part 2: Structured Query Language
 | Part 3: Developing Applications
 | Part 4: Programming and Language Environments
 | Part 5: Advanced Programming Functions
Part 1. Introduction to DB2 UDB for OS/390 and z/OS
 | Chapter 1. Product Overview
 |  | DB2 and E-Business
 |  | DB2 Universal Database
 |  | DB2 Middleware and Connectivity
 |  | DB2 Application Development
 |  | DB2 Administration
 |  | Data Management Tools
 |  | Summary
 |  | Additional Product Resources
 | Chapter 2. Database Objects
 |  | Understanding Data Structures
 |  | Managing Database Objects
 |  | Database Design and Implementation
 |  | Access to DB2 Objects
 |  | Summary
 |  | Additional Resources
Part 2. Structured Query Language
 | Chapter 3. Basic SQL Coding
 |  | Data Retrieval
 |  | Data Modification
 |  | Summary
 |  | Additional Resources
 | Chapter 4. Advanced SQL Coding
 |  | Subqueries
 |  | Unions
 |  | Nested Table Expressions
 |  | Joins
 |  | CASE Expressions
 |  | Row Expressions
 |  | OLAP Features
 |  | Summary
 |  | Additional Resources
Part 3. Developing Applications
 | Chapter 5. Using SQL in an Application Program
 |  | DB2 Application Development Environment
 |  | Delimiting SQL in a Program
 |  | Declaring Table and View Definitions
 |  | Host Variables and Host Structures
 |  | SQL Execution Validation
 |  | Using Cursors
 |  | Using Dynamic SQL
 |  | Summary
 |  | Additional Resources
 | Chapter 6. Binding an Application Program
 |  | Precompile and Bind
 |  | Plan or Package Ownership
 |  | Summary
 |  | Additional Resources
 | Chapter 7. Application Program Features
 |  | Application Program Features
 |  | Commit, Rollback, and Savepoint
 |  | Global Transactions
 |  | Global Temporary Tables
 |  | Fetch for Limited Rows
 |  | Identity Columns
 | Chapter 8. Stored Procedures
 |  | Stored Procedures
 |  | Benefits
 |  | Writing Stored Procedures
 |  | Defining Stored Procedures
 |  | Execution Environments
 |  | SQL Procedure Language
 |  | Stored Procedure Builder
 |  | Summary
 |  | Additional Resources
 | Chapter 9. Testing and Debugging Applications
 |  | Establishing a Test Environment
 |  | Debugging Application Programs
 |  | Locating the Problem
 |  | Testing and Debugging Stored Procedures
 |  | Summary
 |  | Additional Resources
 | Chapter 10. Accessing Distributed Data
 |  | Distributed Data
 |  | Coding Methods for Distributed Data
 |  | Programming Considerations
 |  | Remote Query Performance
 |  | Summary
 |  | Additional Distributed Resources
Part 4. Programming and Language Environments
 | Chapter 11. ODBC/CLI Programming
 |  | Embedded Dynamic Versus Call-Level Interface
 |  | The DB2 ODBC Environment
 |  | Handles
 |  | Database Connections
 |  | Transaction Control
 |  | Executing SQL Statements
 |  | Retrieving Results
 |  | ODBC Stored Procedures
 |  | Error Handling and Problem Determination
 |  | Sample Program
 |  | Summary
 |  | Additional Resources
 | Chapter 12. DB2 Traditional Programming
 |  | COBOL
 |  | C and C++
 |  | REXX
 |  | Summary
 |  | Additional Resources
 | Chapter 13. Java Programming
 |  | DB2 and Java
 |  | JDBC
 |  | SQLJ
 |  | Design Guidelines for Applications
 |  | Java Stored Procedures and UDFs
 |  | Summary
 |  | Additional Resources
 | Chapter 14. Attachment Programming
 |  | Attachments
 |  | TSO
 |  | CICS
 |  | IMS
 |  | Call Attachment Facility
 |  | RRSAF
 |  | Summary
 |  | Additional Resources
Part 5. Advanced Programming Functions
 | Chapter 15. Object-Relational Programming
 |  | Triggers
 |  | Object-Relational Extensions
 |  | Extenders
 |  | LOB and Extender Usage
 |  | Enabling Extenders
 |  | Summary
 |  | Additional Resources
 | Chapter 16. Locking and Concurrency
 |  | Locking Data
 |  | Avoiding Locks
 |  | System Parameters
 |  | Claims and Drains
 |  | Locking Issues and Problems
 |  | Summary
 |  | Additional Resources
 | Chapter 17. Application Performance and Optimization
 |  | Elements of Performance
 |  | Tuning Guidelines
 |  | Access Paths and Optimization
 |  | Designing Indexes for Performance
 |  | Query Parallelism
 |  | Database Monitoring
 |  | Tracing Problems in DB2
 |  | Using DISPLAY Commands
 |  | Summary
 |  | Additional Resources
 | Appendix A. IBM Certified Solutions ExpertDB2 UDB Family Application Development
 |  | Certification Test Objectives
 |  | Sample Test
 | Chapter B. Resources
 |  | DB2 Universal Database Server for OS/390 v7 Product Libraries
 | Chapter C. DB2CERT Database DDL
Index

Top


002 - Copyright

Team-Fly
DB2® Universal Database™ for OS/390™ v7.1 Application Certification Guide
By Susan Lawson
Table of Contents

Copyright

Library of Congress Cataloging-in-Publication Data

Lawson, Susan.

DB2 Universal Database for OS/390 v7.1 application certification guide / Susan Lawson.

p. cm. -- (IBM DB2 certification guide series)

Includes bibliographical references and index.

ISBN 0-13-100771-8 (paper)

1. Electronic data processing personnel--Certification. 2. IBM software--Examinations--Study guides. 3. IBM Database 2. 4. OS/390. I. Title. II. Series.

QA76.3 .L39 2003

005.75'85--dc21 2002034383

© Copyright International Business Machines Corporation 2003. All rights reserved.

Note to U.S. Government Users Documentation related to restricted rights Use, duplication, or disclosure is subject to restrictions set forth in GSA ADP Schedule Contract with IBM Corp.

Editorial/production supervision: Patti Guerrieri

Cover design director: Jerry Votta

Cover design: Anthony Gemmellaro

Manufacturing buyer: Alexis Heydt-Long

Acquisitions editor: Victoria Jones

Editorial assistant: Michelle Vincenti

Marketing manager: Debby vanDijk

Published by Pearson Education, Inc.

Publishing as Prentice Hall Professional Technical Reference

Upper Saddle River, NJ 07458

Prentice Hall books are widely used by corporations and government agencies for training, marketing, and resale.

For information regarding corporate and government bulk discounts please contact:

Corporate and Government Sales (800) 382-3419 or corpsales@pearsontechgroup.com

Other company and product names mentioned herein are the trademarks or registered trademarks of their respective owners.

The licensed work is provided to you on an "as-is" basis without warranty or condition of any kind, either express or implied, including, but not limited to, warranty or condition of merchantable quality or fitness for a particular purpose.

All rights reserved. No part of this book may be reproduced, in any form or by any means, without permission in writing from the publisher.

Printed in the United States of America

10 9 8 7 6 5 4 3 2 1

Pearson Education LTD.

Pearson Education Australia PTY, Limited

Pearson Education Singapore, Pte. Ltd.

Pearson Education North Asia Ltd.

Pearson Education Canada, Ltd.

Pearson Educación de Mexico, S.A. de C.V.

Pearson Education Japan

Pearson Education Malaysia, Pte. Ltd.

Dedication

This book has been dedicated in the memory of its coauthor, Richard Yevich. Richard passed away on January 20, 2002, after a brief illness. I promised Richard this book would be finished following in the tradition of his style and commitment. I could never have completed it, however, without the help of the extraordinarily talented people who are the essence of YL&A and its mission.

    Team-Fly


003 - IBM DB2 Certification Guide Series

Table of Contents

IBM DB2 Certification Guide Series

DB2 Universal Database for OS/390 v7.1 Application Certification Guide
by Lawson

DB2 Universal Database v7.1 Application Development Certification Guide
by Sanyal, Martineau, Gashyna, and Kyprianou

DB2 Universal Database v8 for UNIX, Linux, and Windows Administration Certification Guide, Fifth Edition
by Baklarz and Wong

DB2 Universal Database in Application Development Environments
by Shirai, Barber, Saboji, Naick, and Wilkins

DB2 Universal Database v6.1 Certification Guide, Third Edition
by Cook, Harbus, and Shirai

DB2 Universal Database in the Solaris Operating Environment
by Shirai, Michel, Wilding, Logan, and Bauch

DB2 Cluster Certification Guide
by Cook, Janacek, and Snow

DB2 Universal DRDA Certification Guide
by Brandl, Bullock, Cook, Harbus, Janacek, and Le

DB2 Replication Certification Guide
by Cook and Harbus

DB2 Universal Database and SAP R/3, Version 4
by Bullock, Cook, Deedes-Vincke, Harbus, Nardone, and Neuhaus

The Universal Guide to DB2 for Windows NT
by Cook, Harbus, and Snow


004 - Acknowledgments

Acknowledgments

Terry Purcell (senior consultant, YL&A) brought his amazing knowledge of SQL and performance tuning to all of the SQL chapters.

Dan Luksetich (Senior Consultant, YL&A) helped complete the chapters on object-relational programming, stored procedures, and traditional programming from real-life work experience and expertise.

John Maenpaa (software development manager, YL&A) gave terrific insight to programming with ODBC/CLI, the DB2 attachment facilities, and stored procedures.

Tom Ubelhor (senior consultant, YL&A) brought years of programming experience to the Java chapter.

Larry Hubbard (senior consultant, YL&A) helped to bring real-life experience and advice to the locking and concurrency chapter.

I also acknowledge the entire staff at YL&A whose love and support have gotten me through the loss of my best friend and business partner. This includes Jim Bishop, Kevin Davis, Susan Schneider, Lisa Camacho, Paula Cochran, Ed Wuttke, Paul Riker, Michelle Paoni, Dan Underwood, Phayzon Trice, Mike Ward, Muhammad Owais, Malavika Mantry, Cathy Rowe, Kevin Womack, Jeremy Peck, Amber Lamb, Laurentiu Bradin, King Moy, and of course my husband, Alex Lawson.

Heartfelt thanks go to my friends and coworkers at TransUnion, LLC, for supporting us during this time.

Special acknowledgments go to the tireless reviewers of this book including, James Huddleston, ACM; Klaas Brant, KBCE; Jan Henderyckx, Brainware; Cliff Burns, TransUnion, LLC; and many at IBM, especially Susan Visser.


005 - Preface

Preface

This book is an application programming guide to IBM's relational database server known as DB2 Universal Database Version 7.1 for OS/390 and z/OS. Its purpose is to provide guidance for taking the 514 DB2 Application Certification exam. However, it is much more than that. It is a compilation of information necessary to develop applications for DB2 V7 for OS/390 and z/OS. It also contains hints and tips from real-world experience in this environment.

The 514 exam covers DB2 on all platforms, including OS/390 and z/OS. For information regarding developing applications on platforms other than these two, please refer to the book authored by Tetsuya Shirai, John Barber, Mohan Saboji, Indran Naick, and Bill WilkinsIBM DB2 UDB Application Development Environments (also published by Prentice Hall).

Those interested in becoming an IBM Certified Professional will want to review the sample questions at the end of this book.

The book is divided into five parts.


006 -

Preface

Part 1: Introduction to DB2 UDB for OS/390 and z/OS

This section covers the fundamentals about the DB2 product family and the basics about the DB2 for OS/390 data structures. This information is the foundation on which applications are built in this environment. Understanding these concepts will lead to proper development with the appropriate tools.


007 -

Preface

Part 2: Structured Query Language

Part 2 covers the most robust query language: SQL (Structured Query Language). We look at basic SQL coding concepts and what the SQL language is comprised of. We then take a more in-depth look at some of the advanced features of the language.


008 -

Preface

Part 3: Developing Applications

This section is the heart of the book in terms of how to code an application in order to communicate with DB2. We first look at how to use SQL in an application program and then how to bind these programs to DB2 in order for them establish access paths to the DB2 data.

Some of the additional features of DB2 application programs are examined in terms of how we can use them to make our applications more useful and how to push more work into the DB2 engine. We then look at stored procedures, which provide us not only a way to encapsulate our code, but also a method for reducing traffic across the network. The new SQL procedure language is discussed as well as the use of the Stored Procedure Builder. We then examine how to best test and debug applications before they go into production. Finally, we look at how to access distributed data from our DB2 server within our application programs.


009 -

Preface

Part 4: Programming and Language Environments

Part 4 looks at how some of our more traditional programming languages, such as COBOL, C, C++, and REXX, access DB2. We then look at some more current methods, such as ODBC/CLI programming and Java. We also take a look at attachment programming techniques using CAF, CICS, and RRSAF.


010 -

Preface

Part 5: Advanced Programming Functions

In Part 5 we discuss the features of DB2 that support object-relational programming, such as user-defined functions, user-defined data types, and triggers. We also look at important aspects of application performance in terms of how to diagnose and tune problems. This includes looking at explain output and comparing it to available indexes and the SQL coding techniques.

Locking and concurrency is also a very important issue, because we have to be able to run several applications at the same time and to get the work through the system in an appropriate amount of time, while keeping the integrity of our data intact. In this section we look at all the options for locking and how to use them for best concurrency.

This book can be used as a self-study guide to help you prepare for the 514 DB2 Application Certification exam or simply as a guide to developing applications in a DB2 Universal Database V7.1 for OS/390 and z/OS environment. For information about the DB2 UDB family, refer to the other IBM certification books.


011 -

Part 1: Introduction to DB2 UDB for OS/390 and z/OS

    Chapter 1. Product Overview

    Chapter 2. Database Objects


012 - Chapter 1. Product Overview

Part 1. Introduction to DB2 UDB for OS/390 and z/OS

Chapter 1. Product Overview

  • DB2 Universal Database

  • DB2 Middleware and Connectivity

  • DB2 Application Development

  • DB2 Administration

  • DB2 Data Management Tools

This chapter introduces you to the DB2 Universal Database (DB2 UDB) family of products for S/390, zSeries, UNIX, and Intel platforms. DB2 has the ability to store all kinds of electronic information: traditional relational data as well as structured and unstructured binary information; documents and text in many languages; graphics; images; multimedia (audio and video); information specific to operations like engineering drawings, maps, insurance claims forms, numerical control streams; and any type of electronic information. This chapter illustrates some of the ways to access data in a DB2 database using some of the interfaces provided with the products. A description of each DB2 product is provided to illustrate some of the features and functions.

The DB2 database is an important part of IBM's e-business software portfolio. The e-business Application Framework (see Figure 1-1) provides an open blueprint on how to build e-business applications. Popular IBM e-business tools include Visual Age for Java for developing Java programs or components and Tivoli software for distributed systems management. As for application server software, IBM offers several types of servers depending on the business requirement, from message queuing (MQ) software to Java-based transaction processing with WebSphere Application Server.

Figure 1-1. The e-business Application Framework.

The most popular IBM software servers are its database servers, specifically the DB2 family.

The DB2 family executes on pervasive devices, Intel, UNIX, AS/400, and mainframe platforms (OS/390, z/OS, and Linux). Supported operating environments include OS/2, Windows 95/98/2000/NT, Linux, AIX, Hewlett-Packard's HP-UX, Sun Microsystems' Solaris, NUMA-Q, OS/400, VSE/VM, OS/390, and z/OS. The DB2 code base is optimized for each platform to ensure maximum performance. The SQL API is common to all platforms, which allows applications written on one platform to access data on any platform. Internally, DB2 on OS/400, VSE/VM, and OS/390 differ from DB2 on the UNIX and Intel platforms, but it is the common SQL API that enables applications to work together. The DB2 code base on Intel and UNIX platforms are identical.

DB2 provides seamless database connectivity using the most popular network communications protocols, including NetBIOS, TCP/IP, IPX/SPX, named pipes, and Advanced Program-to-Program Communication (APPC).


013 - DB2 and E-Business

Chapter 1. Product Overview

DB2 and E-Business

As a core component of IBM's e-business cycle, DB2 is a catalyst for delivering applications that transform a company's operations (see Figure 1-2). Transform is the process that takes a business to an e-business; common applications in this area include electronic commerce, enterprise resource planning (ERP), customer relationship management (CRM), and supply chain management (SCM). Build is the process of exploiting the integrated Java and multimedia features of DB2. Run is the part of the e-business cycle that ensures performance and scalability; this is especially important with the new Internet-based companies. Finally, with respect to leveraging data assets, DB2 offers a variety of business intelligence tools to enable end users to make more effective business decisions.

Figure 1-2. The e-business cycle.

In leveraging information in an e-business environment, IBM's Enterprise Information Portal (EIP) provides a secure foundation for a single point of access to diverse information, business processes, and expertise. Figure 1-3 shows the high-level integration of the EIP. Today's high demand for complete and correlated information requires portal access not only to structured transactional and warehouse data, but also to a broader range of content, including XML, HTML, host computer-generated output, images, and audio/video. The IBM Enterprise Information Portal offers access to business data from sources such as spreadsheets, document libraries, company literature, databases, data warehouses, and unstructured information from Web pages. The information can also be searched using parametric or contextual search technologies, with results aggregated across multiple sources and relevant information presented in a context tailored to the user's needs.

Figure 1-3. IBM's Enterprise Information Portal.

    Team-Fly
    Top


014 - DB2 Universal Database

Chapter 1. Product Overview

DB2 Universal Database

The DB2 UDB family (see Figure 1-4) consists of many different platforms that can coexist in a distributed environment:

  • z/OS or OS/390. This offering is the largest of the DB2 family, often serving as an enterprise server handling some of the largest applications in the world. The System/390 is IBM's largest hardware platform.

  • Enterprise Edition. This offering is often used to build e-business applications and to support large departmental applications. If offers the most connectivity options and can share data with third-party databases and DB2 on heterogeneous platforms.

  • Workgroup Edition. This offering is often used for smaller departmental applications or for applications that do not need access to remote databases on the OS/400, VSE/VM, or OS/390 platforms.

  • Enterprise-Extended Edition. This offering is used most often to support very large databases. Popular applications include supporting large data warehouses. By providing intraquery and interquery parallelism, databases can scale to multiple terabytes. DB2 UDB Enterprise-Extended Edition can exploit clusters or massively parallel hardware architectures.

  • Personal Edition. This full-function database offering is for standalone use and will not accept remote database requests. Personal Edition is available on Windows, OS/2, and Linux.

  • Satellite Edition. This offering is for single-users and has a smaller footprint than Personal Edition. It will not accept remote database requests. This offering is available on the Windows platform.

  • Everyplace. This is a mobile computing offering that gives mobile workers access to DB2 data sources in the enterprise through handheld devices such as personal digital assistants (PDAs) and handheld personal computers (HPCs).

Figure 1-4. DB2 Universal Database.

DB2 Everyplace

DB2 Everyplace (or DB2E) is a tiny "fingerprint" database of about 100K (see Figure 1-5). It is designed for low-cost, low-power, small form-factor devices such as PDAs, HPCs, or embedded devices. DB2 Everyplace runs on devices that use the Palm Computing platform, Windows CE, the EPOC operating system, and the QNX Neutrino. DB2 Everyplace provides a local data store on the mobile or embedded device for storing relational data from elsewhere in the enterprise. Relational data can be synchronized to the handheld device from other DB2 data sources, such as DB2 Universal Database for UNIX, OS/2, and Windows NT; DB2 for OS/390; and DB2 for AS/400. DB2 Everyplace with IBM Mobile Connect will also synchronize data from other open database connectivity (ODBC)-compliant data sources, such as Oracle and Microsoft databases.

Figure 1-5. DB2 Everyplace.

The DB2 Everyplace Sync Server mobilizes professionals with e-business information anywhere, anytime. It extends the power of DB2 to a wide range of handheld devices, such as those running the Palm Pilot.

DB2 Satellite Edition

DB2 Satellite Edition (see Figure 1-6) forms part of a DB2 solution to support systems that operate disconnected from the corporate system the majority of the time and connect occasionally to the corporations central database to exchange data. DB2 Satellite Edition is a full-function, high-performance DB2 database specially designed for occasionally connected workers running Windows operating systems. The satellite system itself does not require the user to manage the database. This means the end user is free to focus on business resultsthe user does not even need to know a database is installed.

Figure 1-6. DB2 Satellite environment.

The application areas that can benefit from this solution include contract management, insurance application automation, securities marketing, and automobile insurance claims processing. In addition, large-scale branch office deployments are being used to provide automation to franchise stores, insurance agents, and regional offices of large corporations. In these kinds of environments, the applications are custom built, purchased, or a combination.

The satellite environment administration model minimizes the cost of administering a large number of systems by administering collections of systems running the same application and database in groups. Scripts stored at a central administration control point are used to accomplish administrative tasks on the systems in a group. This model also allows for centralized problem determination.

Replication administration uses the same model. Replication subscription definitions are stored in a central control server as scripts. When executed at the satellite system, the scripts set up each satellite for replication with a corporate data store. DB2 Satellite Edition's small footprint and application compatibility with the rest of the DB2 family make it an ideal candidate for the delivery of distributed applications on systems that will occasionally connect with corporate data stores to exchange data.

This product is available only on the Windows platform.

DB2 Personal Edition

DB2 Personal Edition (DB2 PE) is a full-function database that enables a single user to create databases on the workstation on which it is installed. It can be used as a remote client to a DB2 server, since it also contains the DB2 client components.

The DB2 Personal Edition product is often used by end users requiring access to local and remote DB2 databases or by developers prototyping applications that will be accessing other DB2 databases.

Figure 1-7 shows an example of a DB2 Personal Edition installation. In this example, the user can access a local database on his or her desktop machine and access remote databases located on the database server. From the desktop, the user can make changes to the database throughout the day and replicate those changes as a client to the remote database on the DB2 server.

Figure 1-7. DB2 Personal Edition.

DB2 Personal Edition includes graphical tools (all of the other products include these tools as well, via the DB2 Administration Client component) that enable a user to administer, tune for performance, access remote DB2 servers, process SQL queries, and manage other servers from a single workstation. This product is available on Windows, OS/2, and Linux.

DB2 Workgroup Edition

DB2 Workgroup Edition (DB2 WE) is designed for use in a LAN environment. It provides support for both remote and local clients. A server with DB2 Workgroup Edition installed can be connected to a network and participate in a distributed environment, as shown in Figure 1-8.

Figure 1-8. DB2 Workgroup Edition with remote clients.

In Figure 1-8, App1 and App2 are local database applications. Remote clients can also execute App1 and App2 if the necessary setup has been performed. A DB2 application does not contain any specific information regarding the physical location of the database. DB2 client applications communicate with DB2 Workgroup Edition using a supported distributed protocol. Depending on the client and server operating systems involved, DB2 Workgroup Edition supports the TCP/IP, NetBIOS, IPX/SPX, named pipes, and APPC protocols.

DB2 Workgroup Edition includes DB2 Extenders, which provide the ability to manipulate data outside of conventional rows and columns, and Net.Data, a product that allows you to build Internet-ready applications that store data in DB2 databases. DB2 Workgroup is available on the Windows, OS/2, AIX, Solaris, HP-UX, and Linux platforms.

DB2 Enterprise Edition

DB2 Enterprise Edition (or DB2 EE) is fully Web-enabled; scalable from single processors to symmetric multiprocessors and to massively parallel clusters; and supports unstructured data such as image, audio, video, text, spatial, and XML with its object relational capabilities.

It includes all the functions found in DB2 WE. Applications for DB2 Enterprise Edition can scale upward and execute on massively parallel clusters or can scale downward with applications executing on single-user database systems. DB2 Enterprise Edition is available on the Windows, OS/2, Linux, and UNIX platforms.

DB2 Enterprise-Extended Edition

DB2 Enterprise-Extended Edition (or DB2 EEE) is the scalability option that enables DB2 to partition data across clusters or massively parallel computers (see Figure 1-9). It includes all the functionality found in DB2 EE and adds to it. To the end user or application developer, the database appears to be on a single computer. All SQL statements are processed in parallel, thus increasing the execution speed for any given query. DB2 Enterprise-Extended Edition is available on the Windows, AIX, Solaris, HP-UX, and NUMA-Q platforms.

Figure 1-9. DB2 processing a query in parallel.

DB2 for OS/390 and z/OS

DB2 for OS/390 and z/OS is a relational database management system that is the foundation of many e-business, business intelligence, and mission-critical systems. It is the primary focus of this certification guide. DB2 for OS/390 and z/OS is the largest of the DB2 family, often serving as an enterprise server handling many of the largest applications in the world. The environment provided by System/390 and either OS/390 or z/OS is IBM's largest and most powerful, providing the most scalable and available platform.


015 - DB2 Middleware and Connectivity

Chapter 1. Product Overview

DB2 Middleware and Connectivity

DB2 is a very open database and provides a variety of options for connecting to DB2 and non-DB2 databases.

  • DB2 Clients. Client code is required on workstations for remote users to access a DB2 database.

  • DB2 Connect. This product provides support for applications executing on UNIX and Intel platforms to transparently access DB2 databases on the OS/400, VSE/VM, OS/390, and Linux on S/390 environments. Note that DB2 Connect is not required to access DB2 for any of the UNIX or Intel platforms.

  • DB2 Net.Data. Provides the ability for a Web browser to access relational or nonrelational data. This middleware provides an easy way to embed database calls into a macrolanguage.

  • DB2 DataJoiner. This product allows DB2 clients to access, join, and update tables from heterogeneous databases, such as Sybase, Informix, and Microsoft SQL Server.

  • IBM Classic Connect. This product is a separately orderable component of DataJoiner that provides read-only access to nonrelational data stored in information management system (IMS) databases and virtual storage access method (VSAM) datasets on multiple virtual systems (MVSs).

  • DB2 Relational Connect. This product allows DB2 clients to access and join tables from DB2 and Oracle databases.

  • WebSphere Application Server. This application server is shipped with DB2 Enterprise Edition and allows developers to use Java as a platform in a transaction processing environment.

DB2 Universal Database Clients

DB2 supports a variety of clients. These clients include

  • Windows (2000, NT, 98, 95, and 3.x)

  • OS/2

  • AIX

  • HP-UX

  • SGI-IRIX

  • Linux

  • Solaris Operating Environment

  • Web browsers

DB2 Connect

The DB2 Connect product allows clients to access data stored on data servers that implement the Distributed Relational Database Architecture (DRDA). The target database server for a DB2 Connect installation is known as a DRDA Application Server (see Figure 1-10).

Figure 1-10. DRDA application flow.

NOTE

The most commonly accessed DRDA application server is DB2 for OS/390 and z/OS.

DB2 Connect supports both the TCP/IP and APPC DRDA communication protocols. The protocol supported depends on the DRDA application server being connected to and the version of the host software being run. For instance, a DB2 Connect server acting as a DRDA Application Requester to a host DRDA Application Server can connect to DB2 for OS/390 at version 5.1 and higher. Any of the supported network protocols can be used for a DB2 client to establish a connection to the DB2 Connect Server. Some of the major capabilities provided by DB2 Connect include

  • Support for open database connectivity (ODBC), object linking and embedding database (OLE DB), command-line interface (CLI), Java database connectivity (JDBC), and Structured Query Language for Java (SQLJ) applications.

  • Distributed Join across all DB2 databases.

  • Distributed Join with Oracle (via Relational Connect).

  • Connection pooling.

  • S/390 Sysplex Exploitation for failover and load balancing.

Some of the common uses of DB2 Connect are

  • Web-enabling DB2 OS/390 by providing browsers direct access.

  • Leveraging Microsoft applications written using ADO, ODBC, or OLE DB to transparently access DB2 on mainframe platforms.

  • Offloading mainframe development cycles.

The database application must request the data from a DRDA Application Server through a DRDA Application Requester.

NOTE

The DB2 Connect product provides the DRDA Application Requestor functionality.

The DRDA Application Server accessed using DB2 Connect could be any DB2 server on OS/390, VM, VSE, or OS/400. If TCP/IP is the protocol of choice, then the following are prerequisites:

  • DB2 for OS/390. Only version DB2 5.1 or higher supports TCP/IP in a DRDA environment.

  • DB2 for OS/400. Only OS/400 version 4.3 or higher supports TCP/IP.

  • DB2 Server for VSE/VM. Only version DB2 6.1 or higher for VM supports TCP/IP.

DB2 Connect is available as a server (Enterprise Edition) and as a single-user package (Personal Edition). The DB2 Connect Enterprise Edition product allows multiple clients to access host data. A DB2 Connect server routes the ability for multiple clients to access host data. A DB2 Connect server routs each database request from the DB2 clients to the appropriate DRDA Application Server. The remote client communicates with the DB2 Connect server using any of the supported communication protocols. DB2 Connect Personal Edition is available on Windows, OS/2, and Linux platforms. It provides access to the host database from the system where it is installed.

DB2 Net.Data

Net.Data provides high-performance Web applications with robust application development functions (see Figure 1-11). Net.Data exploits Web server interfaces (APIs), providing higher performance than common gateway interface (CGI) applications. Net.Data supports client-side processing as well as server-side processing with languages such as Java, REXX, Perl, and C++. Net.Data provides conditional logic, a rich macrolanguage, and support for Java, JavaScripts, and XML.

Figure 1-11. DB2 Net.Data.

In a Net.Data environment, users connected to the Internet or an intranet can access database applications. Users can either select automated queries or define new ones that retrieve specified information directly from a variety of data sources. The results are returned to the Web browser in HTML format. Net.Data not only allows access to DB2 data, but also offers native access to Oracle and Sybase, flat files, and other data sources that support ODBC.

DB2 DataJoiner

DB2 DataJoiner (see Figure 1-12) provides application access to both DB2 and multivendor relational databases such as Microsoft, Sybase, and Informix. It acts as middleware for access to heterogeneous data sources. With a single SQL statement, an application can transparently access, join, and update data located across multiple data sources. The access can be done without needing to know the location of the data or the specifics of the SQL dialects for the data source. DataJoiner can run on Windows NT, Windows 2000, AIX, Solaris, or HP-UX.

Figure 1-12. DB2 DataJoiner.

DB2 Relational Connect

DB2 Relational Connect provides applications access to both DB2 and Oracle (see Figure 1-13). This is particularly useful if there is a heterogeneous database environment where DB2 and Oracle coexist, and need to share data.

Figure 1-13. DB2 Relational Connect.

IBM WebSphere Application Server

IBM WebSphere Application Server is built on an open Java-based platform that enables applications to leverage existing application resources and access various databases, including DB2. It is part of the WebSphere family of products that help you develop and manage high-performance Web sites and to integrate those Web sites with new or existing non-Web business systems. Some of the capabilities of WebSphere Application Server include use of

  • Java servlets

  • Java Server Pages

  • XML

With these capabilities, you can quickly transform static Web sites into vital sources of dynamic Web content. Enterprise Java Beans (EJB) can also be used for implementing EJB components that incorporate business logic. WebSphere Application Server is packaged with DB2.


016 - DB2 Application Development

Chapter 1. Product Overview

DB2 Application Development

DB2 offers a rich application development environment that allows developers to build databases supporting requirements for e-business and business intelligence applications. Many of these tools are integrated with the database; the major tools are reviewed next:

  • Stored Procedure Builder. Enables the creation, testing, and debugging of stored procedures on local and remote DB2 servers.

  • DB2 Relational Extenders. Enables the SQL API to access unstructured data types, including text, image, audio, video, and XML.

  • DB2 OLAP Server Starter Kit. Provides the ability to build online analytical processing (OLAP) cubes using DB2 as the relational data store; a higher end version, DB2 OLAP Server, is available to handle larger numbers of users.

  • DB2 Data Warehouse Center. Provides the ability to build data marts/warehouses by automating the processes involved in managing, refreshing, moving, and transforming data, including the ability to define the star schema model.

  • DB2 Data Warehouse Manager. Provides all the capabilities of the Data Warehouse Center, but supports more data sources and includes the Information Catalog, Query Patroller, and Query Management Facility (QMF) for Windows.

  • QMF. Provides an integrated, powerful, and reliable query and reporting tool set for DB2 data. There is also an optional QMF for Windows.

DB2 Stored Procedure Builder

The DB2 Stored Procedure Builder (see Figure 1-14) is a graphical Windows application that runs on Windows, AIX, and Solaris that supports the rapid development of DB2 stored procedures written in either Java or SQL Procedure Language with SQL procedure statements. It can work as a Microsoft Visual Studio plug-in or with Microsoft Visual Basic, IBM VisualAge for Java, or standalone. The Stored Procedure Builder (SPB) supports the entire DB2 family from a single development environment. It has facilities for debugging and deploying stored procedures.

Figure 1-14. DB2 Stored Procedure Builder.

DB2 OLAP Server

The DB2 OLAP Server can be used for developing analytic applications in order to give your organization an edge on the competition. The DB2 OLAP Server presents the data in business dimensions, such as category of data or time period, allowing you to ask questions intuitively. The DB2 OLAP server helps you to do fast, intuitive, multidimensional analysis (see Figure 1-15).

Figure 1-15. Multidimensional cube.

There are many advantages offered by the DB2 OLAP Server, because it integrates the popular Hyperion Essbase OLAP product with the e-business-ready IBM Universal Database family, including DB2 for OS/390. The DB2 OLAP Server allows you to analyze data on OS/390 using popular Web and desktop tools such as Microsoft Excel, Lotus 1-2-3, Hyperion Wired for OLAP, Cognos PowerPlay, Brio products, and Business Objects. It also works with Web-ready tools to support full-function access to the analytical applications. Tools such as Hyperion Wired for OLAP allow you to deliver applications on the Web to different users. The OLAP Server also provides concurrent read-write support for "what-if" analysis for such tasks as forecasting and budgeting. OLAP Server combines the flexibility of a relational database management system and the performance of a multidimensional store.

The DB2 OLAP Server runs on

  • OS/390

  • AIX

  • HP-UX

  • OS/400

  • Solaris Operating Environment

  • Windows

Many applications and tools that support DB2 OLAP Server are available in the marketplace, or you can create your own application.

DB2 Relational Extenders

DB2 Relational Extenders (see Figure 1-16) offer the ability to manipulate data outside of conventional rows and columns to include the manipulation of text, image, audio, video, and XML data types. The DB2 Relational Extenders encapsulate the attributes, structure, and behavior of these unstructured data types and stores this information in DB2. From the developer's perspective, the DB2 Relational Extenders appear as seamless extensions to the database and enable the development of the multimedia-based applications. The following DB2 Relational Extenders are provided by IBM:

  • Text Extender

  • Image Extender

  • Audio Extender

  • Video Extender

  • XML Extender

  • Net.Search Extender (Solaris, NT only)

  • Spatial Extender

Figure 1-16. DB2 Relational Extenders.

The purpose of the DB2 Relational Extenders is to provide for the management of unstructured data through the SQL API. By preserving the current investment in relational applications, new nontraditional applications can be introduced by leveraging existing skills. This open environment enables developers and independent software vendors to develop and introduce their own extenders as extensions to DB2.

The XML extender is provided with DB2 and allows you to store eXtensible Markup Language (XML) documents as a new column datatype (see Figure 1-17). You also have the ability to decompose and store XML in its component parts as columns in multiple tables. In either case, indexes can be defined over the element of attributes of an XML document for fast retrieval. Furthermore, text search and section search can be enabled on the XML column or its decomposed part via DB2 Text Extender. You can also formulate an XML document from existing DB2 tables for data interchange in business-to-business environments.

Figure 1-17. XML Extender.

QMF

QMF is an optional, tightly integrated, powerful, and reliable query and reporting tool set for DB2. With QMF you can execute queries, format reports, and build procedures to perform multiple activities. QMF stores the queries, forms, and procedures in its own database so you can reuse them.

QMF for Windows

QMF for Windows is an easy-to-use query and reporting tool for publishing reports either locally or onto the Internet (see Figure 1-18). It also integrates with other Windows desktop tools. It can be used to access DB2 on OS/390 via DB2 Connect. With QMF for Windows, end users can easily do the following:

  • Build queries and reports easily, using its graphical interface.

  • Integrate query results with desktop tools such as spreadsheets and personal databases.

  • Rapidly build data access and update applications.

  • Exploit DB2 performance and all of its SQL capabilities.

Figure 1-18. QMF for Windows.

DB2 Warehouse Center and Warehouse Manager

The DB2 Warehouse Center and Warehouse Manager are tools that provide a way to access, manage, build, and control data warehouses built in DB2. The DB2 Warehouse Center provides agents that manage the flow of data between the sources and targets in the warehouse. One very nice feature is the means for cleansing data, generating keys, and pivoting data by means of Java stored procedures and user-defined functions. There are also extensive reporting capabilities. An unlimited license for QMF for Windows is included in the product.

These warehouse functions are managed through a component called the Data Warehouse Center (see Figure 1-19). The Data Warehouse Center is itself incorporated into the Control Center. The Data Warehouse Center includes functions to define data sources, manage data movement and transformation, populate the metadata repository, and create generic schema models, including the logical star model for the DB2 OLAP Server.

Figure 1-19. Data Warehouse Center.

A set of warehouse transformers is included for data cleansing, generating key columns and period tables, and inverting and pivoting data. A wide selection of statistical transformers performs basic statistics, subtotals, rollups, cube calculations, moving averages, regression, correlation analysis, and other functions. In all, there are over 100 built-in transformers. You can also build user-defined functions to create your own transformers.

There is an important DB2 family benefit with the DB2 Warehouse Manager. It can be used for either OS/390-to-OS/390 point-to-point data movement or point-to-point to any member of the DB2 family. With federated data access provided by DB2 DataJoiner integration, the warehouse center can be used to manage the process of moving data from Oracle to DB2 as well.

When this product is purchased with DB2 for OS/390, it includes not only the workstation graphical user interface (GUI) control center, but also a full set of procedures for managing the warehouse and data natively on OS/390. The replication controls with Warehouse Center also allow for heterogeneous data sourcing into a warehouse on any of the possible target platforms.

With DB2 Warehouse Manager for OS/390, the QMF family includes QMF for Windows, QMF for OS/390, and QMF High Performance Option (HPO) for query and management of your OS/390 warehouse.


017 - DB2 Administration

Chapter 1. Product Overview

DB2 Administration

DB2 has several tools available to help with administration of the subsystem environment and database objects. Some of these tools are optional and Windows-based.

  • DB2 Installer. Provides a GUI for installing DB2 from a workstation.

  • Control Center. Provides a single point of entry for controlling the entire DB2 family. Can use the Control Center to display database objects and their relationships to each other.

  • Visual Explain. Gives the user a graphical tool to analyze the access paths that DB2 chooses for SQL queries or statements.

  • Index Advisor. Assists in choosing an optimal set of indexes for table data.

  • DB2 Estimator. Provides a facility for estimating the performance of applications.

DB2 Installer

The DB2 Installer (see Figure 1-20) provides a GUI for installing DB2 for OS/390 and z/OS from a workstation. An element of the DB2 Management Tools Package, DB2 Installer provides an alternative to the interactive system product facility (ISPF) installation panels and CLISTs traditionally used on OS/390 systems.

Figure 1-20. DB2 Installer.

The DB2 Installer application illustrates the overall installation process and keeps a graphical record of how each subsystem is defined. You can use DB2 Installer to increase your productivity. It has a command center from which you can install, migrate, or update DB2 for OS/390. The graphical interface follows an easy-to-read map through the entire installation process, including system modification program/extended (SMP/E), fallback, and sample jobs. In addition, it provides a graphical record of completed and uncompleted tasks by subsystem.

DB2 Installer helps you in the following:

  • Installation. Prompts you for the appropriate fields necessary to customize DB2 for OS/390 installation jobs. These installation jobs are executed from your workstation or can be uploaded to the host for execution.

  • Migration. Generates DB2 for OS/390 migration jobs and makes you aware of parameters you might want to customize to take advantage of new functions. It also generates an optional set of jobs that check for catalog consistency and other migration considerations.

  • Update. Allows you to modify the current parameters and saves each updated set of parameters in a unique file.

There is also data-sharing support so you can use DB2 Installer to enable, add, or migrate datasharing members. It also comes with a full help facility.

Control Center

The Control Center supports the entire DB2 family including OS/390. The Control Center can be used as a single point of entry for controlling the entire DB2 family. You can use the Control Center to display database objects and their relationships to each other. The Control Center has a GUI that allows you to easily manage local and remote servers from a single workstation (see Figure 1-21).

Figure 1-21. DB2 Control Center.

The Control Center supports DB2 functions through the following components:

  • Menu Bar. Used to access Control Center functions and online help.

  • Toolbar. Used to access the other administration tools.

  • Objects Pane. This is shown on the left side of the Control Center window. It contains all the objects that can be managed from the Control Center as well as their relationship to each other.

  • Contents Pane. This is found on the right side of the Control Center window and contains the objects that belong or correspond to the object selected on the Objects Pane.

  • Contents Pane Toolbar. These icons are used to tailor the view of the objects and information in the Contents pane. These functions can also be selected in the View Menu.

You can also launch other tools, such as DB2 Warehouse Manager, DB2 Performance Monitor, DB2 Visual Explain, Command Center, Script Center, Stored Procedure Builder, and more. Some of the types of support items in the Control Center added for OS/390 include

  • Utility Support. Support for utility wildcarding gives the ability to execute utilities against a list of objects matching a specified pattern of matching characters. There is also support for restarting utilities from the last committed phase or the last committed point. This is available only for utilities originally started in the Control Center.

  • Dataset Management. Ability to manage your datasets via the Control Center. This allows you to retrieve dataset lists, and depending on the type of dataset, you can show, rename, and delete members. Datasets can be dynamically allocated for utilities through the use of dataset templates used to automatically generate datasets based upon a defined set of criteria.

  • DDL (Data Definition Language) Generation. A feature used to recreate database objects and dependent objects for the DB2 catalog. The output then can be saved to an OS/390 dataset (maybe for input to sequential processing using file input [SPUFI]) or to a workstation file.

  • Integrated SQL Assist. Assists in helping build standalone SQL statements or SQL statements in triggers or views. The SQL statement will be inserted into the text area of the dialog after it is created.

  • Wizards. Wizards are help screens that guide you through several different activities, such as creating objects. Each wizard has detailed information available to help perform these tasks. Wizards are integrated into the administration tools and assist in completing various tasks, such as Add Database. Wizards are invoked from the Control Center. They extract information, ask questions about the tasks being performed, then run any necessary calculations to help determine appropriate settings.

Visual Explain

DB2 Visual Explain (see Figure 1-22) lets you graphically analyze the access paths that DB2 chooses for your SQL queries or statements. The graph of the access path is displayed on an IBM OS/2 or Microsoft Windows NT workstation, eliminating the need to interpret the plan table output manually.

Figure 1-22. Visual Explain.

This tool offers suggestions for improving the performance of your SQL queries or statements. You can change an SQL statement and dynamically explain it to see if the access path is improved by the change. You can also use it to browse the current values of subsystem parameters.

Visual Explain issues DRDA queries through a DB2 client on the workstation to get the information it needs.

DB2 Visual Explain helps database administrators and application developers:

  • Graphically see the access path for a given SQL statement.

  • View statement cost in milliseconds and service units.

  • Tune SQL statements for better performance.

  • View the current values for subsystem parameters.

  • View catalog statistics for tables and indexes.

  • Generate custom reports.

Index Advisor

The Index Advisor is a tool to assist in choosing an optimal set of indexes for table data. This tool helps to determine the best indexes for a problem query or for a particular set of queries. It is helpful for testing an index on a workload without having to create the index.

This process is performed by creating a modeling database for DB2 for OS/390 and z/OS on a DB2 for UNIX, Windows, or OS/2 workstation using configuration parameters to mimic DB2 for OS/390. One way to invoke this tool is through the Control Center.

This tool works on a set of dynamic SQL statements, which have to be processed over a given period of time, and it handles SELECT, INSERT, UPDATE, and DELETE statements. In addition, it uses statistics from the system and user input to be able to evaluate strategies for given workloads. It also scans the catalog tables holding SQL from bound applications and can make determinations and suggestions.

DB2 Estimator

DB2 Estimator is an easy-to-use, standalone tool for estimating the performance of DB2 applications. It can be run on PCs that support Microsoft Windows 3.1, 95, 98, NT, 2000, or OS/2. It supports simple table sizing up to a detailed performance analysis of an entire DB2 application. DB2 Estimator saves time and lowers costs by allowing you to investigate the impact of new or modified applications on your production system before you implement them. DB2 Estimator provides information such as

  • Elapsed time for a SQL statement that fetches N rows.

  • Processor resource used during an N-way join.

  • Impact of adding and dropping an index from a table.

  • System support ability for an anticipated increase in workload.

  • Effects of doubling processor resource on transaction response time.

  • Storage required for a new table and its indexes.

  • Index support for predicates.

  • Effect of doubling table size on performance.

  • Ability of application to complete within a batch window.

  • Execution time of utility jobs.

  • Effects of data compression.

  • Effects of data sharing.

  • Effects of triggers.

DB2 Estimator lets you change your definitions easily to help you evaluate alternative designs. By comparing the cost and performance of these designs, you can determine which design provides the optimum cost/performance ratio before you invest valuable time and resources coding your application or creating a real database. It helps you build more efficient databases by building a model of your system, based on your data knowledge, with reasonable access paths for your SQL statements. If actual DB2 information is available through DB2 Explain and/or DB2 Performance Monitor, you can tune the model by overriding the model assumptions. You can also import table, index, and SQL statements from your DB2 database to DB2 Estimator, and then modify them to suit your modeling requirements.


018 - Data Management Tools

Chapter 1. Product Overview

Data Management Tools

IBM has made a commitment to delivering a quality set of tools as viable alternatives to third-party tools. These tools are offered in the Data Management toolset and are designed to perform at the level that today's systems required. The tools are divided into four categories: Database Administration, Database Performance Management, Database Recovery and Replication, and Database Application Management.

  • DB2 Administration Tool. Provides a comprehensive set of functions to efficiently and effectively manage DB2 environments.

  • DB2 Automation Tool. Continuously and automatically coordinates the execution of DB2 tools, enabling you to realize the full potential of your DB2 system.

  • DB2 Forms. Provides a drag-and-drop solution for quickly building robust, user-friendly e-business front ends to any DB2 database.

  • DB2 High-Performance Unload. Offers sequential reading and the capability to access your DB2 data at top speed.

  • DB2 Log Analysis Tool. Provides immediate pinpoint focus for recovering data changes in real time during normal operations.

  • DB2 Object Restore. Allows for the restoration of dropped objects and all related dependencies automatically.

  • DB2 Buffer Pool Analyzer. Helps database administrators (DBAs) manage buffer pools more efficiently by providing information about the buffer pools and the behavior of the objects in them.

  • DB2 Performance Monitor. Helps you get optimum performance from your database management system and provides useful support for resolving critical performance issues.

  • DB2 Query Monitor. Provides the ability to monitor queries and to quickly pinpoint and resolve problems without going through large amounts of output.

  • DB2 SQL Performance Analyzer. Gives you the ability to estimate the costs of database queries prior to execution.

  • DB2 DataPropagator. This product provides replication capabilities for DB2 databases and is integrated in DB2 on the UNIX and Intel platforms.

  • DB2 Recovery Manager. Significantly speeds up and simplifies the access to and recovery of databases for productive use throughout an enterprise.

  • DB2 Row Archive Manager. Provides a complete solution for selecting, archiving, managing, and retrieving aged data.

  • DB2 Bind Manager. Helps reduce the time and cost of connecting new application programs to a database.

  • DB2 Web Query Tool. Lets end users access, create, share, and execute SQL queries through their browsers against multiple IBM DB2 databases.

  • DB2 Data Export Facility. This enables DBAs to quickly identify database dependencies and extract referentially intact sets of data into a DB2 LOAD utility-ready file format so they can be copied to other subsystems.

  • DB2 Table Editor. A multiplatform tool that provides a variety of ways for users to quickly and easily update, create, and delete data across multiple DB2 database platforms.

  • DB2 Archive Log Compression Tool. Provides a way to automatically compress the IBM DB2 logs at the time of storage and decompress them at retrieval.

  • DB2 Change Accumulation Tool. Quickly restores database objects with precision and minimal disruption.

  • DB2 Object Comparison Tool. Maximizes system availability by keeping production and test catalogs in sync.

  • DB2 Path Checker. Identifies potential effects of performing a bind on one or many programs.

Each of these tools is further described in the following sections.

Database Administration

The following tools can help with the daily activities of database administration and can also provide some automation of redundant tasks.

DB2 Administration Tool for OS/390

IBM DB2 Administration Tool for OS/390 can help you derive the maximum performance and results from your DB2 system, dramatically reducing the effort required to support DB2. This tool provides a comprehensive set of functions that help efficiently and effectively manage DB2 environments. It is an interactive, intuitive, and easy-to-use tool that provides a cost-effective solution for a full range of database administration functions, such as

  • Display and interpret objects in the DB2 catalog.

  • Execute dynamic SQL statistics.

  • Issue DB2 commands against objects.

  • Manage SQL IDs.

  • Perform complex performance and space utilization queries.

  • Reverse-engineer objects in the DB2 catalog.

  • Display and cancel threads.

  • Manage the CDB and RLIMITS tables.

  • Manage the DB2 environment effectively.

  • Manage resource limit specification tables (RLSTs)

  • Display and estimate storage allocations.

It has ALTER capabilities that allow you to change name and attributes of a table or column, modify the definitions of columns, change the sequence of columns, drop columns, and insert new columns. The MIGRATE function allows you to create a separate DB2 test system, move the test system into a production system, and consolidate two separate database systems into one. It can also be used to generate Job Control Language (JCL) to migrate the DDL and data to a target subsystem.

It integrates with other DB2 utilities and simplifies creation of DB2 utility jobs. It also has catalog update functions and has facilities for issuing any DB2 command, issuing GRANT and REVOKE on objects, and performing BIND, REBIND, and FREE operations on selected plans and packages.

DB2 Automation Tool

This tool allows for the automation of some maintenance tasks and provides a statistical history-reporting capability in order to do trend analysis and forecasting. This ability to automate the execution of DB2 tools enables the DBA to focus on more important tasks, such as system optimization and performance.

The DB2 Automation Tool can be used to automate the generation of utility JCL on an as-needed basis to REORG or COPY DB2 objects as necessary.

It provides an interface for the creation of reusable profiles used to define utility control cards. These profiles allow for definition of the utility, identification of the objects to be maintained, and the thresholds for the JCL to be generated.

It also supports workload balancing based on past historical execution data. The product has a Data Management facility, which allows for viewing and evaluating various datasets. It can also be used to move datasets.

DB2 Table Editor

IBM DB2 Table Editor is a powerful, multiplatform tool providing a variety of ways for users to quickly and easily update, create, and delete data across multiple DB2 database platforms with security, referential integrity, and support for the advanced capabilities of DB2. DB2 Table Editor is accessible by both Windows-based and Java-based users, including those with browsers, making it a viable tool for users at all levels. Customers who need to safely provide data editing and data entry capabilities to end users at the front lines of a business or to administrators will find DB2 Table Editor a valuable offering. This tool features

  • Data editing and data entry capabilities for DBAs and end users accessing the table data directly or via forms.

  • Ability to edit DB2 tables everywhere with a choice of end-user entry points: Java-enabled Web browsers, Java interfaces launched from IBM DB2 Control Center, Microsoft Windows, or an ISPF interface.

  • A variety of ways to navigate, create, update, and delete data across multiple platforms with security, referential integrity, and support for the advanced capabilities of DB2.

  • The ability to drag-and-drop or use wizards to rapidly create versatile, task-specific Java-based or Windows-based table editing forms containing built-in data validation and business rules.

  • A Java-based application that allows you to do a wide variety of table editing tasks, including the ability to edit tables on multiple DB2 database platforms, to maintain referential integrity while performing updates, and to search for and locate specific rows quickly and jump to tables of related data immediately.

  • Ability to use administrative and forms-building modules with the Windows-based interface to do these table editing tasks and many others that include saving forms for Java or Windows deployment, building sets of forms and linking them with parentchild relationships, and embedding forms into Web pages as tightly controlled data access and data entry applications.

  • Support for a wide range of database platforms, including IBM DB2 Universal Database for z/OS and OS/390, DB2 for iSeries, and DB2 UDB for multiple platforms, including on IBM AIX, Linux, Microsoft Windows, Sun Solaris, and HP/UX.

DB2 High-Performance Unload for OS/390

DB2 High-Performance Unload offers sequential reading and the capability to access your DB2 data at top speed. It can scan a table space and create output files in the format in which you need them. All you have to do is select the criteria. You can select from many types of conversions, giving your output the desired appearance, such as delimited file for export to another platform or DSNTIAUL (a DB2 supplied unload utility) compatibility. This tool provides the following benefits:

  • Increased speed for unload functions.

  • High-speed unloads of DB2 data using native VSAM.

  • Ability to unload from image copies as well as active tables.

  • Multiple output files during a single unload with minimal additional cost.

  • Multiple output formats, including the opportunity to tailor your own.

  • Comprehensive and powerful SELECT statement.

  • More efficient unloads of DB2 data.

  • Help with batch window constraints.

  • Ability to unload multiple tables each to a separate file or a single table many times.

Large scan performance can become critical when several unloads have to read the same table space concurrently. Performance symptoms can be caused by multiple reads of the same DB2 pages. Sometimes there are channel conflicts. IBM DB2 High-Performance Unload can help solve these problems.

You can code as many SELECT statements as you want for any tables belonging to the same table space. Different output files can be created during the same unload process at very little additional cost. Multiple tables can be unloaded at once, each to its own file, as long as all the tables belong to the same table space. You can unload the same table many times with different SELECT statements, using only one table space scan. You can also run this utility against incremental image copies or any full image copy as well as against active tables.

DB2 Log Analysis Tool for OS/390

The DB2 Log Analysis tool provides you many benefits in the area of recovery and availability. It allows you to locate, UNDO, and REDO changes with ease and to quickly isolate accidental or undesired changes to your database tables. You can then selectively reverse these changes from an easy-to-use, menu-driven interface. The tool also allows you to selectively REDO specific transactions after large-scale reversals of data changes, and locate changes made to one database and copy those changes to another database. These types of activities can be performed while the DB2 systems continue to run as normal. This helps to minimize downtime from conventional recovery sessions and maximize uptime for e-business availability.

DB2 Log Analysis Tool provides a simple interface that lets you quickly specify the scope and magnitude of data changes you wish to viewby dates, users, tables, and much more. Valuable time and system resources are further saved by support of data compression in DB2 for OS/390 and by the elimination of the need to capture data changes and associated administrative, I/O, and storage overhead. Once you've spotted changes that must be reversed, they're easily undone with the tool. It generates the necessary SQL, which is sent to a file for execution by any method referred by the database administrator.

The tool has a comprehensive set of reports. Some of the data change reporting features include

  • Set filtering criteria for reporting data changes by authid, job name, plan name, table, database, table space, or date ranges.

  • Produce summary reports from which drill-down detailed reports can be obtained.

  • View filtered summary of desired date range, tables, and more.

  • View detailed reports showing all data change events, including original state, current state, and INSERT, UPDATE, and DELETE operations executed.

  • Save filtered reports as JCL to be run at will.

DB2 Object Restore for OS/390

IBM DB2 Object Restore for OS/390 can restore dropped objects and all related dependencies automatically. This can include dropped storage groups, databases, tablespaces, tables, indexes, table and column authorizations, and data.

This tool eliminates the need for a shadow copy of the catalog to recover objects. The result is that DB2 Object Restore saves direct access storage device (DASD) space. With this tool you can feel secure in cleaning up your DB2 system, because you can restore discarded DB2 objects if necessary.

Some highlights of DB2 Object Restore include

  • DDL generation, which recreates the dropped objects.

  • Versioning repository to generate the DDL and to run analyses on the repositories to map old database identifiers (DBIDs), page set identifiers (PSIDs), and object identifiers (OBIDs) to new IDs for recreated objects.

  • Move/copy object feature, which allows you to move the objects from one DB2 subsystem to another.

  • Restore object hierarchy, which automatically rebuilds the structure of dependent objects.

DB2 Data Export Facility

DB2 Data Export Facility enables DBAs to quickly identify database dependencies and extract referentially intact sets of data into a DB2 LOAD utility-ready file format for immediate copying to other DB2 subsystems. Such efficient extraction and copying capabilities are valuable not only for application testing, but also when migrating applications to production environments. The tool can also

  • Export and copy data for application development and testing using an ISPF interface that easily extracts RI sets of data or individual tables and/or rows, into a DB2 LOAD-ready file format for copying to other DB2 subsystems.

  • Copy selected source data to test environments for faster application development and testing.

  • Find relationships between tables and allow easy selection and export of precisely the desired scope of data among the referential set, such as exporting a table, a table and all its dependencies, or only certain dependencies.

  • Navigate through table relationships with a simple step-through interface that extracts desired subsets of data so users can see the attributes of tables, such as columns, indexes, and parentchild relationships.

  • Identify referential integrity properties as you navigate, including parentchild relationships, indexes, and columns.

  • Support highly selective data copying that helps cut through the complexity normally associated with surgical problem resolution, populating test environments, or migrating applications to new or additional environments.

  • Provide exporting without referential integrity from a single table so that data can be narrowed down to the precise columns and rows desired.

DB2 Object Comparison Tool

This comparison tool for z/OS maximizes system availability by keeping your production and testing database environments running in parallel. It is used to compare the structure of DB2 objects. It can be used to identify differences between objects via a report.

  • Provides the ability to compare objects (and dependent objects) from one source to those in another, (e.g., test and development database system can be a mirror image of the production system).

  • Runs as an extension to DB2 Administration Tool for OS/390, version 2.1.

  • Includes a DB2 catalog extract function, a batch job generator, and a dynamic-link library (DLL) extract feature.

  • Provides an ISPF front end and a batch-compare capability.

  • Can be used to make a target reflect a source.

  • JCL is generated to accomplish all of the necessary steps in the correct sequence.

Database Performance Management

The following tools are designed to help with monitoring system and SQL performance in the DB2 environment.

DB2 Buffer Pool Analyzer

IBM DB2 Buffer Pool Analyzer helps DBAs manage buffer pools more efficiently by providing information about current buffer pool behavior and using simulation to anticipate future behavior. This tool provides data collection of virtual buffer pool activity via the DB2 instrumentation facility interface (IFI). It also offers comprehensive reporting of the buffer pool activity, including

  • Ordering by various identifiers such as buffer pool, plan, object, and primary authorization id.

  • Sorting by GETPAGE requests, sequential prefetch, and synchronous read.

  • Filtering capability, and loading into tables.

The Buffer Pool Analyzer allows you to simulate buffer pool usage for varying buffer pool sizes and different object placement. It can also produce a display report and simulation results on workstations in form of spreadsheets, graphs and diagrams.

DB2 Performance Monitor for OS/390

DB2 Performance Monitor is designed to help you get optimum performance from your database management system and provides useful support for resolving critical performance issues. It gives you the ability to analyze, control, and tune the performance of DB2 and DB2 applications. It also includes a real-time online monitor, a wide variety of reports for in-depth analysis, and an EXPLAIN feature to analyze and optimize SQL statements. It can be executed using the ISPF panels or on a Windows workstation. DB2 Performance Monitor can help you monitor

  • DB2 and DB2 applications online and in batch by reporting alerts immediately when problems occur.

  • Usage of workstations, which allows parallel monitoring of different DB2 subsystems from one point of control.

  • The status of a DB2 subsystem and its applications while they are currently active or events and performance problems that happened in the past.

  • Individual data sharing members or entire data sharing groups in online or batch modes.

  • Applications running in a query parallelism environment on a Parallel Sysplex cluster, even if the parallel tasks are executed on different processors.

This tool also allows you to analyze performance problems online or through a vast set of detailed reports and to obtain tuning recommendations. It also has the ability to run EXPLAINs, recognize periodic and event exceptions, and take appropriate actions by means of a user exit, by restricting user authorization to specific threads, by recognizing trends and anticipating potential bottlenecks, and by saving DB2 trace data.

DB2 Query Monitor for OS/390

The DB2 Query Monitor for OS/390 lets you quickly pinpoint the kinds of activity that matter to you. It provides both real-time and historical views into query activity throughout your DB2 subsystems. It also provides extensive choice in determining what data is gathered during monitoring, when it is gathered, and about whom. When the thresholds you specify are crossed, activity is logged for rapid drill-down and, if needed, termination. At intervals also under your control, real-time activity is saved from memory to disk and, if desired, from disk to database. So, even while your world of DB2 subsystems is completely open to your view (both as current activity and histories), you incur the lowest system monitoring overhead. The DB2 Query Monitor also allows you to

  • Navigate database activity with ease.

  • Identify trouble in real time before DB2 resources are wasted.

  • Locate problem queries during execution.

  • Identify users and locations issuing problem queries.

  • Set thresholds that automate early warnings and corrective action.

  • Terminate problem queries.

  • Fix processes that are hurting DB2 availability.

This tool has the ability to have multiple monitoring agents, each capable of watching up to 64 DB2 subsystems, to track the activity you specify. You can customize it also via user-defined profiles that highlight real-time events of interest. You also have the ability to set thresholds by CPU time, elapsed time, GETPAGE requests, rows returned, delay time, number of SQL calls, lock failures, lock escalations, invalid SQL codes, or application abends (abnormal ends).

DB2 SQL Performance Analyzer for OS/390

The DB2 SQL Performance Analyzer makes it easier to reduce the escalating costs of database queries by estimating their cost prior to execution. Many times applications fail to perform according to needs, particularly at high transaction volumes. Frequently, the problem is that database queries run too long, causing the batch production window to shrink, which frustrates users and adds to costs.

This tool can perform data modeling during the design phase of an application, determine which SQL statements in major production are the most resource-intensive, and provide a tool that allows efficient queries to be developed and saved. It also can be used to analyze existing SQL statements that have demonstrated performance problems.

It can also approximate how long queries will take before database resources are unnecessarily consumed and can even estimate the cost of a query before it is delivered. Estimates are given in familiar units, such as CPU time, I/O count, elapsed time, or monetary cost. This allows you to perform what-if scenarios to determine what performance can be obtained now and in the future with various database design alternatives and production volumes.

DB2 Performance Expert for OS/390

This tool is a combination of the DB2 Performance Monitor and the DB2 Buffer Pool Analyzer. It is enhanced by the ability to provide recommendations regarding the tuning of the environment.

Database Recovery and Replication Management

The following tools assist the DBA with activities surrounding replication and recovery.

DB2 DataPropagator for OS/390

DB2 DataPropagator offers numerous features for a comprehensive replication solution, such as

  • A highly efficient architecture that automatically captures and asynchronously propagates data changes to the DB2 family of databases.

  • A high-performance log-based change-capture component, which captures all DB2 updates without application changes.

  • Powerful data transformation using standard SQL, including multitable joins and stored procedures.

The IBM replication solution enables full refresh and change propagation across a heterogeneous database environment. DB2 DataPropagator supports a wide variety of databases, including DB2, Oracle, Microsoft, Sybase, Informix, IMS, Lotus Notes, and flat files. Replication is also a core technology that enables mobile users to keep their data synchronized with corporate data residing on a DB2 server. Some of the highlights of this product include

  • Replicates information across the enterprise.

  • Captures data changes against a source database automatically and propagates the changes to a target database.

  • Replicates across MVS, OS/390, VM, VSE, AS/400, OS/2, AIX, HP-UX, Sun's Solaris, Linux for S/390, NUMA-Q, and Microsoft Windows platforms.

  • Unites distributed, heterogeneous databases into an integrated database environment.

The IBM DB2 DataPropagator can help you improve data availability and operational database performance. By replicating data between your central database and regional transactional databases, you can make business data available to the regional databases for prompt transaction processing. It also has sophisticated data transformation capabilities, maximizing the value of your data warehouse and business intelligence systems. It will allow you to derive data using arithmetic (Boolean or any valid SQL expression), aggregate data to produce sums or averages using SQL column functions, convert data by translating encoded fields to descriptive fields, and consolidate data through joins or unions.

DB2 Recovery Manager for OS/390

The IBM DB2 Recovery Manager function significantly speeds and simplifies the access to and recovery of databases for productive use throughout an enterprise. It enables versatile database recovery functions in e-business transaction environments. It can be used to recover a DB2 or IMS application individually and coordinate the recovery of both DB2 and IMS data to a common point, cutting the time and cost of data recovery and availability. This ability eliminates the error-prone complexity of managing different logs, utilities, and processes to do recovery from both databases.

DB2 Recovery Manager works with either DB2 or IMS, or both. It uses image copies for both databases and establishes synchronization points in each called a Virtual Image Copy (VIC) to which recovery may be done. After an application is run in which both DB2 and IMS are accessed, DB2 Recovery Manager is invoked to establish a VIC. It also establishes a quiesce point and notes where the point is located in the respective logs. During recovery, the user specifies the need to recover to this VIC, and DB2 Recovery Manager applies the appropriate image copies and causes the log to be applied up to this point.

You also have the option to automate the recovery of resources. This tool will generate the JCL, locate the proper image copies, and control the execution of jobs for either DB2 or IMS.

DB2 Row Archive Manager for OS/390

DB2 Row Archive Manager is a complete solution for selecting, archiving, managing, and retrieving aged data. By applying appropriate judgment on the need to access your aged data, you can use DB2 Row Archive Manager to reduce the required DASD storage, improve your DB2 performance, and reduce the cost of your overall DB2 environment. This can be achieved by archiving aged DB2 data and doing this archiving at a table row or column level to reduce storage requirements. Performance improvements can be seen by removing aged data, which reduces time spent on table scans and decreases index size. This would also reduce the amount of data processed and time consumed by costly maintenance activities such as reorganizations, image copies, and recoveries.

The DB2 Row Archive Manager administrator implements a set of rules to determine what data is eligible to be archived. There are no programs to write. Only the selected rows are archived at any specified time. DB2 Row Archive Manager also allows you to determine which columns of a row should be archived. Referentially linked rows from related tables or systems of related tables can be archived as a unit. This archived data can be selectively retrieved on demand. The Row Archive Manager catalog is used to locate and retrieve the needed data, usually running as an overnight batch job.

This tool also includes additional utilities, such as REMOVE, which can discard erroneous or obsolete archive specifications from the system. Storage management functions are also performed with DB2 Row Archive Manager utilities to effectively manage the physical storage used by the archived table spaces. It currently does require a PL/1 compiler.

DB2 Archive Log Compression Tool

IBM DB2 Archive Log Compression Tool reduces storage and I/O requirements associated with comprehensive disaster recovery preparedness and automatically compresses IBM DB2 logs at the time of storage and decompresses them at retrieval. It can compress the log at the time of archival or after the log has been archived. This tool provides a way to

  • Restore data directly from highly compressed, off-site copies of DB2 logs.

  • Enable DBAs to reduce the volume of archived logs, resulting in shorter I/O and recovery times.

  • Help lower storage costs by enabling the storage of logs on DASD instead of tape.

DB2 Change Accumulation Tool

IBM DB2 Change Accumulation Tool quickly restores database objects with precision and minimal disruption, setting the scope and specificity of image copy creation through the use of control cards.

  • Makes accurate point-in-time recovery of database objects simple and reliable by restoring database object in a precise manner with minimal disruptions.

  • Allows recovery routines to focus on single objects and previous states.

  • Produces SHRLEVEL REFERENCE image copies without the associated overhead and data locking.

  • Allows you to produce more frequent SHRLEVEL REFERENCE image copies, thereby potentially reducing recovery time.

Database Application Management

The following tools are optional and can help with performing DB2 tasks that may require decisions made upon the current state of the data. There is also a tool to assist with executing SQL statements via a browser.

DB2 Bind Manager for OS/390

The DB2 Bind Manager helps reduce the time and cost of connecting new application programs to a database. It reduces costs by avoiding unnecessary binding steps between application programs and the database. It allows application developers to safely bypass the DB2 bind process for source code changes that do not alter the existing SQL structure.

This tool analyzes each precompile to determine whether the SQL structure has changed. If it has not, then a bind is not needed and will not be executed. This can result in major cost savings in change management. Since DB2 Bind Manager detects only production application changes requiring a bind, it frees database administrators from doing unnecessary binds and allows them to concentrate only on changes that affect the SQL structure.

DB2 Bind Manager offers optional checking functions that further simplify the bind process via the Path Checker function, which gives developers and DBAs the tool they need to avoid performance problems created by unexpected access path changes as programs are migrated or rebound. Another function, database request module (DBRM) Checker, enables consistency checking for an existing DBRMLIB and a DB2 subsystem. DBRM Checker will identify DBRMs by plan that have consistency tokens inconsistent with those in the DB2 catalog tables. DBRM Checker determines which of the packages needs binding.

DB2 Web Query Tool for OS/390

The DB2 Web Query Tool for OS/390 lets end users access, create, share, and execute SQL queries through their browsers against multiple IBM DB2 databases. They can save query results in multiple formats, including XML, and integrate query results with popular PC applications such as spreadsheets.

This tool allows for maximum DB2 availability for e-business by providing global data access to any user without new software or plug-ins on client machines. It has tightly controlled data access with support for existing DB2 security and can be made available to multiple DB2 database servers, safely and simultaneously, regardless of size, hardware, operating system, or location.

It sets a new standard for business responsiveness. Now, anyone in your organization can take robust data access for granted, virtually anywhere and at any time. This responsiveness means more opportunity and more velocity for every business decision. With the trusted architecture of DB2 behind it, DB2 Web Query Tool enables pervasive connectivity over the Internet to every desktop, for the novice or the expert. Query operations available include the ability to query any DB2 database server made available by the administrator, create ad hoc queries, store queries for access by others, browse stored queries by name or description, execute any DB2-specific SQL, view query results in a browser or, download results as .TXT or .CSV files for use in spreadsheets or other tools, export results as XML, and import table data from XML files.

DB2 Path Checker

IBM DB2 Path Checker identifies potential effects of performing a bind on one or many programs. DB2 Path Checker initiates an EXPLAIN into the plan table of the new DBRM and provides you with a report on path changes. DB2 Path Checker

  • determines whether a bind of a DBRM will result in a changed access path.

  • displays available statement table cost estimates.

  • provides easily understood EXPLAIN statements, selected DB2 catalog statistics on path change, and wildcard processing of DBRM library entries.

  • allows statement level EXPLAIN to be passed to DB2 SQL Performance Analyzer on path change.


019 - Summary

Chapter 1. Product Overview

Summary

The DB2 family of products covers a wide range of platforms, allowing us to choose the best performing platform for the job. DB2 is a very scalable product that can scale from the smallest platforms to the large z/OS platform. IBM provides a comprehensive set of tools in many different categories to support and use DB2. Many of these tools are included with the base product itself, and others are available for optional purchase.


020 - Additional Product Resources

Chapter 1. Product Overview

Additional Product Resources

www.ibm.com/software/data/db2imstools


021 - Chapter 2. Database Objects

Part 1. Introduction to DB2 UDB for OS/390 and z/OS

Chapter 2. Database Objects

  • Creating Database Objects

  • Data Types

  • Tables and Tablespaces

  • Aliases and Synonyms

  • Constraints

  • Views

  • Indexes

DB2 is a relational database that consists of one or more tables that are made up of rows and columns. The tables are created and accessed using the industry standard SQL (Structured Query Language). Data in these tables is accessed via content, not location. This chapter looks at the structures in a DB2 subsystem and those that make up a DB2 database.

Many of these objects can be directly referenced from a SQL statement; therefore, it is important to understand their purpose. SQL is divided into three major categories:

  • DDL (Data Definition Language) is used to create, modify, or drop database objects.

  • DML (Data Manipulation Language) is used to select, insert, update, or delete database data (records).

  • DCL (Data Control Language) is used to provide data object access control.

As SQL has evolved, many new statements have been added to provide a more complete set of data access methods. Later in this chapter, the use of DDL to create database objects is discussed.


022 - Understanding Data Structures

Chapter 2. Database Objects

Understanding Data Structures

A database is an organized collection of related objects. SQL is used throughout the database industry as a common method of issuing database queries. SQL is considered a language, composed of statements, functions, and data types. A SQL statement is used to access database objects using relational operations. Before we examine the SQL language, we need to understand some DB2 terminology. We will be referring to the basic data structures or objects that are defined for each DB2 database. These objects include

  • Tables

    - Data types

    - Aliases

    - Synonyms

  • Views

  • Indexes

    - Keys

  • Tablespaces

  • Index spaces

  • Databases

  • Storage Groups

Figure 2-1 shows the relationship between the DB2 objects.

Figure 2-1. A hierarchy of DB2 structures.

Tables

A table is an unordered set of data records. It consists of columns and rows. Each column is based on a data type. Tables, once created and populated with data, are referenced in the FROM clause of the SQL statements. There are three types of tables:

  • Permanent (base) tables

  • Auxiliary tables

  • Temporary (declared or global) tables

We discuss only tables created with a DDL statement in this chapter. These tables are created using the CREATE TABLE, CREATE AUXILIARY TABLE, or CREATE GLOBAL TEMPORARY TABLE statement, and each is a logical representation of the way the data is physically stored on disk. We discuss the declared temporary tables in Chapter 7, "Application Program Features."

Data Types

Data types are used to define the type of data that will occupy each column in a DB2 table. It will also provide the length of column. Data that does not match the data type defined to the column will not be allowed in that column. There are different types of data, such as string, numeric, date, time, ROWIDs, LOB (large object), and user-defined distinct data types. Depending on the data type, the length can be fixed or varying. You can categorize these data types into two categories: built-in and user-defined.

Data types that are defined by DB2 are referred to as built-in. The other type, user-defined, allows you define your own type of data to be stored in the column. These user-defined data types are based upon existing built-in data types.

Aliases

An alias is basically a pointer to another table and is a substitute for the three-part name of a table or view. An alias can be qualified by an owner ID, and the table referenced can be on the local site or on a remote site. Aliases are often used in place of any three-part named table in order to make the references portable, since DB2 on OS/390 is the only server that supports three-part name syntax. Aliases are not dropped if the table they point to is dropped.

Synonyms

Synonyms are used to refer to a table using a different name or to refer to another owner's table as if you were the owner. A synonym is basically a private pointer to a table. It can be referenced only by its owner and is not allowed to be qualified.

Unlike an alias, a synonym can be used to refer only to a table in the same subsystem in which it was defined. If the table is dropped, so is the synonym.

Views

Views are alternate ways of viewing data in one or more base tables or other views. A view is not a physical object and does not store actual data. It is an entry in the DB2 catalog that, when accessed, executes a SQL statement that retrieves data from other tables or views. Views can be used to limit access to certain kinds of data, create customized views of data for users, or allow for alterations of tables without affecting application programs. Views can be read only if necessary, or they can be updateable, insertable, or deleteable. There are some restrictions to using views.

Indexes

Indexes are ordered sets of pointers associated with a table. Indexes can be created on permanent tables or on declared temporary tables. The index is based on the values of one or more columns in the table. The index values can be either ascending or descending. Each table can have one or more indexes, and indexes can also be used to enforce uniqueness in the data values and clustering sequence. Indexes are used to improve performance when accessing data. If an index is used, large scans of data can be avoided.

Indexes are physical objects that are created in index spaces, which are data sets like those that support the tablespaces. The index space is automatically created in the same database as the table on which it is defined.

There are two types of indexes: partitioned and nonpartitioned. A partitioned index is created on a partitioned tablespace and is used to define the allowable values for each partition. A nonpartitioned index is used on tables defined in segmented, simple tablespaces or as an alternate index on a partitioned tablespace.

NOTE

The maintenance overhead of indexes will negatively impact the performance of INSERT, UPDATE, and DELETE statements.

Keys

Many keys can be defined on a table. A key is a named ordered set of columns on one table. A composite key is a key made of several columns. Each key will play a particular role for a given table.

Tablespaces

Tablespaces are objects that consist of one or more datasets that are used to stored DB2 data. Tables are created in tablespaces, and you can have one or many tables in a tablespace, depending on the type of tablespace defined. There are four types of tablespaces: simple, segmented, partitioned, and LOB. Both simple and segmented tablespaces allow for multiple tables, but only segmented should be used due to the many performance issues.

  • Simple tablespaces: These tablespaces can contain one or more tables; however, the rows of the different tables are not kept on separate pages, which can cause concurrency and space usage issues.

  • Segmented tablespaces: Segmented tablespaces can contain one or more tables, and the space is divided into same-size segments. Each segment will contain rows from only one table.

  • Partitioned tablespaces: A partitioned tablespace divides the data into several separate data sets (partitions). There can be only one table in a partitioned tablespace. You can have up to 254 partitions of up to 64 GB each. Each partition can have different characteristics, such as volume placement and free space.

  • LOB tablespaces: LOB tablespaces are required to hold large object data. LOB tablespaces are associated with the tablespace that holds the logical LOB column.

Index Spaces

When an index is created, an index space is also created. Index spaces are a set of virtual storage access method (VSAM) linear datasets that hold index data, and they are implicitly associated with the database that contains the table the index is defined on.

Databases

Databases in DB2 are collections of tablespaces and index spaces. The database on the OS/390 platform does not have any physical storage characteristics, but acts more like an umbrella over all of its dependent objects.

Storage Groups

Storage groups are used to define a list of volumes to DB2 for its use when creating physical objects such as tablespaces and index spaces. The storage is allocated when the tables are loaded with data. Storage groups are created using DDL.


023 - Managing Database Objects

Chapter 2. Database Objects

Managing Database Objects

To create, modify, or delete objects in a database, SQL DDL is used.

Using SQL DDL

The DDL contains four main SQL statements:

  • CREATE

  • ALTER

  • DROP

  • DECLARE

The CREATE Statement
CREATE <database object>

The CREATE statement is used to define database objects. Database objects are used for different purposes. Some are used to define a condition or relationship (index, trigger), and others are a logical representation of the data as it is physically stored on disk (table, tablespace). The following database objects can be created with the CREATE statement:

  • Alias

  • Auxiliary table (LOBs)

  • Database

  • Distinct type (user-defined data type)

  • Function (user-defined functions)

  • Global temporary table

  • Index

  • Procedure (stored procedures)

  • Stogroup (storage groups)

  • Synonym

  • Table

  • Tablespace

  • Trigger

  • View

The creation of any database object using DDL will result in an update to the system catalog tables. Special database authorities or privileges are required to create database objects.

The DECLARE Statement
DECLARE <database object>

The DECLARE statement is very similar to the CREATE statement, except that one of the objects it can create is a temporary table. Temporary tables are used only for the duration of an application or stored procedure or connection. The table does not cause any logging or contention against the system catalog tables and is very useful for working with intermediate results. This table must be placed into an existing TEMP database. The TEMP database should have several segmented tablespaces created within it. A single declared table cannot span tablespaces.

The creation of a temporary table will not result in any update to the system catalog tables, so locking, logging, and other forms of contention are avoided with this object.

Declared tables can be dropped and altered, but no other database objects (such as views or triggers) can be created to act against them. Temporary tables do allow for the specification of a partitioning key.

Once a table is declared, it can be referenced like any other SQL table. For more information on declared temporary tables refer to Chapter 7, "Application Program Features."

The DROP Statement
DROP <database object>

The DROP statement is used to remove definitions from the system catalog tables (and hence the database itself). Since the system catalog tables cannot be directly deleted from, the DROP statement is used to remove data records from these tables. Since database objects can be dependent on other database objects, the act of dropping an object will result in dropping any object that is directly or indirectly dependent on that object. Any plan or package that is dependent on the object deleted from the catalog on the current server will be invalidated. You can drop any object created with the CREATE <database object> and the DECLARE <table> statements.

The ALTER Statement
ALTER <database object>....

The ALTER statement allows you to change some characteristics of database objects. Any object being altered must already exist in the database. The database objects that can be altered are

  • Database

  • Function

  • Index

  • Procedure

  • Stogroup

  • Table

  • Tablespace

Every time you issue a DDL statement, the system catalog tables will be updated. The update will include a creation or modification timestamp and the authorization ID of the creator (modifier).

Let's look in detail at some of the objects that can be created. We will cover data types, tables, tablespaces, views, indexes, databases, and storage groups.

Data Types

Data types are used to specify the attributes of the columns when creating a table. Before discussing a table or other objects, we have to understand the various data types supplied by DB2 or created by the users (user-defined data types). First let us look at the built-in data types supplied by DB2.

DB2-Supplied Data Types

When the database design is being implemented, any of these data types can be used. Data is stored in DB2 tables that are composed of columns and rows. Every DB2 table is defined by using columns. These columns must be one of the built-in DB2 data types or user-defined data types. Every DB2-supplied data type belongs to one of these three major categories:

  • Numeric

  • String (Binary, Single Byte, Double Byte)

  • Date-time

The valid built-in DB2 data types are listed in Table 2-1.

Table 2-1. Built-in Data Types

Date-time types

Time

TIME

Timestamp

TIMESTAMP

Date

DATE

String types: Character

Fixed length

CHAR

Varying length

VARCHAR CLOB

String types: Graphic

Fixed length

GRAPHIC

Varying length

VARGRAPHIC DBCLOB

Varying-length binary

BLOB

Signed numeric types: Exact

Binary integer: 16-bit

SMALLINT

Binary integer: 32-bit

INTEGER

Signed numeric types: Decimal

Packed

DECIMAL

Signed numeric types: Approximate

Floating-point single-precision

REAL

Floating-point double-precision

DOUBLE

Row identifier

ROWID

Numeric Data Types

The six DB2 data types that can be used to store numeric data are

  • SMALLINT

  • INTEGER

  • DECIMAL/NUMERIC

  • FLOAT (REAL or DOUBLE)

  • REAL

  • DOUBLE

These data types are used to store different numeric types and precisions. The precision of a number is the number of digits used to represent its value. The data is stored in the DB2 database using a fixed amount of storage for all numeric data types. The amount of storage required increases as the precision of the number goes up.

You must also be aware of the range limits of the data types and the corresponding application programming language when you are manipulating these numeric fields. Some data values are of the integer type by nature, such as the number of test candidates. It would be impossible to have a number representing a number of people that contains fractional data (numbers to the right of the decimal). On the other hand, some values require decimal places to accurately reflect their value, such as test scores. These two examples should use different DB2 data types to store their values (SMALLINT and DECIMAL, respectively).

Numeric values should not be enclosed in quotation marks. If they are, the value is treated as a character string. Even if a field contains numbers in its representation, a DB2 numeric data type should be used to represent the data only if arithmetic operations should be allowed.

Small integer (SMALLINT)

A small integer uses the least amount of storage in the database for each value. An integer does not allow any digits to the right of the decimal. The data value range for a SMALLINT is 32,768 to 32,767. The precision for a SMALLINT is five digits (to the left of the decimal). Two bytes of database storage are used for each SMALLINT column value.

Integer (INTEGER)

An INTEGER takes twice as much storage as a SMALLINT but has a greater range of possible values. The range value for an INTEGER data type is 2,147,483,648 to 2,147,483,647. The precision for an INTEGER is 10 digits to the left of the decimal. Four bytes of database storage are used for each INTEGER column value.

Decimal (DECIMAL/NUMERIC)

A DECIMAL or NUMERIC data type is used for numbers with fractional and whole parts. The DECIMAL data is stored in a packed format. The precision and scale must be provided when a decimal data type is used. The precision is the total number of digits (range from 1 to 31), and the scale is the number of digits in the fractional part of the number. For example, a DECIMAL data type to store currency values of up to $1 million would require a definition of DECIMAL (9,2). The terms NUMERIC, DECIMAL, or DEC can all be used to declare a decimal or numeric column. If a DECIMAL data type is to be used in a C program, the host variable must be declared as a double. A DECIMAL number takes up p/2 + 1 bytes of storage, where p is the precision used. For example, DEC (8,2) would take up 5 bytes of storage (8/2 + 1), whereas DEC(7,2) would take up only 4 bytes (truncate the division of p/2).

Single-precision floating-point (REAL/FLOAT)

A REAL data type is an approximation of a number. The approximation requires 32 bits or 4 bytes of storage. To specify a single-precision number using the REAL data type, its length must be defined between 1 and 24 (especially if the FLOAT data type is used, as it can represent both single-precision and double-precision, and is determined by the integer value specified).

Double-precision floating-point (DOUBLE/FLOAT)

A DOUBLE or FLOAT data type is an approximation of a number. The approximation requires 64 bits or 8 bytes of storage. To specify a double-precision number using the FLOAT data type, its length must be defined between 25 and 53.

String Data Types

This section discusses the string data types that include

  • CHAR

  • VARCHAR

  • CLOB

  • GRAPHIC

  • VARGRAPHIC

  • DBCLOB

  • BLOB

NOTE

The syntax of LONG VARCHAR and LONG VARGRAPHIC are still supported, but the alternative syntaxes of VARCHAR (integer) and VARGRAPHIC (integer) are preferred. DB2 will translate the LONG definitions into the other format prior to actually defining the table. Therefore, only the VARCHAR() and VARGRAPHIC() definitions should be used.

Fixed-length character string (CHAR)

Fixed-length character strings are stored in the database using the entire defined amount of storage. If the data being stored always has the same length, a CHAR data type should be used.

Using fixed-length character fields can potentially waste disk space within the database if the data is not using the defined amount of storage. However, there is overhead involved in storing varying-length character strings. The length of a fixed-length string must be between 1 and 255 characters. If you do not supply a value for the length, a value of 1 is assumed.

Varying-length character string (VARCHAR)

Varying-length character strings are stored in the database using only the amount of space required to store the data, and a 2-byte prefix to hold the length. The individual names, in our example, are stored as varying-length strings (VARCHAR) because each person's name has a different length (up to a maximum length of 30 characters).

If a varying-length character string is updated and the resulting value is larger than the original, it may not fit on the same page, and the row will be moved to another page in the table, leaving a marker in the original place. These marker data records are known as indirect reference rows. Too many of these records can cause significant performance degradation, since multiple pages (I/Os) are required to return a single data record.

A VARCHAR column has the restriction that it must fit on one database page. This means that a 4-KB page would allow a VARCHAR up to 4,046 characters long (defined as VARCHAR(4046)), an 8-KB page would be up to 8,128 characters long, and so on up to a 32-KB page with the maximum column length of 32,704 bytes. This means that you must create a tablespace for this table that can accommodate the larger page size, and you must have sufficient space in the row to accommodate this string.

NOTE

Character strings on the OS/390 are stored in the database without a termination character. Depending on the non-OS/390 development environment, a null-terminator may or may not be appended to the end of a character string when the data is stored or retrieved.

Character large object (CLOB)

CLOBs are varying-length SBCS (single-byte character set) or MBCS (multibyte character set) character strings that are stored in the database. CLOB columns are used to store greater than 32 KB of text. The maximum size for each CLOB column is 2 GB (2 gigabytes less 1 byte). Since this data type is of varying length, the amount of disk space allocated is determined by the amount of data in each record. Therefore, you should create the column specifying the length of the longest string.

NOTE

The FOR BIT DATA clause can be used following a character string column definition. During data exchange, code page conversions are not performed. Rather, data is treated and compared as binary (bit) data.

Double-byte character strings (GRAPHIC)

The GRAPHIC data types represent a single character using 2 bytes of storage. The GRAPHIC data types include GRAPHIC (fixed length, maximum 127 DBCS characters), VARGRAPHIC (varying length, maximum 32,704 DBCS characters for 32-KB pages), and DBCLOB.

NOTE

VARCHAR data types over 255 bytes are similar to CLOB data types. (Both types have usage restrictions.)

Double-byte character large objects (DBCLOB)

DBCLOBs are varying-length character strings that are stored in the database using 2 bytes to represent each character. There is a code page associated with each column. DBCLOB columns are used for large amounts (>32 KB) of double-byte text data, such as Japanese text. The maximum length should be specified during the column definition because each data record will be variable in length.

Binary large object (BLOB)

BLOBs are variable-length binary strings. The data is stored in a binary format in the database. There are restrictions when using this data type, including the inability to sort using this type of column. The BLOB data type is useful for storing nontraditional relational database information. The maximum size of each BLOB column is 2 GB (2 gigabytes less 1 byte). Since this data type is of varying length, the amount of disk space allocated is determined by the amount of data in each record, not by the defined maximum size of the column in the table definition.

Large object considerations

Traditionally, large unstructured data was stored somewhere outside the database. Therefore, the data could not be accessed using SQL. Besides the traditional database data types, DB2 implements data types that will store large amounts of unstructured data. These data types are known as large objects (LOBs). Multiple LOB columns can be defined for a single table. DB2 provides special considerations for handling these large objects. You can choose not to log the LOB values to avoid large amounts of data being logged.

There is a LOG option that can be specified during the CREATE TABLESPACE statement for each AUXILIARY TABLE holding LOB column data to avoid logging any modifications. If you would like to define a LOB column greater than 1 GB, you must specify the LOG NO option.

In a database, you may choose to use BLOBs for the storage of pictures, images, or audio or video objects, along with large documents. BLOB columns will accept any binary string without regard to the contents. If you would like to manipulate textual data that is greater than 32 KB in length, you would use a CLOB data type. For example, if each test candidate were required to submit his or her resume, the resume could be stored in a CLOB column along with the rest of the candidate's information. There are many SQL functions that can be used to manipulate large character data columns.

Date and Time Data Types

There are three DB2 data types specifically used to represent dates and times:

  • DATE: This data type is stored internally as a (packed) string of 4 bytes. Externally, the string has a length of 10 bytes (MM-DD-YYYYthis representation can vary and is dependent on the country code).

  • TIME: This data type is stored internally as a (packed) string of 3 bytes. Externally, the string has a length of 8 bytes (HH-MM-this representation may vary).

  • TIMESTAMP: This data type is stored internally as a (packed) string of 10 bytes. Externally, the string has a length of 26 bytes (YYYY-MM-DD-HH-MM--NNNNNN).

From the user perspective, these data types can be treated as character or string data types. Every time you need to use a date-time attribute, you will need to enclose it in quotation marks. However, date-time data types are not stored in the database as fixed-length character strings.

NOTE

The internal format of date, time, and timestamps is not at all similar to the external format returned via SQL. For example, the internal format of TIMESTAMP is 10 bytes, but the external format is 26 characters.

DB2 provides special functions that allow you to manipulate these data types. These functions allow you to extract the month, hour, or year of a date-time column. The date and time formats correspond to the site default.

Therefore, the string that represents a date value will change depending on the default format. In some countries, the date format is DD/MM/YYYY, whereas in other countries, it is YYYY-MM-DD. You should be aware of the default format used by your site to use the correct date string format. If an incorrect date format is used in an SQL statement, a SQL error will be reported. There are scalar functions that will return date, time, and timestamp columns in formats other than the default.

As a general recommendation, if you are interested in a single element of a date string, say month or year, always use the SQL functions provided by DB2 to interpret the column value. By using the SQL functions, you can make your application more portable.

We stated that all date-time data types have an internal and external format. The external format is always a character string. Let us examine the various date-time data type formats available in DB2.

NOTE

TIMESTAMP fields use the most storage, but they contain the most accurate time, since they include microseconds.

NOTE

Timestamps cannot be guaranteed to be unique, since the granularity is only to microseconds, and it is possible for two events to ask the system timer for the timestamp within one microsecond. The 8-byte system clock value is unique, however, as it appends the time value with additional bits.

Date string (DATE)

There are a number of valid methods of representing a DATE as a string. Any of the string formats shown in Table 2-2 can be used to store dates in a DB2 database. When the data is retrieved (using a SELECT statement), the output string will be in one of these formats, or can be returned in any format specified.

Table 2-2. Date String Formats

Standard

String Format

International Standards Organization (ISO)

YYYY-MM-DD

IBM USA Standard (USA)

MM/DD/YYYY

IBM European Standard (EUR)

DD.MM.YYYY

Japanese Industrial Standard (JIS)

YYYY-MM-DD

Additionally, there are many scalar functions in DB2 to return date information, such as

  • DATE

  • DAY

  • DAYOFMONTH

  • DAYOFWEEK

  • DAYOFWEEK_ISO

  • DAYOFYEAR

  • JULIAN_DAY

  • MONTH

  • QUARTER

  • WEEK

  • WEEK_ISO

  • YEAR

Time string (TIME)

There are a number of valid methods for representing a time as a string. Any of the string formats in the following table can be used to store times in a DB2 database. When data is retrieved, the external format of the time will be one of the formats shown in Table 2-3.

Table 2-3. Time String Formats

Standard

Format

International Standards Organization ISO

HH.MM.SS

IBM USA Standard USA

HH:MM AM or PM

IBM European Standard EUR

HH.MM.SS

Japanese Industrial Standard JIS

HH:MM:SS

Additionally, there are many scalar functions in DB2 to return time information, such as

  • HOUR

  • MINUTE

  • SECOND

  • TIME

Timestamp string (TIMESTAMP)

The timestamp data type has a single default external format. Timestamps have an external representation of YYYY-MM-DD-HH.MM..NNNNNN (year-month-day-hour-minute-seconds-microseconds). However, there are several scalar functions that can manipulate the output format, especially the TIMESTAMP_FORMAT function, which returns any type of string, up to 255 characters, based on a user-defined template.

Additionally, there are many scalar functions in DB2 to return timestamp information besides all those listed for DATE and TIME, such as

  • MICROSECOND

  • TIMESTAMP

  • TIMESTAMP_FORMAT

User-Defined Data Types

User-defined data types (UDTs) allow a user to extend the data types that DB2 understands in a database. DB2 for OS/390 and z/OS supports only the user-defined distinct type. The user-defined data types can be created on an existing data type or on other user-defined data types. UDTs are used to define further types of data being represented in the database. If columns are defined using different UDTs based on the same base data type, these UDTs cannot be directly compared. This is known as strong typing. DB2 provides this strong data typing to avoid end-user mistakes during the assignment or comparison of different types of real-world data. For more information on how to create and use UDTs, refer to Chapter 15, "Object Relational Programming."

Null Value Considerations

A null value represents an unknown state. Therefore, when columns containing null values are used in calculations, the result is unknown. All of the data types discussed in the previous section support the presence of null values. During the table definition, you can specify that a valid value must be provided. This is accomplished by adding a phrase to the column definition. The CREATE TABLE statement can contain the phrase NOT NULL following the definition of each column. This will ensure that the column contains a known data value.

Special considerations are required to properly handle null values when coding a DB2 application. DB2 treats a null value differently than it treats other data values. To define a column not to accept null values, add the phrase NOT NULL to the end of the column definitionfor example:

CREATE TABLE t1 (c1 CHAR(3) NOT NULL)

From this example, DB2 will not allow any null values to be stored in the c1 column. In general, avoid using nullable columns unless they are required to implement the database design. There is also overhead storage you must consider. An extra byte per nullable column is necessary if null values are allowed.

NOTE

Relational databases allow null values. It is important to remember that they can be appropriate for your database design.

NOT NULL WITH DEFAULT

When you insert a row into a table and omit the value of one or more columns, those columns may either be populated using a null value (if the column is defined as nullable) or a defined default value (if you have specified this to be used). If the column is defined as not nullable, the insert will fail unless the data has been provided for the column. DB2 has a defined default value for each DB2 data type, but you can provide a default value for each column. The default value is specified in the CREATE TABLE statement. By defining your own default value, you can ensure that the data value has been populated with a known value.

Now, all the INSERT statements that omit the DEPT column will populate the column with the default value of 10. The COMM column is defined as with default. In this case, you can choose at insert time between null or the default value of 15. To ensure that the default value is being used during an INSERT operation, the keyword DEFAULT should be specified in the VALUES portion of the INSERT statement. The following example shows two examples of inserting a record with user-defined default values.

CREATE TABLE Staff
(ID SMALLINT NOT NULL,
NAME VARCHAR(9),
DEPT SMALLINT not null with default 10,
JOB CHAR(5),
YEARS SMALLINT,
SALARY DECIMAL(7,2),
COMM DECIMAL(7,2) NOT NULL WITH DEFAULT 15);

In this case, both cause the same result.

INSERT INTO STAFF
VALUES(360,'Purcell',DEFAULT, 'SE',8,20000,DEFAULT);
INSERT INTO STAFF (ID,NAME,JOB,YEARS,SALARY)
VALUES(360, 'Purcell ', 'SE',8,20000,);

The result is

ID     NAME      DEPT   JOB   YEARS  SALARY    COMM
------ --------- ------ ----- ------ --------- ---------
360    Purcell   10     SE    8      20000.00  15.00
1 record(s) selected.
Identity Column

The previous section discussed how columns can be populated with values if no value was supplied by the user. It is also possible to have DB2 generate sequence numbers or other values as part of a column during record insertion.

In the majority of applications, a single column within a table represents a unique identifier for that row. Often this identifier is a number that gets sequentially updated as new records are added. In DB2, a feature exists that will automatically generate this value on behalf of the user. The following example shows a table definition with the EMP_NO field automatically being generated as a sequence.

CREATE TABLE EMPLOYEE (
EMPNO INT GENERATED ALWAYS AS IDENTITY,
NAME CHAR(10));

INSERT INTO EMPLOYEE(NAME) VALUES 'YEVICH','LAWSON';

SELECT * FROM EMPLOYEE;
EMPNO NAME
----------- ----------
          1 YEVICH
          2 LAWSON

If the column is defined with GENERATED ALWAYS, then the INSERT statement cannot specify a value for the EMPNO field. By default, the numbering will start at 1 and increment by 1. The starting and increment values can be modified as part of the column definition:

CREATE TABLE EMPLOYEE (
EMPNO INT GENERATED ALWAYS AS
IDENTITY(START WITH 100, INCREMENT BY 10)),
NAME CHAR(10));

INSERT INTO EMPLOYEE(NAME) VALUES 'YEVICH','LAWSON';

SELECT * FROM EMPLOYEE;
EMPNO NAME
----------- ----------
        100 YEVICH
        110 LAWSON

In addition, the default value can be GENERATED BY DEFAULT, which means that the user has the option of supplying a value for the field. If no value is supplied (using the DEFAULT keyword), DB2 will generate the next number in sequence.

One additional keyword is available as part of IDENTITY columns. You can decide how many numbers should be "pregenerated" by DB2. This can help reduce catalog contention, since DB2 will store the next n numbers in memory rather than go back to the catalog tables to determine which number to generate next.

Identity columns are restricted to numeric values (integer or decimal) and can be used in only one column in the table definition.

CREATE TABLE EMPLOYEE (
EMPNO INT GENERATED ALWAYS AS IDENTITY,
NAME CHAR(10),
SALARY INT,
BONUS INT,
PAY INT);
INSERT INTO EMPLOYEE(NAME, SALARY, BONUS) VALUES
('YEVICH',20000,2000),
('LAWSON',30000,5000);

SELECT * FROM EMPLOYEE;
EMPNO     NAME         SALARY        BONUS        PAY
-------   ----------   -----------   -----------  ----------
1         YEVICH       20000         2000         22000
2         LAWSON       30000         5000         35000

The EMPNO is generated as an IDENTITY column.

Unicode Support in DB2

Unicode support is another very important enhancement. Support for Unicode will help with support across multinational boundaries. It is an encoding scheme that allows for the representation of codepoints and characters of several different geographies and languages. Unicode character-encoding standard is a fixed-length, character-encoding scheme that includes characters from most of the world's languages. Unicode characters are usually shown as U+xxxx where xxxx is the hexadecimal code of the character. Each character is 16 bits wide, allowing for support of 65,000 characters. The normal support that will probably be provided is the UCS-2/UTF-8 standard. With UCS-2 or Unicode encoding, ASCII and control characters are also 2 bytes long, and the lead byte is zero. Since extraneous NULLs may appear anywhere in the string, this could be a problem for ASCII. UTF-8 is a transformation algorithm that is used to avoid the problem for programs that rely on ASCII code. UTF-8 transforms fixed-length UCS characters into variable-length byte strings. ASCII characters are represented by single-byte codes, but non-ASCII characters are 2 or 2 bytes long. UTF-8 transforms UCS-2 characters to a multibyte codeset.

The UCS-2 code page is being registered as code page 1200. When new characters are added to a code page, the code page number does not change. Code page 1200 always refers to the current version of Unicode/UCS-2 and has been used for UCS-2 support in DB2 UDB on many of the other platforms. UTF-8 has been registered as CCSID 1208 (Code Page 1208) and is used as the multibyte code page number for DB2's UCS-2/UTF-8 support.

DB2 UDB supports UCS-2 as a new multibyte code page. CHAR, VARCHAR, LONG VARCHAR, and CLOB data are stored in UTF-8, and GRAPHIC, VARGRAPHIC, LONG VARGRAPHIC, and DBCLOB data are stored in UCS-2.

Databases are created in the code page of the application creating them as a default. Alternatively, "UTF-8" can be specified as the CODESET name with any valid two-letter TERRITORY code.

CREATE DATABASE dbname USING CODESET UTF-8 TERRITORY US

A UCS-2 database allows connection from every single-byte and multibyte code page supported. Code page character conversions between client's code page and UTF-8 are automatically performed by DB2. Data in graphic string types is always in UCS-2 and does not go through code page conversions. While some client workstations have a limited subset of UCS-2 characters, the database allows the entire repertoire of UCS-2 characters.

All supported data types are also supported in a UCS-2 database. In a UCS-2 database, all identifiers are in multibyte UTF-8. Therefore, it is possible to use any UCS-2 character in identifiers where the use of a character in the extended character set is allowed by DB2. This feature will also allow UCS-2 literals to be specified either in GRAPHIC string constant format, using the G'...' or N'....' formats, or as a UCS-2 hexadecimal string, using the UX'....' or GX'....' format.

Selecting the Correct Data Type

Knowledge of the possible data values and their usage is required to be able to select the correct data type. Specifying an inappropriate data type when defining the tables can result in

  • Wasted disk space

  • Improper expression evaluation

  • Performance considerations

Table 2-4 provides a small checklist for data type selection.

Table 2-4. Data Type Selection

Usage

Data Type

Is the data variable in length?

VARCHAR

If the data is variable in length, what is the maximum length?

VARCHAR

Do you need to sort (order) the data?

CHAR, VARCHAR, NUMERIC

Is the data going to be used in arithmetic operations?

DECIMAL, NUMERIC, REAL, DOUBLE, FLOAT, INTEGER, SMALLINT

Does the data element contain decimals?

DECIMAL, NUMERIC, REAL, DOUBLE

Is the data fixed in length?

CHAR

Does the data have a specific meaning (beyond DB2 base data types)?

USER DEFINED TYPE

Is the data larger than what a character string can store, or do you need to store nontraditional data?

CLOB, BLOB, DBCLOB

Remember that you need to create page sizes that are large enough to contain the length of a row in a table. This is particularly important for tables with large character columns. When using character data types, the choice between CHAR and VARCHAR is determined by the range of lengths of the columns. For example, if the range of column length is relatively small, use a fixed CHAR with the maximum length. This will reduce the storage requirements and could improve performance.

Tables

Tables consist of columns and rows that store an unordered set of data records. Tables can have constraints to guarantee the uniqueness of data records, maintaining the relationship between and within tables, and so on. A constraint is a rule that the database manager enforces. There are three types of constraints:

  • Unique constraint: Ensures the unique values of a key in a table. Any changes to the columns that comprise the unique key are checked for uniqueness.

  • Referential constraint: Enforces referential constraints on insert, update, and delete operations. It is the state of a database in which all values of all foreign keys are valid.

  • Check constraint: Verifies that changed data does not violate conditions specified when a table was created or altered.

Unique Constraints

A unique constraint is the rule that the values of a key are valid only if they are unique within the table. Each column making up the key in a unique constraint must be defined as NOT NULL. Unique constraints are defined in the CREATE TABLE statement or the ALTER TABLE statement using the PRIMARY KEY clause or the UNIQUE clause. When used, the table is marked as unavailable until you explicitly create an index for any key specified as UNIQUE or PRIMARY KEY, unless processed by the schema processor, in which case DB2 will implicitly create all necessary indexes.

A table can have any number of unique constraints; however, a table cannot have more than one unique constraint on the same set of columns. The enforcement of the constraint is through the unique index. Once a unique constraint has been established on a column, the check for uniqueness during multiple row updates is deferred until the end of the update (deferred unique constraint). A unique constraint can also be used as the parent key in a referential constraint.

Referential Integrity

Referential integrity allows you to define required relationships between and within tables. The database manager maintains these relationships, which are expressed as referential constraints, and requires that all values of a given attribute or table column also exist in some other table column. Figure 2-2 shows an example of the referential integrity between two tables.

Figure 2-2. Referential integrity between two tables.

This constraint requires that every employee in the EMPLOYEE table must be in a department that exists in the DEPARTMENT table. No employee can be in a department that does not exist.

A unique key is a set of columns in which no two values are duplicated in any other row. Only one unique key can be defined as a primary key for each table. The unique key may also be known as the parent key when referenced by a foreign key.

A primary key is a special case of a unique key. Each table can only have one primary key. In this example, DEPTNO and EMPNO are the primary keys of the DEPARTMENT and EMPLOYEE tables.

A foreign key is a column or set of columns in a table that refer to a unique key or primary key of the same or another table. A foreign key is used to establish a relationship with a unique key or primary key and enforces referential integrity among tables. The column WORKDEPT in the EMPLOYEE table is a foreign key because it refers to the primary key, column DEPTNO, in the DEPARTMENT table.

A parent key is a primary key or unique key of a referential constraint. A parent table is a table containing a parent key that is related to at least one foreign key in the same or another table. A table can be a parent in an arbitrary number of relationships. In this example, the DEPARTMENT table, which has a primary key of DEPTNO, is a parent of the EMPLOYEE table, which contains the foreign key WORKDEPT.

A dependent table is a table containing one or more foreign keys. A dependent table can also be a parent table. A table can be a dependent in an arbitrary number of relationships. For example, the EMPLOYEE table contains the foreign key WORKDEPT, which is dependent on the DEPARTMENT table that has a primary key.

A referential constraint is an assertion that nonnull values of a designated foreign key are valid only if they also appear as values of a unique key of a designated parent table. The purpose of referential constraints is to guarantee that database relationships are maintained and data entry rules are followed.

Enforcement of referential constraints has special implications for some SQL operations that depend on whether the table is a parent or a dependent. The database manager enforces referential constraints across systems based on the referential integrity rules. The rules are INSERT rule, DELETE rule, and UPDATE rule. However, only the DELETE rules are explicitly defined.

INSERT rules

The INSERT rule is implicit when a foreign key is specified. You can insert a row at any time into a parent table without any action being taken in the dependent table. You cannot insert a row into a dependent table unless there is a row in the parent table with a parent key value equal to the foreign key value of the row that is being inserted unless the foreign key value is null. If an INSERT operation fails for one row during an attempt to insert more than one row, all rows inserted by the statement are removed from the database.

DELETE rules

When you delete a row from a parent table, the database manager checks if there are any dependent rows in the dependent table with matching foreign key values. If any dependent rows are found, several actions can be taken. You determine which action will be taken by specifying a DELETE rule when you create the dependent table.

  • RESTRICT or NO ACTION: This rule prevents any row in the parent table from being deleted if any dependent rows are found. If you need to remove both parent and dependent rows, delete dependent rows first.

  • CASCADE: This rule automatically deletes the row from the dependent table when the parent row is deleted.

  • SET NULL: This option sets the value of the foreign key to NULL (provided it allows nulls). Other parts of the row will remain unchanged.

UPDATE rules

The database manager prevents the update of a unique key of a parent row. When you update a foreign key in a dependent table and the foreign key is defined with the NOT NULL option, it must match some value of the parent key of the parent table.

Check Constraints

Table check constraints will enforce data integrity at the table level. Once a table check constraint has been defined for a table, every UPDATE and INSERT statement will involve checking the restriction or constraint. If the constraint is violated, the data record will not be inserted or updated, and an SQL error will be returned.

A table check constraint can be defined at table creation time or later, using the ALTER TABLE statement. The table check constraints can help implement specific rules for the data values contained in the table by specifying the values allowed in one or more columns in every row of a table. This can save time for the application developer, since the validation of each data value can be performed by the database and not by each of the applications accessing the database.

When a check constraint is created or added, DB2 performs a syntax check on it. A check constraint cannot contain host variables or special registers.

The check constraint's definition is stored in the system catalog tables, specifically the SYSIBM.SYSCHECKS and SYSIBM.SYSCHECKDEP tables.

Adding check constraints

When you add a check constraint to a table that contains data, one of two things can happen:

  • All the rows meet the check constraint.

  • Some or all the rows do not meet the check constraint.

In the first case, when all the rows meet the check constraint, the check constraint will be created successfully. Future attempts to insert or update data that does not meet the constraint business rule will be rejected.

When there are some rows that do not meet the check constraint, the check constraint will not be created (i.e., the ALTER TABLE statement will fail), depending on the CURRENT RULES setting. The ALTER TABLE statement, which adds a new constraint to the EMPLOYEE table, is shown below. The check constraint is named check_job. DB2 will use this name to inform us which constraint was violated if an INSERT or UPDATE statement fails.

It is possible to turn off constraint checking to let you add a new constraint. The SET INTEGRITY statement enables you to turn off check constraint and referential constraint checking for one or more tables. When you turn off the constraint checking for a table, it will be put in a check-pending (CHKP) state, and only limited access to the table will be allowed. For example, once a table is in a check-pending state, use of SELECT, INSERT, UPDATE, and DELETE is disallowed on a table.

ALTER TABLE EMPLOYEE
ADD CONSTRAINT check_job
CHECK (JOB IN ('Engineer','Sales','Manager'));

NOTE

It is a good idea to label every constraint (triggers, table-check, or referential integrity). This is particularly important for diagnosing errors that might occur.

Modifying check constraints

As check constraints are used to implement business rules, you may need to change them from time to time. This could happen when the business rules change in your organization. There is no special command used to change a check constraint. Whenever a check constraint needs to be changed, you must drop it and create a new one. Check constraints can be dropped at any time, and this action will not affect your table or the data within it.

When you drop a check constraint, you must be aware that data validation performed by the constraint will no longer be in effect. The statement used to drop a constraint is the ALTER TABLE statement. The following example shows how to modify the existing constraint. After dropping the constraint, you have to create it with the new definition.

ALTER TABLE EMPLOYEE DROP CONSTRAINT check_job;

ALTER TABLE EMPLOYEE
ADD CONSTRAINT check_job
CHECK (JOB IN ('OPERATOR','CLERK'));
Creating Tables

The CREATE TABLE statement allows you to define a new table. The definition must include its name and the attributes of its columns. The definition may include other attributes of the table, such as its primary key or check constraints.

Once the table is defined, column names and data types cannot be modified. However, new columns can be added to the table (be careful when adding new columns, since default data values will be used for existing records).

The RENAME TABLE statement can change the name of an existing table.

The maximum number of columns that a table can consist of is 750. This maximum will not vary depending on the data page size on the OS/390. DB2 supports 4-KB, 8-KB, 16-KB, and 32-KB data page sizes. Table 2-5 shows the maximum number of columns in a table and maximum length of a row by page size.

NOTE

If the table is a dependent table in a referentially intact (RI) structure, then the maximum number of columns is 749.

Tables are always created within a tablespace. Users can specify the tablespace name in which the table will be created, or DB2 will create one implicitly. In the following example, DB2 will implicitly create a tablespace in the HUMANDB database because no tablespace name was provided. The name of the tablespace will be derived from the table.

Table 2-5. Maximum Table Columns and Row Lengths

4-KB Page

8-KB Page

16-KB Page

32-KB Page

Max Columns

750

750

750

750

Max Row Length (bytes)

4,056

8,138

16,330

32,714

CREATE TABLE Department
(Deptnumb SMALLINT NOT NULL,
Deptname VARCHAR(20),
Mgrno SMALLINT,
PRIMARY KEY(Deptnumb)
IN DATABASE HUMANDB
);

NOTE

Indexes will have their own index spaces created when they are created.

After a table is created, user data can be placed into the table using one of these methods:

  • INSERT statement

  • LOAD utility

  • DSN1COPY

NOTE

If an EDITPROC was defined on a table, the maximum row sizes shown in Table 2-5 would decrease by 10 bytes in each case.

NOTE

If you really need a temporary table that is used only for the duration of a program, use the DECLARE GLOBAL TEMP TABLE statement instead. This will result in no catalog contention, no logging, and no lock contention.

Following are sample CREATE TABLE statements. This example creates two tables. The definition includes unique constraints, check constraints, and referential integrity. In this example:

  • The DEPARTMENT table has a primary key that consists of column DEPTNUMB.

  • The EMPLOYEE table has a check constraint that says JOB should be Sales, Mgr, or Clerk.

  • The default value is defined for the column HIREDATE in the EMPLOYEE table.

  • EMPLOYEE table has a primary key that consists of column ID.

  • A referential constraint is defined between the DEPARTMENT table and the EMPLOYEE table.

  • The EMPLOYEE table is created in the HUMANTS tablespace in the HUMANDB database.

    CREATE TABLE Department
(Deptnumb SMALLINT NOT NULL,
Deptname VARCHAR(20),
Mgrno SMALLINT,
PRIMARY KEY(Deptnumb))
IN HUMANDB.HUMANTS;
CREATE TABLE Employee
(Id SMALLINT NOT NULL,
Name VARCHAR(9) NOT NULL,
Dept SMALLINT,
Job CHAR(5) CHECK (Job IN
('Sales','Mgr','Clerk')),
Hiredate DATE WITH DEFAULT CURRENT DATE,
Salary DECIMAL(7,2),
Comm DECIMAL(7,2),
CONSTRAINT UNIQUEID PRIMARY KEY(Id),
FOREIGN KEY(Dept) references DEPARTMENT(Deptnumb)
ON DELETE RESTRICT)
IN HUMANDB.HUMANTS;
Auxiliary Tables

LOB data is not actually stored in the table in which it is defined. The defined LOB column holds information about the LOB, while the LOB itself is stored in another location. The normal place for this data storage is a LOB tablespace defining the physical storage that will hold an auxiliary table related to the base column and table.

Because the actual LOB is stored in a separate table, one performance consideration might be that if you have a large variable character column in use (that is infrequently accessed), you may be able to convert it to a LOB so it is kept separately, and this could speed up tablespace scans on the remaining data because fewer pages would be accessed.

Null is the only supported default value for a LOB column, and if the value is null, then it will not take up space in the LOB tablespace. The examples below show how to create a base table with a LOB and an auxiliary table to support it.

CREATE TABLE DB2USER1.CANDIDATE
 (CID           CANDIDATE_ID    NOT NULL,
...
  CERT_APP      CHAR(1) NOT NULL WITH DEFAULT,
  PHOTO         BITMAP,
  PRIMARY KEY (CID)
  IN DB2CERT.CERTTS);

CREATE AUX TABLE CAND_PHOTO
  IN DB2CERT.CERTPIC
  STORES DB2USER1.CANDIDATE
  COLUMN PHOTO;
Copying a Table Definition

It is possible to create a table using the same characteristics of another table (or a view). This is done through the CREATE TABLE LIKE statement. The name specified after LIKE must identify a table or view that exists at the current server, and the privilege set must implicitly or explicitly include the SELECT privilege on the identified table or view. An identified table must not be an auxiliary table. An identified view must not include a column that is considered to be a ROWID column or an identity column.

The use of LIKE is an implicit definition of n columns, where n is the number of columns in the identified table or view. The implicit definition includes all attributes of the n columns as they are described in SYSCOLUMNS with a few exceptions, such as identity attributes (unless the INCLUDING IDENTITY clause is used).

The implicit definition does not include any other attributes of the identified table or view. For example, the new table will not have a primary key, foreign key, or check constraint. The table is created in the tablespace implicitly or explicitly specified by the IN clause, and the table has any other optional clause only if the optional clause is specified.

Below is an example of the CREATE LIKE statement:

CREATE TABLE New_Dept LIKE Department
IN DATABASE HUMANDB
Modifying a Table

After you create a table, the ALTER TABLE statement enables you to modify existing tables. The ALTER TABLE statement modifies existing tables by

  • Adding one or more columns to a table.

  • Adding or dropping a primary key.

  • Adding or dropping one or more unique or referential constraints.

  • Adding or dropping one or more check constraint definitions.

  • Altering the length of a VARCHAR column.

  • Enable auditing of the table.

Some of the attributes of a table can be changed only after the table is created. The following example shows how to add a check constraint to the DEPARTMENT table.

ALTER TABLE DEPARTMENT ADD CHECK (DEPTNUM > 10)
Removing a Table

When you want to remove a table, issue this statement:

DROP TABLE EMPLOYEE

NOTE

Any objects that are directly or indirectly dependent on this table are deleted or made inoperativefor example, indexes, triggers, and views. Whenever a table is deleted, its description is deleted from the catalog, and any packages that reference the object are invalidated.

Tablespaces

Data is stored in tablespaces that are comprised of one or many VSAM datasets. There are four types of tablespaces:

  • Simple

  • Segmented

  • Partitioned

  • LOB

Simple Tablespace

Simple tablespaces are the default but normally not the most optimal. In a simple tablespace you can have more than one table in the tablespace. If you have several tables in the tablespace, you can have rows from different tables interleaved on the same page; therefore, when a page is locked, you are potentially locking rows of other tables.

Segmented Table Space

Normally, in the cases where a table is not partitioned, a segmented, not simple, tablespace is used. A segmented tablespace organizes pages of the tablespace into segments, and each segment will contain the rows of only one table. Segments can be composed of 4 to 64 pages each, and each segment will have the same number of pages.

There are several advantages to using segmented tablespaces. Since the pages in a segment will contain rows from only one table, there will be no locking interference with other tables. In simple tablespaces, rows are intermixed on pages, and if one table page is locked, it can inadvertently lock a row of another table just because it is on the same page. When you have only one table per tablespace, this is not an issue; however, there are still several benefits to having a segmented tablespace for one table, such as

  • If a table scan is performed, the segments belonging to the table being scanned are the only ones accessed; empty pages will not be scanned.

  • If a mass delete or a DROP table occurs, segment pages are available for immediate reuse (after the commit), and it is not necessary to run a REORG utility.

  • Mass deletes are much faster for segmented tablespace, and they produce less logging.

  • The COPY utility will not have to copy empty pages left by a mass delete.

  • When inserting records, some read operations can be avoided by using the more comprehensive space map of the segmented tablespace.

  • By being able to safely combine several tables in a tablespace, you can reduce the number of open datasets necessary, which reduces the amount of memory required in the subsystem.

NOTE

When using a segmented tablespace to hold more than one table, make sure the tables have very similar characteristics in all categories, including size, volatility, locking needs, compression, and backup/recovery strategies.

There are some guidelines for how many tables to have in a segmented tablespace based upon the number of pages in the tablespace, but number of pages is not the only consideration. Table 2-6 lists very generic thresholds.

Table 2-6. Table Page Thresholds

Number of Pages

Table Space Design

> 100,000

Consider partitioning

> 10,000

One-table segmented tablespace

> 128 to < 10,000

Multiple-table segmented tablespaces

< 128

Multiple-table segmented tablespaces

The SEGSIZE is what tells DB2 on OS/390 how large to make each segment for a segmented tablespace, and it will determine how many pages are contained in a segment. The SEGSIZE will vary, depending on the size of the tablespace. Recommendations are listed in Table 2-7.

Table 2-7. Table Segment Size Recommendations

Number of Pages

SEGSIZE

28 or less

4 to 28

28 to 128

32

128 or more

64

NOTE

A segmented tablespace is a single dataset and is limited to 2 GB.

The following example shows how to create a segmented tablespace with a segment size of 32.

CREATE TABLESPACE CERTTS
IN DB2CERT
USING STOGROUP CERTSTG
PRIQTY 52
SECQTY 20
ERASE NO
LOCKSIZE PAGE
BUFFERPOOL BP6
CLOSE YES
SEGSIZE 32;

NOTE

The SEGSIZE parameter cannot be ALTERed.

Partitioned Tablespace

There are several advantages to partitioning a tablespace. For large tables, partitioning is the only way to store large amounts of data, but partitioning also has advantages for tables that are not necessarily large. DB2 allows us to define up 254 partitions of up to 64 GB each. Nonpartitioned tablespaces are limited to 64 GB of data. You can take advantage of the ability to execute utilities on separate partitions in parallel. This also gives you the ability to access data in certain partitions while utilities are executing on others. In a datasharing environment, you can spread partitions among several members to split workloads. You can also spread your data over multiple volumes and need not use the same storage group for each dataset belonging to the tablespace. This also allows you to place frequently accessed partitions on faster devices. The following shows an example of how to create a partitioned tablespace with two partitions:

CREATE TABLESPACE CERTTSPT
IN DB2CERT
USING STOGROUP CERTSTG
   PRIQTY 100
   SECQTY 120
   ERASE NO
NUMPARTS 2
(PART 1
 COMPRESS YES,
 PART 2
 FREEPAGE 20)
ERASE NO
LOACKSIZE PAGE
CLOSE NO;

NOTE

It is possible to use the ALTER statement to change the partitioning key ranges for rebalancing.

LOB Tablespaces

A LOB tablespace needs to be created for each column (or each column of each partition) of a base LOB table (table with a LOB column). This tablespace will contain the auxiliary table. This LOB tablespace has a structure that can be up to 4,000 TB in size. This is a storage model used only for LOB tablespaces. This linear tablespace can be up to 254 datasets, which can be up to 64 GB each. The LOB tablespace is basically implemented in the same fashion as pieces are implemented for NPIs (discussed later in this chapter). We can have 254 partitions of 64 GB each, allowing for a total of 16 TB, and we will have one for each LOB column (up to 254 partitions), which makes up to 4,000 TB possible. See Figure 2-3.

Figure 2-3. Physical LOB storage.

Partitioned base tables can each have different LOB tablespaces. A LOB value can be longer than a page in a LOB tablespace and can also span pages. Following is an example of creating a LOB tablespace.

CREATE LOB TABLESPACE CERTPIC
  IN DB2CERT
  USING STOGROUP CERTSTG
      PRIQTY 3200
      SECQTY 1600
  LOCKSIZE LOB
  BUFFERPOOL BP16K1
  GBPCACHE SYSTEM
  LOG NO
  CLOSE NO;

NOTE

If a table contains a LOB column and the plan or package is bound with SQLRULES (STD), then DB2 will implicitly create the LOB tablespace, the auxiliary table, and the auxiliary index. DB2 will choose the name and characteristics for these implicitly created objects. This is not a good idea. Naming standards and placement of these objects is critical for management and performance.

Creating Tablespaces

The CREATE TABLESPACE statement is used to define a simple, segmented, partitioned tablespace or LOB tablespace on the current server. There is a large number of parameters used in defining tablespaces, with significant options depending on the type of tablespace. The major tablespace parameters are

  • DSSIZE: This specifies that the maximum size of any partition in a partitioned tablespace can exceed the 2-GB limit up to a size of 64 GB.

  • LOB: This specifies that the tablespace is a LOB tablespace, used to hold only LOB values.

  • USING clause: This specifies whether or not storage groups or a user-defined tablespace is being defined.

    - USING STOGROUP specifies that DB2 will manage the datasets and there will also be a PRIQTY and SECQTY to define the allocations for the datasets.

    - USING VCAT specifies that the datasets will be user-defined.

  • FREEPAGE and PCTFREE: These parameters specify the amount of free space to be left when a tablespace is loaded or reorganized.

  • GBPCACHE: This is used in data sharing to specify which pages of a tablespace or partition are written to the group buffer pools.

  • NUMPARTS: This specifies the number of partitions in a partitioned tablespace, with a maximum of 254 allowed.

  • SEGSIZE: This specifies the number of pages in a segment for segmented tablespaces.

  • BUFFERPOOL: This specifies which buffer pool the tablespace is assigned to.

  • LOCKSIZE: This specifies the size of locks used within the tablespace and in certain cases can specify the threshold at which lock escalation occurs. The allowable lock sizes are

    - ANY

    - TABLESPACE

    - TABLE

    - PAGE

    - ROW

    - LOB

  • MAXROWS: Specifies the maximum number of rows that are allowed on a page up to a maximum of 255.

  • LOCKPART: Specifies whether or not selective partition locking is to be used when locking a partitioned tablespace.

  • COMPRESS: Specifies whether or not data compression is used for rows in the tablespace or partition.

  • TRACKMOD: Specifies whether DB2 tracks modified pages in the space map pages in the tablespace or partition.

Page sizes

Four page sizes are available for use, listed in Table 2-8.

Table 2-8. Table Page Sizes

Buffer Pool

Pages

BP0BP49

4-KB pages

BP8K0BP8K9

8-KB pages

BP16K0BP16K9

16-KB pages

BP32K0BP32K9

32-KB pages

The 8-KB, 16-KB, and 32-KB page sizes are logical constructs of actual physical 4-KB pages. Index page sizes are only 4-KB pages, and work file (DSNDB07) tablespace pages are only 4 KB or 32 KB.

With the larger page sizes, we can achieve better hit ratios and have less I/O because we can fit more rows on a page. For instance, if we have a 2,200-byte row (maybe for a data warehouse), a 4-KB page would be able to hold only one row, but if an 8-KB page was used, three rows could fit on a page, two more than if 4-KB pages were used, and one less lock also is required.

The page size is defined by the buffer pool chosen for the tablespace (i.e., BP8K0 supports 8-KB pages).

Free space

The FREEPAGE and PCTFREE clauses are used to help improve the performance of updates and inserts by allowing free space to exist on tablespaces or index spaces. Performance improvements include improved access to the data through better clustering of data, less index page splitting, faster inserts, fewer row overflows, and a reduction in the number of REORGs required. Some tradeoffs include an increase in the number of pages (and therefore more auxiliary storage needed), fewer rows per I/O and less efficient use of buffer pools, and more pages to scan. As a result, it is important to achieve a good balance for each individual tablespace and index space when deciding on free space, and that balance will depend on the processing requirements of each tablespace or index space. When inserts and updates are performed, DB2 will use the free space defined, and by doing this it can keep records in clustering sequence as much as possible. When the free space is used up, the records must be located elsewhere, and this is when performance can begin to suffer. Read-only tables do not require any free space, and tables with a pure insert-at-end strategy generally don't require free space. Exceptions to this would be tables with VARCHAR columns and tables using compression that are subject to updates.

The FREEPAGE amount represents the number of full pages inserted between each empty page during a LOAD or REORG of a tablespace or index space. The tradeoff is between how often reorganization can be performed and how much disk can be allocated for an object. FREEPAGE should be used for tablespaces so that inserts can be kept as close to the optimal page as possible. For indexes, FREEPAGE should be used for the same reason, except improvements would be in terms of keeping index page splits nearby the original page instead of placing them at the end of the index. FREEPAGE is useful when inserts are sequentially clustered.

PCTFREE is the percentage of a page left free during a LOAD or REORG. PCTFREE is useful when you can assume an even distribution of inserts across the key ranges. It is also needed in indexes to avoid all random inserts causing page splits.

Compression

Using the COMPRESS clause of the CREATE TABLESPACE and ALTER TABLESPACE SQL statements allows for the compression of data in a tablespace or in a partition of a partitioned tablespace.

NOTE

Indexes and LOB tablespaces are not compressed.

In many cases, using the COMPRESS clause can significantly reduce the amount of DASD space needed to store data, but the compression ratio achieved depends on the characteristics of the data.

Compression allows us to get more rows on a page and therefore see many of the following performance benefits, depending on the SQL workload and the amount of compression:

  • Higher buffer pool hit ratios

  • Fewer I/Os

  • Fewer getpage operations

  • Reduced CPU time for image copies

There are also some considerations for processing cost when using compression.

  • Compressing data can result in a higher processor cost, depending on the SQL workload. However, if you use IBM's synchronous data compression hardware, processor time is significantly less than if you use just the DB2-provided software simulation or an edit or field procedure to compress the data.

  • The processor cost to decode a row using the COMPRESS clause is significantly less than the cost to encode that same row. This rule applies regardless of whether the compression uses the synchronous data compression hardware or the software simulation built into DB2.

  • The data access path DB2 uses affects the processor cost for data compression. In general, the relative overhead of compression is higher for tablespace scans and less costly for index access.

The following example shows a tablespace created with compression:

CREATE TABLESPACE CERTTSPT
IN DB2CERT
USING STOGROUP CERTSTG
   PRIQTY 100
   SECQTY 120
   ERASE NO
COMPRESS YES
ERASE NO
LOACKSIZE PAGE
Modifying Tablespaces

After you create a tablespace, the ALTER TABLESPACE statement enables you to modify existing tablespaces. The ALTER TABLESPACE statement modifies many of the tablespace parameters, such as:

  • Change the buffer pool assignment.

  • Change the lock size or the lock escalation threshold.

  • Change the specifics for a single partition.

  • Change any of the space definitions.

  • Turn compression off and on.

  • Change how pages are cached in group buffer pools.

  • Change logging for LOB tablespaces.

  • Change the USING VCAT.

NOTE

If the USING VCAT is ALTERed, the tablespace must be stopped first.

In the following example, the ALTER TABLESPACE is used to change the buffer pool assignment and size of the locks used.

ALTER TABLESPACE DB2CERT.CERTTS
BUFFERPOOL BP4
LOCKSIZE ROW
Removing Tablespaces

When you want to remove a tablespace, the DROP TABLESPACE statement is used to delete the object. This will remove any objects that are directly or indirectly dependent on the tablespace. It will also invalidate any packages or plans that refer to the object and will remove its descriptions and all related data from the catalog.

DROP TABLESPACE DB2CERT.CERTTS

Views

Views are logical tables that are created using the CREATE VIEW statement. Once a view is defined, it may be accessed using DML statements, such as SELECT, INSERT, UPDATE, and DELETE, as if it were a base table. A view is a temporary table, and the data in the view is available only during query processing.

With a view, you can make a subset of table data available to an application program and validate data that is to be inserted or updated. A view can have column names that are different from the names of corresponding columns in the original tables. The use of views provides flexibility in the way the application programs and end-user queries look at the table data.

A sample CREATE VIEW statement is shown below. The original table, EMPLOYEE, has columns named SALARY and COMM. For security reasons, this view is created from the ID, NAME, DEPT, JOB, and HIREDATE columns. In addition, we are restricting access on the column DEPT. This definition will show the information only of employees who belong to the department whose DEPTNO is 10.

CREATE VIEW EMP_VIEW1
(EMPID,EMPNAME,DEPTNO,JOBTITLE,HIREDATE)
    AS SELECT ID,NAME,DEPT,JOB,HIREDATE FROM EMPLOYEE
    WHERE DEPT=10;

After the view has been created, the access privileges can be specified. This provides data security, since a restricted view of the base table is accessible. As we see in this example, a view can contain a WHERE clause to restrict access to certain rows or can contain a subset of the columns to restrict access to certain columns of data.

The column names in the view do not have to match the column names of the base table. The table name has an associated schema, as does the view name. Once the view has been defined, it can be used in DML statements such as SELECT, INSERT, UPDATE, and DELETE (with restrictions). The database administrator can decide to provide a group of users with a higher level privilege on the view than the base table.

A view is an alternate way to look at data in one or more tables. It is basically a SQL SELECT statement that is effectively executed whenever the view is referenced in a SQL statement. Since it is not materialized until execution, operations such as ORDER BY, the WITH clause, and the OPTIMIZE FOR clause have no meaning.

Views with Check Option

If the view definition includes conditions (such as a WHERE clause) and the intent is to ensure that any INSERT or UPDATE statement referencing the view will have the WHERE clause applied, the view must be defined using WITH CHECK OPTION. This option can ensure the integrity of the data being modified in the database. An SQL error will be returned if the condition is violated during an INSERT or UPDATE operation.

The following example is of a view definition using the WITH CHECK OPTION. The WITH CHECK OPTION is required to ensure that the condition is always checked. You want to ensure that the DEPT is always 10. This will restrict the input values for the DEPT column. When a view is used to insert a new value, the WITH CHECK OPTION is always enforced.

CREATE VIEW EMP_VIEW2
(EMPID,EMPNAME,DEPTNO,JOBTITLE,HIREDATE)
    AS SELECT ID,NAME,DEPT,JOB,HIREDATE FROM EMPLOYEE
    WHERE DEPT=10
WITH CHECK OPTION;

If the view in the above example is used in an INSERT statement, the row will be rejected if the DEPTNO column is not the value 10. It is important to remember that there is no data validation during modification if the WITH CHECK OPTION is not specified. If the view in the previous example is used in a SELECT statement, the conditional (WHERE clause) would be invoked, and the resulting table would contain only the matching rows of data. In other words, the WITH CHECK OPTION does not affect the result of a SELECT statement. The WITH CHECK OPTION must not be specified for views that are read only.

Nested View Definitions

If a view is based on another view, the number of predicates that must be evaluated is based on the WITH CHECK OPTION specification. If a view is defined without the WITH CHECK OPTION, the definition of the view is not used in the data validity checking of any insert or update operations. However, if the view directly or indirectly depends on another view defined with the WITH CHECK OPTION, the definition of that super view is used in the checking of any insert or update operation.

Modifying a View

In order to modify a view, you simply drop and recreate it. You cannot alter a view.

Removing a View

To remove a view, you simply use the following:

DROP VIEW EMP_VIEW2

Indexes

An index is a list of the locations of rows sorted by the contents of one or more specified columns. Indexes are typically used to improve the query performance. However, they can also serve a logical data design purpose. For example, a unique index does not allow the entry of duplicate values in columns, thereby guaranteeing that no rows of a table are the same. Indexes can be created to specify ascending or descending order by the values in a column. The indexes contain a pointer, known as a record ID (RID), to the physical location of the rows in the table. There are three main purposes for creating indexes:

  • To ensure uniqueness of values

  • To improve query performance

  • To ensure a physical clustering sequence

More than one index can be defined on a particular base table, which can have a beneficial effect on the performance of queries. However, the more indexes there are, the more the database manager must work to keep the indexes up to date during update, delete, and insert operations. Creating a large number of indexes for a table that receives many updates can slow down processing.

NOTE

Indexes are also stored in underlying VSAM datasets, just like tablespaces. In order to make a correlation between the index that you created (or DB2 created), you can look in the INDEXSPACE column in the SYSINDEXES catalog table.

We will take a look at some of the most important parameters of the CREATE INDEX statement.

  • TYPE 2: Specifies a type 2 index. The TYPE 2 clause is not required. A type 2 index is always created.

  • UNIQUE: Prevents the table from containing two or more rows with the same value of the index key.

  • USING clause: This specifies whether or not storage groups or a user-defined index space is being defined.

    - USING STOGROUP specifies that DB2 will manage the datasets and there will also be a PRIQTY and SECQTY to define the allocations for the datasets.

    - USING VCAT specifies that the datasets will be user defined and there are no space allocations defined in this statement.

  • FREEPAGE and PCTFREE: These parameters specify the amount of free space to be left when an index space is built or reorganized.

  • GBPCACHE: This is used in data sharing to specify which pages of a index space are written to the group buffer pools.

  • DEFINE: This specifies whether or not to create the underlying datasets.

  • CLUSTER: This specifies whether or not it is a clustering index.

  • PART: Identifies the partition number.

  • VALUES: Identifies the values of the keys to be contained in the partition.

  • BUFFERPOOL: This specifies which buffer pool the tablespace is assigned to.

  • PIECESIZE: Identifies the size of the pieces (datasets) used for a nonpartitioning index (NPI).

  • COPY: Specifies whether or not the index can be image copied.

Type 2

Type 2 indexes are created by default. There is no locking on type 2 indexes, and they do not have subpages. Type 1 indexes should not be used and, depending on the release of DB2, are unsupported.

Deferring Physical Definition

An index can be defined with the DEFINE NO option (DEFINE YES is default). This is done to specify an index and defer the actual physical creation. The datasets will not be created until data is inserted into the index. This option is helpful in order to reduce the number of physical datasets.

Clustering Index

On the S/390, it is generally important to control the physical sequence of the data in a table. The CLUSTER option is used on one and only one index on a table and specifies the physical sequence. If not defined, then the first index defined on the table in a nonpartitioned tablespace is used for the clustering sequence.

There is an option in defining tablespaces called MEMBER CLUSTER. When this is specified, the clustering sequence specified by the clustering index is ignored. In that case, DB2 will choose to locate the data based on available space when an SQL INSERT statement is used.

Partitioning Index

For a partitioned tablespace, a clustering index is required and specifies key ranges to be used for each partition. This requires using one PART clause for each partition, specifying the highest value for the partition. The length of the limit key is the same as the length of the partitioning index. The following example shows how to define a clustering index to be used for partitioning. In this example the data is partitioned by the TCIDentries with a key value up to 300 will go into partition 1 and entries with a key value up to 500 will go into partition 2.

CREATE UNIQUE INDEX DB2USER1.TESTCNTX
  ON DB2USER1.TEST_CENTER
   (TCID ASC)
  USING STOGROUP CERTSTG
  PRIQTY 512
  SECQTY 64
  ERASE NO
  CLUSTER
    (PART 1 VALUES (300),
     PART 2 VALUES (500))
  BUFFERPOOL BP3
  CLOSE YES;

Just like the partitioned tablespace, the partitioning index is made up of several datasets. Each partition can have different attributes (i.e., some may have more free space than others).

Unique Index and Nonunique Index

A unique index guarantees the uniqueness of the data values in a table's columns. The unique index can be used during query processing to perform faster retrieval of data. The uniqueness is enforced at the end of the SQL statement that updates rows or inserts new rows. The uniqueness is also checked during the execution of the CREATE INDEX statement. If the table already contains rows with duplicate key values, the index is not created. An example of creating a unique index follows.

CREATE UNIQUE INDEX DB2USER1.TESTIX
  ON DB2USER1.TEST
   (NUMBER ASC)
  USING STOGROUP CERTSTG
  PRIQTY 512
  SECQTY 64
  ERASE NO
  CLUSTER

A nonunique index can also improve query performance by maintaining a sorted order for the data. Depending on how many columns are used to define a key, you can have one of the following types:

  • An atomic key is a single-column key.

  • A composite key is composed of two or more columns.

  • The following are types of keys used to implement constraints:

    - A unique key is used to implement unique constraints. A unique constraint does not allow two different rows to have the same values on the key columns.

    - A primary key is used to implement entity integrity constraints. A primary key is a special type of unique key. There can be only one primary key per table. The primary key column must be defined with the NOT NULL option.

    - A foreign key is used to implement referential integrity constraints. Referential constraints can reference only a primary key or unique constraint. The values of a foreign key can have values defined only in the primary key or unique constraint they are referencing or null values. (A foreign key is not an index.)

NOTE

DB2 uses unique indexes and the NOT NULL option to maintain primary and unique key constraints.

Unique Where Not Null Index

This is a special form of a unique index. Normally, in a unique index, any two null values are taken to be equal. Specifying WHERE NOT NULL will allow any two null values to be unequal.

Null Values and Indexes

It is important to understand the difference between a primary key and a unique index. DB2 uses two elements to implement the relational database concept of primary and unique keys: unique indexes and the NOT NULL constraint. Therefore, unique indexes do not enforce the primary key constraint by themselves, since they can allow a null value. Null values are unknown, but when it comes to indexing, a null value is treated as equal to all other null values (with the exception of the UNIQUE WHERE NOT NULL INDEX). You cannot insert a NULL value twice if the column is a key of a unique index, because it violates the uniqueness rule for the index.

Nonpartitioning Indexes

NPIs are indexes that are used on partitioned tables. They are not the same as the clustered partitioning key, which is used to order and partition the data, but rather they are for access to the data. NPIs can be unique or nonunique. While you can have only one clustered partitioning index, you can have several NPIs on a table if necessary. NPIs can be broken apart into multiple pieces (datasets) by using the PIECESIZE clause on the CREATE INDEX statement. Pieces can vary in size from 254 KB to 64 GBthe best size will depend on how much data you have and how many pieces you want to manage. If you have several pieces, you can achieve more parallelism on processes, such as heavy INSERT batch jobs, by alleviating the bottlenecks caused by contention on a single dataset. The following example shows how to create an NPI with pieces:

CREATE UNIQUE INDEX DB2USER1.TESTCN2X
  ON DB2USER1.TEST_CENTER
   (CODE ASC)
  USING STOGROUP CERTSTG
  PIECESIZE 512K;
LOB Indexes

An index must be created on an auxiliary table for a LOB. The index itself consists of 19 bytes for the ROWID and 5 bytes for the RID. Due to this fact, it is always unique. No LOB columns are allowed in the index. The below example shows the CREATE statement for an auxiliary index.

CREATE INDEX DB2CERT.PHOTOIX
  ON DB2USER1.CAND_PHOTO
  USING VCAT DB2USER1
  COPY YES;

NOTE

No columns are specified, because the auxiliary indexes have implicitly generated keys.

General Indexing Guidelines

Indexes consume disk space. The amount of disk space will vary depending on the length of the key columns and whether the index is unique or nonunique. The size of the index will increase as more data is inserted into the base table. Therefore, consider the disk space required for indexes when planning the size of the database. Some of the indexing considerations include the following:

  • Primary and unique key constraints will always create a unique index.

  • It is usually beneficial to create indexes on foreign key constraint columns.

  • It is beneficial to always create a clustering index.

Modifying an Index

The ALTER INDEX statement will allow you to change many of the characteristics on the index, such as

  • Change the buffer pool assignment.

  • Change the specifics for a single partition.

  • Change any of the space definitions.

  • Change whether or not the index is to be copied.

The example below shows how to change the buffer pool assignment for an index.

ALTER INDEX TESTCN2X BUFFERPOOL BP1;
Removing an Index

When you want to remove an index, issue the following statement:

DROP INDEX TESTCN2X;

Databases

A database is a collection of tablespaces, index spaces, and the objects with them. There are also a couple of different types of databases that are used for special purposes: A WORKFILE database holds the DB2 work files used for sorting and other activities, and a TEMP database holds temporary tables as defined by a DECLARE TEMP statement (refer to Chapter 7 for more information on declared temporary tables). For these special databases, you can also specify which data sharing member they are for, since each member must have its own. You can also specify the coding scheme for the data in the database (ASCII, CCSID, EBCDIC, UNICODE).

Creating a Database

Following is an example of the creation of the DB2CERT database. The BUFFERPOOL parameter lets us specify that any objects created in this database without a buffer pool assigned will default to buffer pool BP7. INDEXBP is for the same reason, but provides a default buffer pool for indexes.

CREATE DATABASE CERTTS
STOGROUP CERTSTG
BUFFERPOOL BP7
INDEXBP BP8;
Modifying a Database

The default buffer pools, encoding scheme, and the storage group can be changed for a database. The following is an example of ALTER DATABASE.

ALTER DATABASE DB2CERT
BUFFERPOOL BP4;
Removing a Database

It is very easy to remove a database, it is a simple DROP statement (provided all the appropriate authorities are in place). When a database is dropped, all dependent objects are dropped.

DROP DATABASE DB2CERT;

Storage Groups

Storage groups are used to list the DASD volumes that will be used to store the data. They can contain one or many volumes. Storage groups can work with or without SMS (system-managed storage). If tablespaces or index spaces are defined using a storage group (identified in the USING clause in the CREATE INDEX and CREATE TABLESPACE statements), they are considered to be DB2-managed, and DB2 will create them, allowing you to specify the PRIQTY and SECQTY for the dataset allocations. Otherwise, they are considered to be user-managed and must be defined explicitly through ICF (Integrated Catalog Facility).

Creating a Storage Group
CREATE STOGROUP CERTSTG
VOLUME(*) VCAT DB2USER1;

NOTE

The asterisk (*) in this example indicates that SMS will manage the volumes to be used.

Modifying a Storage Group

We can add or remove volumes within a storage group. This is done via the ALTER.

ALTER STOGROUP CERTSTG ADD VOL1;
Removing a Storage Group

Storage groups can be removed by using the DROP statement. This can be done only if there are no tablespaces or index spaces using it.

DROP STOGROUP CERTSTG;


024 - Database Design and Implementation

Chapter 2. Database Objects

Database Design and Implementation

The best way to understand data type selection is to design a database and implement the design using DB2. We will create a database that can be used to schedule and track the results of a certification program. This database will be used to illustrate many aspects of SQL and features of DB2. You have already seen many examples from this database throughout this chapter. This database will be used to schedule test candidates' exams, and following the completion of the test, it will contain the candidates' test scores. The database and its application will need to perform the following tasks:

  1. Insert/update/delete testing center information.

  2. Insert/update/delete test information.

  3. Insert/update/delete test candidate information.

  4. Guarantee a uniquely identified test name, regardless of the test number.

  5. Schedule a candidate to take a test.

  6. Update candidate test scores once exams have been completed.

  7. Determine which candidates qualify for certification.

  8. Generate various reports on the candidates and tests.

The database will be named DB2CERT. The data to be stored in the DB2CERT database can easily be grouped into three reference tables, and a fourth table is used to relate the other tables. The primary relationship can be defined as a test candidate takes a specific test at a test center.

Figure 2-4 shows the relationships within the problem domain. The rectangles represent the base tables: CANDIDATE, TEST_CENTER, and TEST. The fourth table is a relationship table called TEST_TAKEN.

Figure 2-4. Tables for the DB2CERT database.

DB2CERT Database Table Descriptions

The following is a list of tables that will be used in the DB2CERT database:

  • The CANDIDATE table stores information about each test candidate for the DB2 Certification Program. Data such as candidate name, address, candidate ID, and phone number will be stored in this table. A data record represents a single test candidate (person).

  • The TEST_CENTER table stores information about the test centers where a candidate can take a DB2 Certification exam. Data such as the test center name, address, number of seats at the test center, test center ID, and its phone number will be stored in this table. A data record represents a single test center location.

  • The TEST table stores information about each of the DB2 Certification exams. Data such as the test name, type, test ID, cut score (passing percentage), and the length of each test will be stored in this table. A data record represents a single test. For our example, there are three tests in the DB2 Certification Program; therefore, there are only three data records in this table. A test name must be uniquely identified.

  • The TEST_TAKEN table associates the records from the other three tables. It serves the dual purpose of scheduling tests and tracking each test result. Data such as the candidates' test scores, date taken, start time, and seat number will be stored in this table. This will be the most active of the four tables, since multiple exams must be taken by each candidate to become certified, and each test taken will have a corresponding data record in this table.

Once you have defined the tables and their relationships, the following should be defined:

  1. User-defined data types

  2. Columns or attributes for the tables

  3. (Optional) primary keys (PK) for the tables

  4. (Optional) unique keys for the tables

  5. (Optional) foreign keys (referential constraints) for the tables

  6. (Optional) table-check constraints for the tables

  7. (Optional) triggers for the database

In Figure 2-5, the database design is shown. The rectangles represent the entities or tables. The columns or attributes are shown as ellipses. Note that some of the columns are derived columns. A derived column is a column that represents a concept and not a physical attribute of an object. The derived columns are included in the model because their values will be populated by the database using a constraint mechanism.

Figure 2-5. DB2 Certification database entity relationship diagram.

We must map the attributes shown in Figure 2-5 to DB2 as supported data types or user-defined data types. To demonstrate some of the powerful features of DB2, we have decided to create distinct types for many of the attributes.

It is beneficial to have a primary key defined for each table, since this will ensure uniqueness of the data records. The attributes that are underlined will be used as primary keys. We will also create unique keys to illustrate their use. Unique key attributes are double underlined.

In the previous section, we mentioned that there will be four tables in the DB2CERT database. However, the design shown in Figure 2-5 has only three tables defined:

They are shown as rectangles. There is an implied table defined in the relationship candidate takes a test. A table is required to store each occurrence of a candidate taking a certification test.

We will impose a restriction on the candidates: They can take the test only once on any given day. A candidate can take different tests on the same day, but not the same test. With this restriction in place, we will define a primary key for the TEST_TAKEN table as a composite key including NUMBER (test ID), CID (candidate ID), and DATE_TAKEN (the date of the test). By defining the primary key as a combination of these three values, we can enforce this constraint.

Figures 2-5 and 2-6 show the entity relationship diagrams for the Certification database.

Figure 2-6. DB2 Certification database entity basic relationship diagram.

Figure 2.7 shows the RI relationships between the tables in the Certification database.

Figure 2-7. DB2 Certification database referential integrity.

The diamond shapes are used to describe the relationships between the tables, including the parentchild relationship. For example, there is a one-to-many relationship between the CANDIDATE and the TEST_TAKEN table because a single candidate can take many tests. This relationship is shown by denoting the values of 1 and N (many) on the appropriate side of the diamond.

The database design shown in Figure 2-5 is just one type of diagramming technique. A logical database design can be represented in a number of ways, but it should not dictate the physical implementation of the database. We have included it here because it will be used in many of the SQL statements throughout the rest of the book.

Defining User-Defined Data Types

If you wish to utilize user-defined data types, they must exist in your database before they can be referenced in a CREATE TABLE statement. We have decided to create a number of user-defined data types, as shown in the following example. The CANDIDATE_ID, TEST_ID, CENTER_ID, and PHONE data types are all based on the fixed-length character (CHAR) data type. These attributes were chosen to be user-defined because they have meaning in their structure, and they should not be used in expressions with other character data types. For example, a telephone number data type could be defined and then a user-defined function could be created to extract the area code. The function would be used only for phone data types.

We also decided to create some numeric user-defined data types, including the data types score and minutes.

CREATE DISTINCT TYPE candidate_id AS CHAR(8)
WITH COMPARISONS
CREATE DISTINCT TYPE test_id AS CHAR(6)
WITH COMPARISONS
CREATE DISTINCT TYPE center_id AS CHAR(4)
WITH COMPARISONS
CREATE DISTINCT TYPE phone AS CHAR(10)
WITH COMPARISONS
CREATE DISTINCT TYPE score AS DECIMAL(6,2)
WITH COMPARISONS
CREATE DISTINCT TYPE minutes AS SMALLINT
WITH COMPARISONS

Defining Tables and Columns

Designing a database involves many considerations. We will examine only some of these considerations in this book. If we use the database design in Figure 2-5 as a starting point, we can start creating database objects.

The first step in creating a database is to issue the run a CREATE DATABASE statement, such as the one below.

CREATE DATABASE CERTTS
STOGROUP CERTSTG
BUFFERPOOL BP7
INDEXBP BP8;

Once the database has been created, we can start creating objects. We can create distinct (user-defined) data types as we did previously. Then we can start creating tables (if explicit tablespaces are to be used, they will need to be created first, but for this example we will assume they are already created. Refer to Appendix C, "DB2CERT Database DDL," for more of the tablespace create methods).

The database design has a number of attributes shown. Each of these attributes will be a column in the table definitions. Every DB2 table contains one or more columns. The tables and their corresponding columns are given names. In the previous sections, we discussed all of the data types that can be used for column definitions.

Data is placed in a DB2 table using the SQL statement INSERT or UPDATE. (The LOAD utility is also an option.) Usually, it is desirable for each column, or data value, to have a value. Sometimes, there is no value provided for a column during the INSERT statement. If the column is defined as NOT NULL, the INSERT statement will fail. If a default value is defined, it will be stored.

The table being created in the following DDL is called DB2CERT.CANDIDATE, and it contains 14 columns. Each column is given a name and a data type. There are two user-defined data types being used in the DB2CERT.CANDIDATE table. These data types are CANDIDATE_ID and PHONE There are also constraints defined for the valid values for some of the columns. For example, the null constraint is specified for all of the columns except HPHONE, WPHONE, and INITIAL.

CREATE TABLE db2cert.candidate (
    Cid candidate_id NOT NULL,
LName VARCHAR(30) NOT NULL,
FName VARCHAR(30) NOT NULL,
Initial CHAR(1),
HPhone phone,
WPhone phone,
StreetNo VARCHAR(8) NOT NULL,
StreetName VARCHAR(20) NOT NULL,
City VARCHAR(30) NOT NULL,
Prov_State VARCHAR(30) NOT NULL,
Code CHAR(6) NOT NULL,
Country VARCHAR(20)) NOT NULL,
Cert_DBA CHAR(1) NOT NULL WITH DEFAULT 'N',
Cert_APP CHAR(1) NOT NULL WITH DEFAULT 'N',
CONSTRAINT Unique_Candidate PRIMARY KEY (Cid))
IN DB2CERT.CERTTS;

Keys

Keys are a special set of columns defined on a table. They can be used to uniquely identify a row or to reference a uniquely identified row from another table. Keys can be classified either by the columns they are composed of or by the database constraint they support.

Depending on how many columns are used to define a key, you can have one of the following types:

  • An atomic key is a single-column key.

  • A composite key is composed of two or more columns.

The following are types of keys used to implement constraints:

  • A unique key is used to implement unique constraints. A unique constraint does not allow two different rows to have the same values in the key columns.

  • A primary key is used to implement entity integrity constraints. A primary key is a special type of unique key. There can be only one primary key per table. The primary key column must be defined with the NOT NULL option.

  • A foreign key is used to implement RI constraints. Referential constraints can reference only a primary key or unique key. The values of a foreign key can have values defined only in the primary key or unique key they are referencing or the null value.

Defining Primary Keys

It is sometimes beneficial to define a primary key for each of your DB2 tables, since this will guarantee the uniqueness of a column value or group of column values (composite key). In the previous CREATE statement, the primary key for the table candidate is defined as the column CID (candidate ID). By specifying this column as a primary key, DB2 will create a system-unique index if one does not already exist.

Let us look at the other tables representing the tests and the test centers. In the following CREATE statements, the TEST and TEST_CENTER tables are shown. These tables each have a primary key defined. In our example, the primary key constraint was given a name (UNIQUE_TEST and UNIQUE_CENTER) for referencing purposes.

CREATE TABLE db2cert.test (
Number test_id NOT NULL,
Name VARCHAR(50) NOT NULL,
Type CHAR(1) NOT NULL,
Cut_Score score NOT NULL,
Length minutes NOT NULL,
TotalTaken SMALLINT NOT NULL,
TotalPassed SMALLINT NOT NULL,
CONSTRAINT Unique_Test PRIMARY KEY(Number),
CONSTRAINT Unique_Test_Name UNIQUE (Name)
CONSTRAINT Test_Type CHECK (Type IN ('P','B')))
IN DB2CERT.CERTTS

CREATE TABLE db2cert.test_center (
Tcid center_id NOT NULL,
Name VARCHAR(40) NOT NULL,
StreetNo VARCHAR(8) NOT NULL,
StreetName VARCHAR(20) NOT NULL,
City VARCHAR(30) NOT NULL,
Prov_State VARCHAR(30) NOT NULL,
Country VARCHAR(20) NOT NULL,
Code CHAR(6) NOT NULL,
Type CHAR(1) NOT NULL,
Phone phone NOT NULL,
No_Seats SMALLINT NOT NULL,
CONSTRAINT Unique_Center PRIMARY KEY (Tcid))
IN DB2CERT.CERTTS
Defining Unique Keys

Unique keys can be used to enforce uniqueness on a set of columns. A table can have more than one unique key (index) defined. The TEST table definition uses a unique constraint (UNIQUE_TEST_NAME) on column NAME to ensure that a test name is not used twice. There is also a primary key constraint on the column NUMBER to avoid duplicate test numbers.

Having unique constraints on more than one set of columns of a table is different than defining a composite unique key that includes the whole set of columns. For example, if we define a composite primary key on the columns NUMBER and NAME, there is still a chance that a test name will be duplicated using a different test number.

NOTE

A unique index needs to be always created for primary (if one does not already exist) or unique key constraints (unless using the schema processor). If you define a constraint name, it will be used to name the index; otherwise, a system-generated name will be used for the index.

Defining Foreign Keys

A foreign key is a reference to the data values in another table. There are different types of foreign key constraints. Let us look at the remaining table in the DB2 Certification database and, in particular, its foreign key constraints. We have one composite primary key defined and three foreign key constraints.

The primary key is defined as the columns CID, TCID, and NUMBER. The foreign key constraints will perform the following:

  • If a record in the candidate table is deleted, all matching records in the TEST_TAKEN table will be deleted (DELETE CASCADE).

  • If a test center in the TEST_CENTER table is deleted, all of the matching records in the TEST_TAKEN table will be deleted (DELETE CASCADE).

  • If a test in the TEST table is deleted and there are matching records in the TEST_TAKEN table, the DELETE statement will result in an error (DELETE RESTRICT).

NOTE

A foreign key constraint always relates to the primary or unique constraint of the table in the references clause.

CREATE TABLE db2cert.test_taken (
Cid candidate_id NOT NULL,
Tcid center_id NOT NULL,
Number test_id NOT NULL,
Date_Taken date NOT NULL WITH DEFAULT,
Start_Time TIME NOT NULL,
Finish_Time TIME NOT NULL,
Score score,
Seat_No CHAR(2) NOT NULL,
CONSTRAINT number_const
PRIMARY KEY (Cid,Tcid,Number),
FOREIGN KEY (Cid)
REFERENCES db2cert.candidate ON DELETE CASCADE,
FOREIGN KEY (Tcid)
REFERENCES db2cert.test_center ON DELETE CASCADE,
FOREIGN KEY (Number)
REFERENCES db2cert.test ON DELETE RESTRICT)
IN DB2CERT.CERTTS

Defining parentchild relationships between tables is known as declarative referential integrity because the child table refers to the parent table. These constraints are defined during table creation or by using the ALTER TABLE SQL statement. DB2 will enforce referential constraints for all INSERT, UPDATE, and DELETE activity.

NOTE

This database implementation created only the tables and UDTs. The complete DDL for the storage group, databases, tablespaces, tables, and indexes can be found in Appendix C.


025 - Access to DB2 Objects

Chapter 2. Database Objects

Access to DB2 Objects

An individual process can be represented by a primary authorization identifier (ID), possibly one or more secondary IDs, and an SQL ID. The use of IDs is affected by the security and network systems, and by the DB2 connections made.

DB2 controls access to objects by assigning privileges and authorities to either primary or secondary IDs. Ownership of an object carries with it a set of related privileges over the object. An ID can own an object it creates, or it can create an object to be owned by another ID. There are separate controls for creation and ownership. We will take a look at how privileges, authorities, and ownership work together to provide security for access to DB2 objects.

Executing a plan or package exercises implicitly all the privileges that the owner needed when binding it. Hence, granting the privilege to execute can provide a finely detailed set of privileges and can eliminate the need to grant other privileges separately.

NOTE

You can use resource access control facility (RACF) access control to supplement or replace the DB2 GRANT and REVOKE.

Explicit Privileges and Authorities

One way of controlling access within DB2 is by granting, not granting, or revoking explicit privileges and authorities to authorization IDs. A privilege allows a specific operation, sometimes on a specific object. An explicit privilege has a name and is held as the result of an SQL GRANT or REVOKE statement. The authorities group these privileges together. Both privileges and authorities are held by authorization IDs. These will be covered in detail in this chapter.

NOTE

When installing or updating DB2, the entire system of control within DB2 can be disabled by setting USE PROTECTION to NO DB2. If protection in DB2 is disabled, then any user that gains access can do anything, but no GRANT or REVOKE statements are allowed.

Authorization IDs

Every process that connects to or signs on to DB2 is represented by a set of one or more DB2 short identifiers called authorization IDs. Authorization IDs can be assigned to a process by default procedures or by user-written exit routines.

Primary Authorization ID

A primary authorization ID is assigned to every process. There will be only one primary authorization ID for a process, and it is the ID normally used to uniquely identify a process.

Secondary Authorization ID

A secondary authorization ID is optional, and this ID can hold additional privileges. Secondary authorizations are often used for groups, such as RACF groups, and a primary authorization ID can be associated with multiple secondary authorization IDs.

Current SQL ID

Either the primary ID or the secondary ID can be the current SQL ID at any given time. Furthermore, one ID (either primary or secondary) is designated as the current SQL ID. You can change the value of the SQL ID during your session. If DB2EXPT is your primary or one of your secondary authorization IDs, you can make it your current SQL ID by issuing the SQL statement

SET CURRENT SQLID ='DB2EXPT';

An ID with SYSADM authority (covered in this section) can set the current SQL ID to any string of up to 8 bytes, whether or not it is an authorization ID or associated with the process that is running.

Explicit Privileges

There are several explicit privileges that can be granted to a primary or secondary authorization ID, allowing that ID the privilege to perform a particular task. When some privileges are granted, they also provide an inherited authority (e.g., if CREATEDBA is granted to an ID, then that ID will become DBADM over the database it creates). The privileges are grouped into several categories.

  • Plans

  • Packages

  • Collections

  • Databases

  • Systems

  • Usage

  • Schemas

  • Distinct types

  • Routines

Table 2-9 provides a list of the available privileges that can be granted to a primary or secondary authorization ID and the type of usage associated with the privilege.

Table 2-9. Privileges for Primary or Secondary Authorization ID

Privilege

Provides the following usage…

Table

ALTER

ALTER TABLE, to change the table definition.

DELETE

DELETE, to delete rows.

INDEX

CREATE INDEX, to create an index on the table.

INSERT

INSERT, to insert rows.

REFERENCES

ALTER or CREATE TABLE, to add or remove a referential constraint referring to the named table or to a list of columns in the table.

SELECT

SELECT, to retrieve data from the table.

TRIGGER

CREATE TRIGGER, to define a trigger on a table.

GRANT ALL

SQL statements of all table privileges.

Plan

BIND

BIND, REBIND, and FREE PLAN, to bind or free the plan.

EXECUTE

RUN, to use the plan when running the application.

Package

BIND

The BIND, REBIND, and FREE PACKAGE subcommands, and the DROP PACKAGE statement, to bind or free the package, and, depending on the installation option BIND NEW PACKAGE, to bind a new version of a package.

COPY

The COPY option of BIND PACKAGE, to copy a package.

EXECUTE

Inclusion of the package in the PKLIST option of BIND PLAN.

GRANT ALL

All package privileges.

Collection

CREATE IN

Naming the collection in the BIND PACKAGE subcommand.

Database

CREATETAB

The CREATE TABLE statement, to create tables in the database.

CREATETS

The CREATE TABLESPACE statement, to create tablespaces in the database.

DISPLAYDB

The DISPLAY DATABASE command, to display the database status.

DROP

The DROP and ALTER DATABASE statements, to drop or alter the database.

IMAGCOPY

The QUIESCE, COPY, and MERGECOPY utilities, to prepare for, make, and merge copies of tablespaces in the database; the MODIFY utility, to remove records of copies.

LOAD

The LOAD utility, to load tables in the database.

RECOVERDB

The RECOVER, REBUILD INDEX, and REPORT utilities, to recover objects in the database and report their recovery status.

REORG

The REORG utility, to reorganize objects in the database.

REPAIR

The REPAIR and DIAGNOSE utilities (except REPAIR DBD and DIAGNOSE WAIT), to generate diagnostic information about and repair data in objects in the database.

STARTDB

The START DATABASE command, to start the database.

STATS

The RUNSTATS and CHECK utilities, to gather statistics and check indexes and referential constraints for objects in the database.

STOPDB

The STOP DATABASE command, to stop the database.

Subsystem

ARCHIVE

The ARCHIVE LOG command, to archive the current active log; the DISPLAY ARCHIVE command, to give information about input archive logs; the SET LOG command, to modify the checkpoint frequency specified during installation; and the SET ARCHIVE command, to control allocation and deallocation of tape units for archive processing.

BINDADD

The BIND subcommand with the ADD option, to create new plans and packages.

BINDAGENT

The BIND, REBIND, and FREE subcommands, and the DROP PACKAGE statement, to bind, rebind, or free a plan or package, or copy a package on behalf of the grantor. The BINDAGENT privilege is intended for separation of function, not for added security. A bind agent with the EXECUTE privilege might be able to gain all the authority of the grantor of BINDAGENT.

BSDS

The RECOVER BSDS command, to recover the bootstrap dataset.

CREATEALIAS

The CREATE ALIAS statement, to create an alias for a table or view name.

CREATEDBA

The CREATE DATABASE statement, to create a database and have DBADM authority over it.

CREATEDBC

The CREATE DATABASE statement, to create a database and have DBCTRL authority over it.

CREATEESG

The CREATE STOGROUP statement, to create a storage group.

CREATETMTAB

The CREATE GLOBAL TEMPORARY TABLE statement, to define a created temporary table.

DISPLAY

The DISPLAY ARCHIVE, DISPLAY BUFFERPOOL, DISPLAY DATABASE, DISPLAY LOCATION, DISPLAY LOG, DISPLAY THREAD, and DISPLAY TRACE commands, to display system information.

MONITOR1

Receive trace data that is not potentially sensitive.

MONITOR2

Receive all trace data.

RECOVER

The RECOVER INDOUBT command, to recover threads.

STOPALL

The STOP DB2 command, to stop DB2.

STOSPACE

The STOSPACE utility, to obtain data about space usage.

TRACE

The START TRACE, STOP TRACE, and MODIFY TRACE commands, to control tracing.

Use

USE OF BUFFERPOOL

A buffer pool.

USE OF STOGROUP

A storage group.

USE OF TABLESPACE

A tablespace.

Schema

CREATEIN

Create distinct types, user-defined functions, triggers, and stored procedures in the designated schemas.

ALTERIN

Alter user-defined functions or stored procedures, or specify a comment for distinct types, user-defined functions, triggers, and stored procedures in the designated schemas.

DROPIN

Drop distinct types, user-defined functions, triggers, and stored procedures in the designated schemas.

Distinct Type

USAGE ON DISTINCT TYPE

A distinct type.

Routine

EXECUTE ON FUNCTION

A user-defined function.

EXECUTE ON PROCEDURE

A stored procedure.

NOTE

There are also additional privileges for statements, commands, and utility jobs.

GRANTing and REVOKEing Privileges

The privileges in Table 2-9 must be GRANTed to an authorization ID. The GRANT and REVOKE statements are part of the SQL language known as DCL (Data Control Language). We will take a look at a couple of examples of GRANTing and REVOKEing privileges.

In order to grant DB2EXPT the ability to select data from a particular table, we must execute the following SQL statement:

GRANT SELECT ON DB2CERT.TEST_TAKEN TO DB2EXPT

To grant DB2EXPT the ability to BIND packages to the CERTCL collection, we would execute the following statement:

GRANT BIND ON PACKAGE CERTCL.* TO DB2EXPT

To grant everyone the ability to select, update, insert, or delete data from a particular table, we must execute the following SQL statement:

NOTE

The keyword PUBLIC allows for any user to have the privilege granted.

To take away everyone's delete privilege from a particular table, we must execute the following SQL statement:

REVOKE DELETE ON DB2CERT.TEST_TAKEN FROM PUBLIC

Revoking a privilege from a user can also cause that privilege to be revoked from other users. This is called a cascade revoke.

Related and Inherited Privileges

DB2 has defined sets of related privileges that are identified by administrative authorities. We will take a look at these authorities in the next section. This grouping makes it easier to administrate authority, because instead of having to grant several individual privileges to an ID, one can simple grant the administrative authoritywhich includes all applicable privileges. There are also privileges that are inherited with object ownership.

Authorities

An administrative authority is a set of privileges, often covering a related set of objects (see Table 2-10). Authorities often include privileges that are not explicit, have no name, and cannot be specifically granted; for example, the ability to terminate any utility job, which is included in the SYSOPR authority.

Table 2-10. Authorities

Authorization

Description of Capabilities

Privileges

Installation SYSADM

Assigned during DB2 installation. This ID has all the privileges of SYSADM plus

  • Authority is not recorded in the DB2 catalog. The catalog need not be available to check installation SYSADM authority. (The authority outside the catalog is crucial: If the catalog tablespace SYSDBAUT is stopped, for example, DB2 cannot check the authority to start it again. Only an installation SYSADM can start it.)

  • No ID can revoke this authority; it can be removed only by changing the module that contains the subsystem initialization parameters (typically DSNZPARM).

Those IDs can also:

  • Run the CATMAINT utility.

  • Access DB2 when the subsystem is started with ACCESS(MAINT).

  • Start databases DSNDB01 and DSNDB06 when those are stopped or in restricted status.

  • Run the DIAGNOSE utility with the WAIT statement.

  • Start and stop the database containing the application registration table (ART) and object registration table (ORT).

All privileges of all the authorities.

SYSCTRL

Almost complete control of the DB2 subsystem but cannot access user data directly, unless granted the privilege to do so. Designed for administering a system containing sensitive data, SYSCTRL can

  • Act as installation SYSOPR (when the catalog is available) or DBCTRL over any database.

  • Run any allowable utility on any database.

  • Issue a COMMENT ON, LABEL ON, or LOCK TABLE statement for any table.

  • Create a view for itself or others on any catalog table.

  • Create tables and aliases for itself or others.

  • Bind a new plan or package, naming any ID as the owner.

Without additional privileges, it cannot

  • Execute DML statements on user tables or views.

  • Run plans or packages.

  • Set the current SQL ID to a value that is not one of its primary or secondary IDs.

  • Start or stop the database containing the ART and ORT.

  • Act fully as SYSADM or as DBADM over any database.

  • Access DB2 when the subsystem is started with ACCESS(MAINT).

Note that SYSCTRL authority is intended for separation of function, not for added security.

System privileges:

  • BINDADD

  • BINDAGENT

  • CREATEDBC

  • CREATESG

  • BSDS

  • CREATETMTAB

  • CREATEALIAS

  • CREATEDBA

  • MONITOR1

  • MONITOR2

  • STOSPACE

Privileges on all tables:

  • ALTER INDEX

  • REFERENCES

  • TRIGGER

Privileges on catalog tables:

  • SELECT

  • UPDATE

  • INSERT

  • DELETE

Privileges on all plans:

  • BIND

Privileges on all packages:

  • BIND

  • COPY

Privileges on all collections:

  • CREATE IN

Privileges on all schemas:

  • CREATE IN

  • DROPIN

  • ALTERIN

Use privileges on

  • BUFFERPOOL

  • TABLESPACE

  • STOGROUP

SYSADM

Includes SYSCTRL plus access to all data. SYSADM can

  • Use all the privileges of DBADM over any database.

  • Use EXECUTE and BIND on any plan or package, and COPY on any package.

  • Use privileges over views that are owned by others.

  • Set the current SQL ID to any valid value, whether it is currently a primary or secondary authorization ID.

  • Create and drop synonyms and views for others on any table.

  • Use any valid value for OWNER in BIND or REBIND.

  • Drop database DSNDB07.

  • Grant any of the privileges listed above to others.

Holders of SYSADM authority can also drop or alter any DB2 object except system databases, issue a COMMENT ON or LABEL ON statement for any table or view, and terminate any utility job, but SYSADM cannot specifically grant those privileges.

All privileges held by SYSCTRL and DBADM.

Plan privileges:

  • EXECUTE

Package privileges:

  • BIND

  • COPY

FREERoutine privileges:

  • EXECUTE

Distinct type privileges:

  • USAGE

SYSOPR

  • Ability to issue most DB2 commands except ARCHIVE LOG, START DATABASE, STOP DATABASE, and RECOVER BSDS.

  • Ability to terminate any utility job.

  • Ability to execute the DSN1SDMP utility.

Privileges:

  • DISPLAY

  • STOPALL

  • RECOVER

  • TRACE

Privileges on routines:

  • START DISPLAY

  • STOP

Installation SYSOPR

Assigned during DB2 installation. Privileges in addition to SYSOPR:

  • Authority is not recorded in the DB2 catalog. The catalog need not be available to check installation SYSOPR authority.

  • No ID can revoke the authority; it can be removed only by changing the module that contains the subsystem initialization parameters (typically DSNZPARM).

  • Access DB2 when the subsystem is started with ACCESS(MAINT).

  • Run all allowable utilities on the directory and catalog databases (DSNDB01 and DSNDB06).

  • Run the REPAIR utility with the DBD statement.

All privileges held by SYSOPR.

System privileges:

  • ARCHIVE STARTDB (cannot change access mode)

  • Start and stop the database containing the ART and ORT.

  • Issue dynamic SQL statements that are not controlled by the DB2 governor. Issue a START DATABASE command to recover objects that have logical page list (LPL) entries or group buffer pool recovery-pending status. These IDs cannot change the access mode.

PACKADM

Has all package privileges on all packages in specific collections or on all collections, plus the CREATE IN privilege on those collections. If the installation option BIND NEW PACKAGE is BIND, PACKADM also has the privilege to add new packages or new versions of existing packages.

Privileges on a collection:

  • CREATE IN

Privileges on all packages in the collection:

  • EXECUTE

  • BIND

  • COPY

DBMAINT

Granted for a specific database, in which the ID can create certain objects, run certain utilities, and issue certain commands. Can use the TERM UTILITY command to terminate all utilities except DIAGNOSE, REPORT, and STOSPACE on the database.

Privileges on one database:

  • CREATETAB

  • STARTDB

  • CREATETS

  • STATS

  • DISPLAYDB

  • STOPDB

  • IMAGCOPY

DBCTRL

In addition to DBMAINT privileges, it can run utilities that can change the data.

All privileges held by DBMAINT on a database. Privileges on one database:

  • DROP LOAD

  • RECOVERDB REORG

  • REPAIR

DBADM

In addition to the privileges held by DBCTRL over a specific database, DBADM has privileges to access any of its tables through SQL statements. Can also drop and alter any tablespace, table, or index in the database and issue a COMMENT ON, LABEL ON, or LOCK TABLE statement for any table. If the value of field DBADM CREATE VIEW on installation panel DSNTIPP was set to YES during DB2 installation, a user with DBADM authority can create a view for another user ID on any table or combination of tables and views in a database.

All privileges held by DBCTRL on a database. Privileges on tables and views in one database:

  • ALTER

  • INSERT

  • DELETE

  • SELECT

  • INDEX

  • UPDATE

  • REFERENCES

  • TRIGGER

GRANTing and REVOKEing Authorities

The authorities in Table 2-10 must be GRANTed to an authorization ID. Just as with privileges, we can do this via the GRANT and REVOKE statements. We will take a look at a couple of examples of GRANTing and REVOKEing authorities.

In order to grant DB2EXPT DBADM authority on a the DB2CERT database, the following statement must be issued:

GRANT DBADM ON DB2CERT TO DB2EXPT

In order to remove PACKADM authority from DB2EXPT, the following statement must be issued:

REVOKE PACKADM FROM DB2EXPT
WITH GRANT OPTION

If an authority is GRANTed with the WITH GRANT OPTION, the holder can GRANT the privileges contained in that authority to others. In order to grant DB2EXPT DBADM authority on a the DB2CERT database and allow DB2EXPT to give this authority to others, the following statement must be issued:

GRANT DBADM ON DB2CERT TO DB2EXPT WITH GRANT OPTION

NOTE

If the DBADM authority is ever revoked from DB2EXPT, then any ID that has been granted DBADM from this ID will also be automatically revoked.

Ownership

There are implicit privileges included with ownership of an object. When you create DB2 objects (except for plans and packages) by issuing SQL CREATE statements in which you name the object, you establish ownership. The owner implicitly holds certain privileges over it.

NOTE

The privileges inherent in the ownership of an object cannot be revoked.

Unqualified Objects

If an object name is unqualified, how ownership of the object is established depends on the type of object. Ownership of tables, views, indexes, aliases, and synonyms with unqualified names is established differently than ownership of user-defined functions, stored procedures, distinct types, and triggers with unqualified names. This section describes how ownership is established for each group of objects.

If the name of a table, view, index, alias, or synonym is unqualified, you establish the object's ownership in these ways:

  • If the CREATE statement was issued dynamicallyvia SPUFI or the Query Management Facility (QMF)the owner of the created object is the current SQL ID of the issuer. That ID must have the privileges that are needed to create the object.

  • If the CREATE statement was issued statically (via execution of a plan or package that contains it), the ownership of the created object depends on the option used for the bind operation. The plan or package can be bound with the QUALIFIER option, the OWNER option, or both.

    - With the QUALIFIER option only, the QUALIFIER is the owner of the object. The QUALIFIER option allows the binder to name a qualifier to use for all unqualified names of tables, views, indexes, aliases, or synonyms that appear in the plan or package.

    - With the OWNER option only, the OWNER is the owner of the object.

    - With both the QUALIFIER option and the OWNER option, the QUALIFIER is the owner of the object.

    - If neither option is specified, the binder of the plan or package is implicitly the object owner.

NOTE

The plan or package owner must have all required privileges on the objects designated by the qualified names.

Explicitly establish the ownership a user-defined function, stored procedure, distinct type, or trigger in the following ways:

  • If the CREATE statement is issued dynamically, the owner of the created object is the current SQL ID of the issuer. That ID must have the privileges that are needed to create the object.

  • If the CREATE statement is issued statically, by running a plan or package that contains it, the owner of the object is the plan or package owner. The OWNER bind option can be used to explicitly name the object owner. If the OWNER bind option is not used, the binder of the package or plan is implicitly the object owner.

The following section describes how the implicit qualifier is determined for a user-defined function, stored procedure, distinct type, or trigger if they are unqualified.

Qualified Objects

If an object name is qualified, how ownership of the object is established depends, again, on the type of object. For tables, views, indexes, aliases, or synonyms created with a qualified name, the qualifier becomes the owner of the object, subject to these restrictions for specifying the qualifier:

  • If you issue the CREATE statement dynamically, and have no administrative authority, the qualifier must be your primary ID or one of your secondary IDs.

  • If the CREATE statement is issued statically, and the owner of the plan or package that contains the statement has no administrative authority, the qualifier can be only the owner. However, if the owner has at least DBCTRL authority, the plan or package can use any qualifier for a table or an index, and if the owner has SYSADM or SYSCTRL authority, it can also use any qualifier for a view or alias.

NOTE

If your current SQL ID has at least DBCTRL authority, you can use any qualifier for a table or index, and if it has SYSADM or SYSCTRL authority, you can also use any qualifier for a view or alias. If the current SQL ID has at least DBCTRL authority, the qualifier ID does not need any privileges. Otherwise, the SQL ID must have any additional privileges that are needed to create the object. If the current SQL ID does not have at least DBCTRL authority, the qualifier ID must hold all the necessary privileges.

Schema Name

If you create a distinct type, user-defined function, stored procedure, or trigger with a qualified name, the qualifier will be the schema name. It identifies the schema to which the object belongs. You can think of all objects that are qualified by the same schema name as a group of related objects. Unlike other objects, however, this qualifier does not identify the owner of the object. You establish ownership of a distinct type, user-defined function, stored procedure, or trigger in these ways:

  • If the CREATE statement is issued dynamically, the owner of the created object is your current SQL ID. That ID must have the privileges that are needed to create the object.

  • If the CREATE statement is issued statically, by running a plan or package that contains it, the owner of the object is the plan or package owner. The OWNER bind option can be used to explicitly name the object owner. If the OWNER bind option is not used, the binder of the package or plan is the implicit object owner.

Privileges of Ownership by Object

Table 2-11 shows the privileges that are inherited with ownership of an object.

Table 2-11. Inherited Ownership Privileges

Object Type

Implicit Privileges of Ownership

Storage group

  • ALTER or DROP the storage group

  • Name it in the USING clause of a CREATE INDEX or CREATE TABLESPACE statement

Database

DBCTRL or DBADM authority over the database, depending on the privilege (CREATEDBC or CREATEDBA) that is used to create it

Tablespace

  • ALTER or DROP the tablespace

  • Name it in the IN clause of a CREATE TABLE statement

Table

  • ALTER or DROP the table or any indexes on it

  • Use LOCK TABLE, COMMENT ON, or LABEL on it

  • CREATE an index or view on the table

  • SELECT or UPDATE any row or column

  • INSERT or DELETE any row

  • Use the LOAD utility for the table

  • Define referential constraints on any table or set of columns

  • CREATE a trigger on the table

Index

ALTER or DROP the index

View

  • DROP, COMMENT ON, or LABEL the view, or SELECT any row or column

  • UPDATE any row or column

  • INSERT or DELETE any row (if the view is not read-only)

Synonym

USE or DROP the synonym

Package

BIND, REBIND, FREE, COPY, DROP, EXECUTE, or DROP the package

Plan

BIND, REBIND, FREE, or EXECUTE the plan

Alias

DROP the alias

Distinct type

USE or DROP a distinct type

User-defined functions

EXECUTE, ALTER, DROP, START, STOP, or DISPLAY a user-defined function

Stored procedure

EXECUTE, ALTER, DROP, START, STOP, or DISPLAY a stored procedure


026 - Summary

Chapter 2. Database Objects

Summary

In this chapter, we concentrated on the SQL Data Definition Language (DDL). DDL is used to create, modify, and remove database objects. There are three main statements in DDL: CREATE, ALTER, and DROP. If you want to use a DB2 database, you may need to learn DDL first to create some database objects. There are many kinds of objects in a DB2 database.

We focused primarily on data types, tables, views, and indexes among the database objects created by DDL. A data type is used to specify the attribute of columns in a table. DB2 has two kinds of data types: built-in data types and user-defined data types. The built-in type is a DB2-supplied data type and falls into three main categories:

  • Numeric

  • String (including large objectLOB)

  • Date-time

We also discussed that DB2 supports Unicode. The user-defined data type enables you to create your application-oriented data type based on the built-in data type.

A table consists of columns and rows, and stores an unordered set of records. Each column has a data type as one of the attributes. A table itself can have some rules called constraints to guarantee the uniqueness of records or maintain the relationship between and within tables. It helps application programmers to evaluate the records or maintain the consistency between the tables. A view may also reduce some application development workload. A logical table is created and is based on the physical table or other views. A view can be created to limit access to sensitive data while allowing more general access to other data. An index is one of the most important objects for performance. It can also be used to guarantee the uniqueness of each record. We also covered some of the options in the CREATE and ALTER statements.

Finally, we looked at what authorities and privileges are required to access DB2 objects and the DCL (Data Control Language) needed to GRANT and REVOKE these privileges.


027 - Additional Resources

Chapter 2. Database Objects

Additional Resources

IBM DB2 UDB for OS/390 SQL Reference SC26-9944-01

IBM DB2 UDB for OS/390 Administration Guide SES1-2186-01


028 -

Part 2: Structured Query Language

    Chapter 3. Basic SQL Coding

    Chapter 4. Advanced SQL Coding


029 - Chapter 3. Basic SQL Coding

Part 2. Structured Query Language

Chapter 3. Basic SQL Coding

  • Data Manipulation Language

  • Retrieving Data

  • Inserting Data

  • Updating Data

  • Deleting Data

In the previous chapter, we discussed the definitions of various database objects using the Data Definition Language (DDL). In this chapter, we start manipulating the database objects using the portion of SQL known as Data Manipulation Language (DML). We will be populating (inserting) data into the database and retrieving the data using many powerful methods. Depending on the sophistication of the database users, they can use SQL to query the database. The majority of the SQL statements within a DB2 application involve DML statements. Therefore, application developers must understand the various methods of inserting, updating, and retrieving data from the database. We will start with simple retrieval statements and gradually introduce more complex methods of data manipulation. The DB2 Certification database will be used for most of the examples. There are four main DML SQL statements we consider: SELECT, INSERT, UPDATE, and DELETE.


030 - Data Retrieval

Chapter 3. Basic SQL Coding

Data Retrieval

SQL is based on mathematical principles, specifically on set theory and relational algebra. The data is stored in the database as unordered sets of data records. SQL is a set-oriented language, and many of its language elements are directly related to relational algebraic terms, such as permutation, projection, restriction, and join.

A set of data is represented in a DB2 database as a table or a view and is stored in a DB2 table without regard to order. To retrieve data in a particular order, an ORDER BY phrase must be added to a SELECT statement. Similarly, if the data is to be grouped, then a GROUP BY phrase must be added to the statement.

Now, let's review the DB2CERT database design defined in the previous chapter and manipulate data using various SQL statements. There are three main tables: CANDIDATE, TEST, and TEST_CENTER. Each table represents a set of records that correspond to a test candidate (person), a test, and a test center (location).

There is an associative table, known as the TEST_TAKEN table, that is used to reflect the relationships among the three main tables. The TEST_TAKEN table is used to schedule the test candidates and also to maintain their test scores.

NOTE

The longest SQL statement is 32,765 bytes.

NOTE

Remember that to execute any operation, the user must have the necessary privileges.

Retrieving the Entire Table

The most basic of all retrieval command involves the SELECT statement with no operators other than the name of the table. This SQL statement retrieves all of the candidates who have taken a DB2 Certification exam. The information requested is contained in the table TEST_TAKEN.

SELECT * FROM db2cert.test_taken

SQL is a data access language that consists of language statements and clauses. There are many optional clauses that can be used to modify the output. The output of a SELECT statement is known as a result set or result table. The results from the SELECT statement are shown next. In this example, using an asterisk or star character (*) for column selection, the columns will be returned to the user in the order in which they are defined in the table.

CID TCID NUMBER DATE_TAKEN START_TIME FINISH_TIME SCORE PASS_FAIL SEAT_NO
--- ---- ------ ---------- ---------- ----------- ----- --------- -------
111 TX01 500     01/01/2000 11:30:00  12:30:00     65     Y            1
111 TX01 501     02/02/2000 10:30:00  11:45:00     73     Y            1
111 TX01 502     03/03/2000 12:30:00  13:30:00     67     Y            1
222 TR01 500     01/01/2000 14:00:00  15:30:00     55     N            2
222 TR01 502     01/02/2000 09:00:00  10:15:00     53     N            2
222 TR01 502     02/18/2000 10:00:00  11:30:00     75     Y            2
333 TX01 500     03/01/2000 11:30:00  13:00:00     82     Y            2
333 TX01 501     12/29/2000 14:00:00  -            -      -            1
333 TX01 502     03/02/2000 14:00:00  14:30:00     92     Y            1
9 record(s) selected.

In SQL, the * is used to indicate that all columns of a table are being referenced. In this example, the SQL statement refers to all of the columns defined for the DB2CERT.TEST_TAKEN table. If the table is altered and a new column is added to the table definition, the result set would contain the new column.

NOTE

Adding a new column to an existing table will result in default values being populated for the existing rows.

Since the output of the SQL statement using * character varies according to the table definition, it is recommended that you specify all of the column names you want to see in the SELECT statement. We could have obtained the same result as the statement using SELECT * with the following SQL statement.

SELECT cid, tcid, number,date_taken,start_time,
finish_time,score,seat_no
FROM db2cert.test_taken;

NOTE

The * character is used to refer to all of the columns defined for a table. The order of the columns in the result table is the same order as specified in the CREATE TABLE or CREATE VIEW statement.

What is returned to the user is known as the result set. If the result set is large it is advisable to be sure to filter the data using a WHERE predicate.

The FROM clause is required for the DML SQL statement, since it describes the location (table or view) of the data. Our example references a single table called DB2CERT.TEST_TAKEN. The SELECT and FROM clauses are required in all data retrieval statements. The list of columns following the SELECT keyword is referred to as the select list.

Projecting Columns from a Table

Projection is a relational operation that allows you to retrieve a subset of the defined columns from a table. The next example restricts the output from the SELECT command so that only the candidate ID, test center, and test number attributes from the TEST_TAKEN table are shown.

SELECT cid,tcid,number FROM db2cert.test_taken

The output of this SELECT statement is shown below.

CID TCID NUMBER
--- ---- ------
111 TX01 500
111 TX01 501
111 TX01 502
222 TR01 500
222 TR01 502
222 TR01 502
333 TX01 500
333 TX01 501
333 TX01 502
9 record(s) selected.

The order of the columns in the result table will always match the order in the select list. The order of the columns as they were defined in the CREATE TABLE or CREATE VIEW statement is ignored when a select list is provided in the SQL statement. In this example, the order of the columns is similar to the order in the CREATE TABLE statement, since the CID column was defined prior to TCID and NUMBER columns.

Changing the Order of the Columns

Permutation is the relational operation that allows you to change the order of the columns in your result table. Permutation is used every time you select columns in an order different than the order defined in the CREATE TABLE statement. For example, to display the test center ID prior to the candidate IDs and the test number, you could execute the following:

SELECT tcid,cid,number FROM db2cert.test_taken

The result of this SELECT statement specifies a select list in a different order than was defined in the table definition.

TCID CID NUMBER
---- --- ------
TX01 111 500
TX01 111 501
TX01 111 502
TR01 222 500
TR01 222 502
TR01 222 502
TX01 333 500
TX01 333 501
TX01 333 502
9 record(s) selected.

NOTE

We refer to the output of a SELECT statement as the result table because the output of all SELECT statements can be considered a relational table.

Restricting Rows from a Table

Restriction is a relational operation that will filter the resulting rows of a table. Restriction can be accomplished through the use of predicates defined in a SQL WHERE clause. To restrict the result set, we need to add a WHERE clause to the SQL statement.

NOTE

A predicate is a condition placed on the data. The result of the condition is TRUE, FALSE, or UNKNOWN.

The WHERE clause specifies conditions or predicates that must be evaluated by DB2 before the result table is returned to the end user. There are many valid types of predicates that can be used. In the following example, the equality (=) predicate is used to restrict the records to only those candidates who have taken a DB2 Certification test at the test center TR01.

SELECT tcid,cid FROM db2cert.test_taken
WHERE tcid ='TR01'

The WHERE clause also accepts other comparison operators, such as greater than (>), less than (<), greater than or equal to (>=), less than or equal to (<=), and not equal to (<>).This statement is an example of a basic predicate. A basic predicate compares two values. In addition, more complex predicates, such as LIKE, BETWEEN, and IN, are also valid and will be discussed later.

NOTE

Trying to execute this example SQL statement will result in a data type compatibility error, because the column TCID is defined with a user-defined data type (UDT).

Predicate Evaluation for UDTs

The column TCID was defined as a user-defined data type. To make the comparison in the WHERE clause valid, a casting function needs to be used.

This is not mandatory if the comparison is to a literal or host variable. This technique is however demonstrated below:

SELECT tcid, cid FROM db2cert.test_taken
WHERE tcid=CAST('TR01' AS db2cert.center_id)

Predicate evaluation requires that the data types be compatible (same data type or a compatible data type). We can accomplish the data type conversion (cast) using one of two methods:

  • Use the CAST expression.

  • Use a casting function.

Refer to Chapter 15, "Object Relational Programming," for more information on casting for UDTs.

NOTE

Although not always mandatory, casting is recommended to ensure compatible data types are compared, including length and scale. This allows DB2 to resolve these as indexable rather than stage 2 predicates.

Restricting Rows Using Multiple Conditions

It is possible to combine multiple conditions (predicates) in a single SQL statement. The predicates can be combined using Boolean operators, such as the AND or OR operators. These operators allow you to combine multiple conditions in a single SQL statement. The order of the predicate evaluation will not affect the result set (known as set closure).

The next example retrieves the records for the test candidates who took a test at test center TR01 and achieved a score greater than 65. The rows that satisfy the predicates are known as the qualifying rows. The following example is an SQL statement using multiple predicates:

SELECT tcid,cid,score
FROM db2cert.test_taken
WHERE tcid= CAST('TR01' AS db2cert.center_id)
AND score > 65

Selecting Columns from Multiple Tables

There are basically two operations that combine columns from multiple tables in a single SQL statement. These operations are

  • Cartesian product

  • Join

Cartesian Product

A Cartesian product is a relational operation that will merge all the values from one table with all the values from another table. This operation is not used frequently because the result table can be very large. The number of rows in the result table is always equal to the product of the number of rows in the qualifying rows for each of the tables being accessed.

NOTE

The DB2 optimizer may choose to utilize a Cartesian product of unrelated tables if this is deemed to be an efficient method of accessing multiple tables. An example would be two single-row tables that are joined with a large table. The cross-product of 1 x 1 = 1; thus the large table access is deferred as late as possible, with a potential increase in the restrictive predicates that can be applied without incurring the overhead of a large Cartesian result. This method of table access is typical in processing queries against a star schema data model.

The following example is a Cartesian product of all test numbers and test names from the TEST table, with all candidates from the TEST_TAKEN table. First, select from the TEST table.

SELECT number, name FROM db2cert.test

NUMBER NAME
------ --------------------------------------------------
500 DB2 Fundamentals
501 DB2 Administration
502 DB2 Application Development
3 record(s) selected.

Next select of all candidates from the test_taken table.
SELECT cid,tcid FROM db2cert.test_taken

CID TCID
--- ----
222 TR01
222 TR01
222 TR01
111 TX01
111 TX01
111 TX01
333 TX01
333 TX01
333 TX01
9 record(s) selected.

Then combine the two tables to form a Cartesian product result table.

SELECT db2cert.test_taken.number,cid,tcid
FROM db2cert.test_taken,db2cert.test

NUMBER CID TCID
------ --- ----
500 111 TX01
501 111 TX01
502 111 TX01
500 222 TR01
502 222 TR01
502 222 TR01
500 333 TX01
501 333 TX01
502 333 TX01
500 111 TX01
501 111 TX01
502 111 TX01
500 222 TR01
502 222 TR01
502 222 TR01
500 333 TX01
501 333 TX01
502 333 TX01
500 111 TX01
501 111 TX01
502 111 TX01
500 222 TR01
502 222 TR01
502 222 TR01
500 333 TX01
501 333 TX01
502 333 TX01
27 record(s) selected.

There are two tables referenced in the FROM clause of this query. The tables are separated by commas. There is no relationship expression in the WHERE clause. This type of query results in a Cartesian product.

The result table is a representation of all possible combinations of the input tables. The TEST table has three rows, and the TEST_TAKEN table has nine rows. Therefore, the SELECT statement shown above returns 27 rows. Note the first column name in this query. It is necessary to fully qualify the column name by providing the schema name and table name with the column name because this column exists in both the TEST table and TEST_TAKEN table. In this case, we needed to specify that the NUMBER column is to be retrieved from the DB2CERT.TEST_TAKEN table and not from the DB2CERT.TEST table.

By adding a predicate to a Cartesian product SQL query, the result table can represent a more useful representation of the data. In the example below, the query represents all of the tests that were taken by the candidate whose ID is 111.

SELECT db2cert.test_taken.number,cid,tcid
FROM db2cert.test_taken,db2cert.test
WHERE cid='111'

NUMBER CID TCID
------ --- ----
500 111 TX01
500 111 TX01
500 111 TX01
501 111 TX01
501 111 TX01
501 111 TX01
502 111 TX01
502 111 TX01
502 111 TX01
9 record(s) selected.

Adding a WHERE clause to your query does not always provide the desired result. In the example shown above, you want to know all of the tests that were taken by the candidate whose ID is 111, and the query returns nine rows. But we know from previous queries that the candidate took only three tests. The query in the example above has a WHERE clause to filter out the candidate whose ID is 111 from the TEST_TAKEN table, but there was no filter on the TEST_CENTER table. Therefore, the result of the query would always be a multiple of the number of testing centers. Usually, when multiple tables are referenced, you should include a cross-table relationship using a table merge or join method, as shown in the following example. We will examine table join methods further in the next section.

SELECT db2cert.test_taken.number,cid,tcid
FROM db2cert.test_taken,db2cert.test
WHERE cid= '111'
AND db2cert.test_taken.number=db2cert.test.number

NUMBER CID TCID
------ --- ----
500 111 TX01
501 111 TX01
502 111 TX01
3 record(s) selected.

To avoid data redundancy, it is recommended that the database tables be normalized. Following a normalization process, a number of related tables will exist. To satisfy some of the required queries, the tables must be reconstructed. The tables are reconstructed temporarily, using a table join strategy to produce a single-result table.

The result tables in the previous examples usually provided candidate ID numbers and not the complete name of the test candidates. The candidate IDs are stored in the TEST_TAKEN table, and the full names are stored in the CANDIDATE table. To obtain the name of a candidate, the data must be retrieved from the CANDIDATE table, using a relationship or join strategy.

Consider an example that will list the names and phone numbers of candidates who were registered to take a DB2 Certification test in 2000. To accomplish this, we need to select data from two different tables:

  • db2cert.candidate

  • db2cert.test_taken

Let's retrieve a list of candidate names, phone numbers, and IDs from the CANDIDATE table. The candidate names were stored in multiple columns to allow for easy retrieval by last name.

SELECT fname,initial,lname,hphone,cid
FROM db2cert.candidate

The output of this example follows. Pay special attention to the values in the CID column. It will be used as the join column in the next example.

FNAME     INITIAL    LNAME       HPHONE      CID
--------  -------    ----------  ----------  ---
Bill      B          Wong        1115551234  111
George               Baklarz     2226543455  222
Susan     M          Visser      4442314244  333
Glen      R          Sheffield   5552143244  444
Jim       G          Stittle     6662341234  555
Kevin     W          Street      7773142134  666
Bert      F          Nicol       8886534534  777
Paul      C          Zikopoulos  9992112212  888
8 record(s) selected.

Now, let's retrieve the ID numbers of those candidates who were registered to take the test in 2000.

SELECT distinct cid FROM db2cert.test_taken
WHERE YEAR(date_taken) = 2000

CID
---
222
111
333
3 record(s) selected.

The candidate IDs in the TEST_TAKEN table must correspond to a candidate ID in the CANDIDATE table because of the declarative referential integrity constraints. The parent table in the relationship is the CANDIDATE table and the child table (dependent table) is the TEST_TAKEN table.

The result table from the above query does not include the test candidate 444, since that candidate did not have a test scheduled for 2000. We need to join the two result tables based on the candidate ID values. This column is known as the join column.

NOTE

Query performance can significantly improve if the join columns are appropriately indexed.

The following single query will satisfy the end-user requirement.

SELECT distinct fname,initial,lname,hphone
FROM db2cert.test_taken,db2cert.candidate
WHERE YEAR(date_taken) = 2000
AND db2cert.test_taken.cid=db2cert.candidate.cid

A table join requires a predicate that includes an expression based on columns from the tables referenced in the FROM clause. This is known as a join predicate. The FROM clause has not changed from the Cartesian product examples. The only difference is in the join predicate (test_taken.cid = candidate.cid).

NOTE

An alternative form of the FROM clause for joins involves explicitly coding the JOIN keyword between the tables (rather than using a comma) and coding the join predicates in the ON clause rather than in the WHERE clause. This method of coding will be covered in more detail in Chapter 4, "Advanced SQL Coding."

The table names needed to be explicitly stated because there is a column named CID in both of the referenced tables. When multiple tables are being accessed in a single query, any selected columns that occur in more than one table must be qualified with the table name.

NOTE

An error will occur if the columns being referenced are ambiguous (not properly qualified).

The maximum number of base tables that can be in a single SQL statement is 225; however, you are limited to 15 tables in a join (the FROM clause).

NOTE

The 15-table limit can be increased by updating the macro SPRMMXT to a value greater than 15.

NOTE

This kind of join operation shown in the above example is also known as an inner join. An inner join displays only the rows that are present in both of the joined tables.

Using Correlation Names

If each of the columns needed to be fully qualified with the table name, such as tableschema.tablename.columnname, the queries would become very large and cumbersome to work with. Fortunately, there is an easier way to qualify the ambiguous columns resulting from a multitable SELECT statement.

The columns can be qualified using a correlation name. A correlation name is a temporary alias for the tables referenced in an SQL statement. We rewrite the previous query using correlated names as follows:

SELECT distinct fname,initial,lname,hphone
FROM db2cert.test_taken tt, db2cert.candidate c
WHERE YEAR(date_taken) = 2000
AND tt.cid = c.cid

The correlation name immediately follows the name of the table as stated in the FROM clause. In this example, the correlated name for the TEST_TAKEN table is tt, and the correlated name for the CANDIDATE table is c.

NOTE

Correlation names can be optionally prefixed with the AS keyword, such as DB2CERT.CANDITATE AS C. This is purely for readability.

The correlated names are accessible within the SQL statement only. Following the execution of the SQL statement, the correlation name is no longer defined. Once a correlation name has been defined, it can be referenced in the rest of the query instead of the table name. However, the table name can still be referenced.

NOTE

Use simple, easy-to-remember correlation names. Table initials are good candidates for correlation names.

Sorting Your Output

We have been retrieving data from one or more tables. The order of the result table has not been specified in any of the SQL statements. Therefore, the data is retrieved in an undetermined order if there is no ORDER BY clause in the SQL statement.

NOTE

The only guaranteed way to return data in the required sequence is with the ORDER BY clause. Any data retrieval that is currently returned in sequence without this clause is purely based upon the data retrieval method at the time. A future access path change may not return the data in the same sequence.

The following example produces a list of the test candidates in alphabetical order by last name for the candidates who have taken a DB2 Certification test at the TR01 test center.

SELECT lname,initial,fname
FROM db2cert.candidate c,db2cert.test_taken tt
WHERE c.cid=tt.cid
AND tcid='TR01'
ORDER BY lname

This example contains a new clause, ORDER BY. After the ORDER BY clause, you can list the columns that will specify the sort order and the type of sort.

NOTE

Appropriate indexing may allow DB2 to avoid sorting the data to match the ORDER BY clause. If the data is already sequenced via the index, DB2 may choose to utilize the index and avoid sorting the data. DB2 cannot avoid a sort for an ORDER BY involving columns from more than one table. Where possible, include columns from only one table in the ORDER BY to give DB2 greater opportunity for sort avoidance.

The SQL can be modified so that the output is changed to descending order by last name and a secondary order column on the first name in ascending order.

SELECT lname,fname,hphone
FROM db2cert.candidate c,db2cert.test_taken tt
WHERE c.cid=tt.cid
AND tcid= 'TR01'
ORDER BY lname DESC, fname

In this example, the DESC keyword that follows the lname column indicates that the result table should be in descending order based on the last name. More than one record can have the same last name. This situation is quite common. There is a second column specified in the ORDER BY clause, fname.

There is no keyword specifying the sort sequence based on the fname column. Therefore, the default ordering sequence (ascending) is used.

The next example contains three columns lname, fname, and hphone. You can reference the column that should be used to sort the data using the column name or by specifying its position in the select list. Using the column position is useful when the column in the select list is made up of derived columns (calculated columns) that have no explicit name.

SELECT lname,fname,hphone
FROM db2cert.candidate c,db2cert.test_taken tt
WHERE c.cid=tt.cid
AND tcid='TR01'
ORDER BY 1 DESC, 2

In this example, the sort order is specified using the column position. Therefore, the query result is exactly the same as the in previous example.

You can also assign an alternative column name using column renaming. The assigned name can then be referenced in the ORDER BY clause, and it appears as the column heading where appropriate.

NOTE

Although useful, coding a column position rather than a column (or renamed column) in the ORDER BY clause may lead to a different sequence if another column is inadvertently added to the query that alters the column positioning.

NOTE

The ORDER BY clause must succeed all subselects in the FULLSELECT statement. The only clauses that can succeed the ORDER BY clause are the for FOR FETCH ONLY, FOR READ ONLY, OPTIMIZE, WITH QUERYNO, FETCH FIRST n ROWS clauses.

Derived Columns

There are some cases when you will need to perform calculations on the data. The SQL language has some basic mathematical and string functions built in. Mathematical operations include standard addition, subtraction, multiplication, and division.

The calculation can be defined in the WHERE clause of the SQL statement or the select list. Suppose that you need to calculate a passing rate for a DB2 test. The passing rate is defined as the percentage of candidates that pass the test (totalpassed*100/totaltaken). The following SQL statement will accomplish this for us for test number 500:

SELECT number, totalpassed*100/totaltaken
FROM test
WHERE number='500'

In this example, the second column of the output list is a calculated column. Remember that you must use the column position if you want to use this calculated column for the ORDER BY clause unless you name it (as we now discuss).

NOTE

Occasionally, the results of a derived column may not display as expected. The example using totalpassed*100/totaltaken will result in a value of 66 being retrieved. Since both the totalpassed and totaltaken columns are integers, the final result is also an integer, and the fractional part is discarded. If this is not your desired result, you should use other functions (like decimal) to change the way the calculation is performed or displayed.

Naming Derived/Calculated Columns

You can specify a column name for any expression. When you provide the derived (calculated) column with a name, the ORDER BY clause can reference the derived name to allow for a more readable SQL statement.

The following SQL calculates the percentage of people that have passed the DB2 Certification exams and orders the output in descending order of the passing rate.

SELECT number,totalpassed*100/totaltaken AS PassedRate
FROM test
ORDER BY PassedRate DESC

The AS clause is used to rename the default name of an element in the select list. In this example, we are giving the name of PassedRate to the result of the division of columns totalpassed by totaltaken. The named column is used in the query to specify the column that should be used for sorting the output.

NOTE

The AS keyword is optional, although it should be added for readability. Without the AS clause, it may be unclear whether the intention was to rename a column or a comma was missed between two retrieved columns.

Functions

In DB2, there are different types of functions provided. For example, two types of functions provided by DB2 are scalar and column functions (a third type of function called a table function is discussed in Chapter 15, "Object Relational Programming."

  • Scalar functions (also known as row functions) provide a result for each row of the result table. A scalar function can be used any place an expression is allowed.

  • Column functions (also known as vector functions) work with a group of rows to provide a result. The group is specified using a FULLSELECT and optionally grouped using the GROUP BY clause.

In this section, we introduce you to some of the SQL functions provided with DB2. SQL functions are categorized by their implementation type. Either the functions are built in or they are extensions of DB2 and are known as user-defined functions (UDFs).

  • Built-in functions are defined within the SQL standards, and they are provided by DB2. These can be either scalar or column functions.

  • UDFs are not defined within the SQL standards because they are extensions of the current SQL language. These functions can be developed by a DB2 administrator or application developer. UDFs can be either scalar or table functions, but not column functions. Once the UDFs have been created, they can be invoked by any end user with the proper privileges. For more information about UDFs, refer to Chapter 15.

Scalar Functions

Scalar functions are applied to each row of data, and there is a per-row result provided. If we want to retrieve only the first three digits of telephone numbers for each candidate, we could use a scalar function. The function that is used is called SUBSTR. The arguments for this function include a string data type column, a beginning offset, and length. The output data type and attribute of the function depend on the input data type and attribute. The following example retrieves the telephone area code for the column wphone.

SELECT lname, SUBSTR(CHAR(wphone),1,3)
FROM db2cert.candidate

The SUBSTR function is a scalar function. In this example, SUBSTR returns a character string of three characters. The result string corresponds to the first three characters of the wphone column. This function is known as a string function because it works with any string data type. If we wanted to provide the output column with a meaningful name, we could provide an alias, as was done for calculated columns.

In the example above, the substring starts from the beginning of the string, because we indicate one (1) as the second parameter of the function. The length of the resulting string is indicated in the third argument. In our example, the length is three. Note that the data type of the wphone column is phone, so a casting function is used to convert the phone data type to the char data type.

The following query will provide the month when the exam was taken. The input for this function is a DATE string, and the output is an integer.

SELECT fname, MONTH (date_taken)
FROM candidate c, test_taken tt
WHERE c.cid=tt.cid
Column Functions

Column functions provide a single result for a group of qualifying rows for a specified table or view. Many common queries can be satisfied using column functions where they include common tasks, such as finding the smallest value, the largest value, or the average value for a group of data records. In the following example you can obtain the maximum length of time of any of the DB2 Certification exams:

SELECT MAX("length") FROM test

Because the length column shares its name with the length scalar function, the column name is encased within double-quotes to distinguish this as a column and not a function.

If we added a WHERE clause to this example, the maximum would represent the maximum length for the qualifying rows, since the predicate is used to filter the data prior to the application of the MAX function.

This next example calculates the average of the number of seats for all of the test centers. Notice the column function AVG is used in this example:

SELECT AVG(noseats) FROM test_center

DB2 provides many more built-in functions. If you are interested in calculating statistical information, you can use statistical functions, such as VARIANCE, STDDEV, or a sampling of these functions.

NOTE

MAX and MIN functions can be either column or scalar functions depending on the input arguments.

Grouping Values

Many queries require some level of aggregated data. This is accomplished in SQL through the use of the GROUP BY clause. The following SQL obtains the average number of seats for each country:

SELECT country, AVG(noseats) FROM test_center
GROUP BY country

This SQL statement obtains the average number of seats per country, and the GROUP BY clause tells DB2 to group together the rows that have the same values in the columns indicated in the GROUP BY list. In our example, we are grouping countries into subsets. As the subsets are created, DB2 calculates the average of each of those groups or subsets, in this case, by each country.

When you combine column functions and other elements, such as column names, scalar functions, or calculated columns, you must use the GROUP BY clause. In this case, you must include every element that is not a column function in the GROUP BY list. The only elements that can be omitted in the GROUP BY list are constant values.

The next SQL statement obtains a list that includes the average cut score and minimum test length for the DB2 Certification exams. We group this list by the type of exam, as follows:

SELECT type, AVG(cut_score),
MIN("length")
FROM test
GROUP BY type

NOTE

Appropriate indexing can allow DB2 to avoid a sort to group the data rows to match the GROUP BY clause.

It is possible to sort the output of the previous example using an ORDER BY clause.

NOTE

GROUP BY may return data in the same order as an ORDER BY, but this is not guaranteed and is based upon the access path. The only method to guarantee data sequence is with an ORDER BY.

Restricting the Use of Sets of Data

Up to now, we have discussed how to restrict output based on row conditions. With SQL, it is also possible to restrict that output using column functions and the GROUP BY clause. Suppose you want a list of all the test centers that have administered more than five DB2 Certification exams. To make it easier to understand, let's first get the number of tests that have been taken in each test center.

SELECT tcid, count(*) FROM test_taken GROUP BY tcid

We use the COUNT column function to get the total number of tests that have been taken in each test center. When you use an asterisk (*) with the COUNT function, you are indicating that you want the number of rows in a table that meet the criteria established in the SQL statement. In this example, we are grouping by TCID because we have a number of occurrences for all the test centers in the TEST_TAKEN table. The TEST_TAKEN table has an entry for every DB2 Certification exam that has been taken. Finally, the output is restricted to only those test centers that have administered more than four exams.

SELECT tcid FROM test_taken
GROUP BY tcid HAVING COUNT(*) > 4

This example introduces the HAVING clause. The HAVING clause is equivalent to the WHERE clause for groups and column functions. The HAVING clause will restrict the result set to only the groups that meet the condition specified in it. In our example, only the test centers that have administered more than four DB2 Certification exams will be displayed.

Eliminating Duplicates

When you execute a query, you might get duplicate rows in the answer set. The SQL language provides a special clause to remove the duplicate rows from your output. The following SQL generates a list of names and phone numbers for all the candidates who have taken a test. In the following example, we eliminate the duplicate rows from our output list using the DISTINCT clause.

SELECT DISTINCT fname,wphone,hphone
FROM candidate c,test_taken tt
WHERE c.cid=tt.cid

The DISTINCT clause can also be used with the COUNT function. When you use DISTINCT inside a COUNT function, it will not count the duplicate entries for a particular column. The following example allows you to count how many different test centers have candidates registered.

SELECT COUNT(DISTINCT tcid) FROM test_taken

This example provides the number of test centers that are registered in the TEST_TAKEN table. Remember that all the candidates who have registered for DB2 Certification exams are stored in this table. Make sure that you understand the difference between COUNT(*), COUNT(colname), and COUNT(DISTINCT colname). They are very similar in syntax but differ in function.

NOTE

COUNT(*) returns a count of all rows that qualify against the WHERE clause. COUNT(colname) returns a count of all rows that qualify against the WHERE clause, with null occurrences of colname removed. COUNT(DISTINCT colname) counts distinct occurrences of colname, with nulls removed.

Searching for String Patterns

SQL has a powerful predicate that allows you to search for patterns in character string columns. This is the LIKE predicate. Suppose you want to generate a list of the candidates whose first name starts with the letter G.

SELECT fname,lname,wphone,hphone FROM candidate
WHERE fname LIKE 'G%' ORDER BY lname,fname

In this query, we use a wildcard character with the LIKE predicate. In SQL, the percent character (%) is a substitute for zero or more characters. The search string G% can be substituted with names like George, Gary, Ginger, and so on (since the percent character can substitute zero or more characters, the search string can also be a single letter G).

The percent character can be used any place in the search string. It also can be used as many times as you need it. The percent sign is not case-sensitive, so it can take the place of uppercase or lowercase letters. However, the constant characters included in your search string are case-sensitive.

Another wildcard character used with the LIKE predicate is the underline character (_). This character substitutes one and only one character. The underline character can take the place of any character. However, the underline character cannot be substituted for an empty character.

NOTE

If the pattern needs to search for occurrences of the wildcard characters % and _ as their actual values, then the ESCAPE clause is used to specify a character that precedes the percent or underscore in the pattern.

The previous SQL can be modified to include all candidates' names and the telephone numbers for those candidates whose name has a lowercase letter "a" as its second letter.

SELECT fname,lname,wphone,hphone FROM candidate
WHERE fname LIKE '_a%' ORDER BY lname,fname

This example uses two wildcard characters that work with the LIKE predicate. The search string in this example can include names, such as Paul, Gabriel, or Natalie. (The first character may be any character, the lowercase letter "a" is the second character in the string, and the string ends with any number of characters.)

NOTE

When the pattern in a LIKE predicate is a fixed-length host variable, the correct length must be specified for the string to be returned. 'G%' assigned to an 8-byte variable (LIKE :variable) will search for all occurrences of 'G% ' (G, followed by any character, followed by 6 blank characters). To find rows that begin with a G, then 'G%%%%%%%' should be assigned to the fixed-length variable.

Searching for Data in Ranges

SQL also offers us a range operator. This operator is used to restrict rows that are in a particular range of values. Consider the requirement to list those candidates whose scores in the DB2 Certification exam are between 60 and 75.

SELECT DISTINCT fname,lname,wphone,hphone
FROM candidate c, test_taken tt
WHERE c.cid=tt.cid
AND score BETWEEN 60 AND 75

The BETWEEN predicate includes the values that you specify for searching your data. An important fact about the BETWEEN predicate is that it can work with character ranges as well.

In addition to the score requirement, this example modifies the SQL to include only those candidates whose last name begins with a letter between B and G.

SELECT DISTINCT fname,lname,wphone,hphone
FROM candidate c, test_taken tt
WHERE c.cid=tt.cid
AND score BETWEEN 60 AND 75
AND lname BETWEEN 'B' AND 'GZ'

In this example, the second BETWEEN predicate contains character values. We need to specify the GZ value to include all the possible names that start with the letter G. This was done assuming that the letter Z is the last possible value in the alphabet.

NOTE

The arguments of the BETWEEN clause are not interchangeable; the first must specify the low value, and the second, the high value. BETWEEN 1 AND 2 will return all values within the range (inclusive of 1 and 2). BETWEEN 2 AND 1 will return zero rows.

Searching for Null Values

Null values represent an unknown value for a particular occurrence of an entity. We can use a null value in the cases where we don't know a particular value of a column. Let's say that we want a list of all those candidates whose score is not yet input. This condition is represented with a null value.

SELECT fname,lname,wphone,hphone
FROM candidate c, test_taken tt
WHERE c.cid=tt.cid AND score IS NULL

The IS predicate is used to search for the null value in this example. Remember that the null value means "unknown." Because it has no particular value, it can't be compared with other values. You can't use conditional operands, such as equal (=) or greater than (>), with null values.

Searching for Negative Conditions

The BETWEEN, IS, and LIKE predicates always look for the values that meet a particular condition. These predicates can also be used to look for values that don't meet a particular criterion.

The NOT predicate can be used to look for the opposite condition, combined with the LIKE, BETWEEN, and IS predicate, to accomplish negative searches, as shown in the following example. This example has a LIKE predicate combined with the NOT predicate. We want a list of those candidates whose last names do not start with the letter S.

SELECT DISTINCT fname,lname,wphone,hphone FROM candidate
WHERE lname NOT LIKE 'S%'
ORDER BY lname,fname

The next example has a BETWEEN predicate combined with the NOT predicate. We want the list of those candidates whose score, in any test, is not in the range 60 to 75.

SELECT DISTINCT fname,lname,wphone,hphone
FROM candidate c, test_taken tt
WHERE c.cid=tt.cid
AND integer(score) NOT BETWEEN 60 and 75

In this example, the NOT predicate will exclude all the values that are in the range 60 to 75.

Negation can also be applied to the null value. This SQL produces a report that searches for those candidates that have a seat number assigned. This is expressed with a NOT NULL value.

SELECT DISTINCT fname,lname,wphone,hphone
FROM candidate c, test_taken tt
WHERE c.cid=tt.cid AND seat_no IS NOT NULL

NOTE

The NOT operator can also be used to negate the standard comparison operators, =, <, <=, >, and >=.

NOTE

When dealing with nulls, NOT or negation may not return the opposite of the positive logic. For example, WHERE SEAT_NO = 1 will return only the rows for seat number 1. Any value other than 1 is discarded, as these rows are FALSE, including nulls, since these are unknown. WHERE SEAT_NO <> 1 excludes rows where the seat number is 1, and also discards nulls because these are unknown.

Searching for a Set of Values

In SQL, it is possible to establish a restriction condition based on a set of values. Suppose that you need a list of the test centers that have candidates registered for the DB2 Fundamentals test and for the DB2 Application Development test. This can be queried with the following statement:

SELECT DISTINCT name,phone
FROM test_center tc, test_taken tt
WHERE tc.tcid=tt.tcid
AND (number = '500' or number ='502')

To simplify building multiple OR conditions when multiple values for the same column are being compared, it is possible to rewrite the statement using the IN clause.

SELECT DISTINCT name,phone
FROM test_center tc, test_taken tt
WHERE tc.tcid=tt.tcid
AND number IN ('500','502')

The IN clause is used to denote a set of values. In this example, we use a constant set of values.

You can also use the NOT predicate with the IN clause. In this case, the condition will be true when a value is not present in the set of values provided to the IN clause. You can use as many values as you wish in the IN clause, within the defined limits of the size of a SQL statement.

Advanced Selection Functionality

In Chapter 4, "Advanced SQL Coding," we will look at more of the functionality and power of the SELECT statement. We will cover topics such as

  • Subqueries

  • Inner and outer joins

  • Nested table expressions

  • CASE expressions

  • Row expressions

  • Unions


031 - Data Modification

Chapter 3. Basic SQL Coding

Data Modification

Up to now, we have discussed basic SELECT statements. The SELECT statement allows you to retrieve data from your database tables and assumes that data has been previously loaded into the tables. Now we will concentrate on manipulating data in tables using SQL. There are three main statements that can be used to add and change data stored in a DB2 database table. They are the INSERT, DELETE, and UPDATE SQL statements.

To perform these operations, you must have the required privileges on the tables being accessed. Usually, these privileges are more strictly enforced, since they can allow the end user to modify data records.

Inserting Data Records

To initially populate a DB2 table with data, the INSERT statement can be used to store one data record at a time. The statement can be targeted to insert data directly into a base table, or a view can be used instead. If a view is being used as the target, remember that it is the base table where the actual data is being stored.

Every row that is populated using the INSERT statement must adhere to table-check constraints, data type validation, dynamic (trigger) constraints, and referential integrity constraints. An SQL error will occur if any of these conditions are violated during the processing of the INSERT statement.

NOTE

Remember that you must have the necessary view or table privileges to perform an INSERT statement.

The first example is a simple INSERT statement. This statement will insert the data for the DB2 Data Propagation (#508) exam into the TEST table.

INSERT INTO db2cert.test
(number,name,type,cut_score,length,
totaltaken,totalpassed) VALUES
('508','DB2 Data Propagation','P',NULL,90,0,0);

In this example, we specify all the column names and their corresponding values for this data record. Following the VALUES portion of the statement, we include all of the data values for this record.

In the VALUES clause, the number and order of the inserted elements must match the number and order of the column names defined in the INSERT statement. However, the order of the columns doesn't have to match the order in which they are defined in the table. For those columns that don't require a value, you can indicate null or default values. In this example, we use the null value for the cut_score column.

NOTE

The number of elements following the VALUES clause must match the number of names in the insert column list.

Depending on your column definition, the DEFAULT value can cause the insertion of a system-defined default, a user-defined default, or null. Be aware that if the column doesn't accept nulls (NOT NULL) and wasn't defined as WITH DEFAULT, you will receive an error message when using the DEFAULT value. This error is because the default value for those columns not using the WITH DEFAULT option is the null value.

When you want to insert values into all the columns of a table, you do not have to provide the column names in the INSERT statement. This example is shown next.

INSERT INTO db2cert.test VALUES
('508','DB2 Data Propagation','P',DEFAULT,90,79,11)

This method will work only if you specify a value for all the columns in a table. If you miss one of the columns of the table, DB2 will not allow you to insert the row into the table. The DEFAULT keyword used in this example will insert the default value for the cut_score column.

NOTE

Remember that depending on the column definition, the default value could be a user-defined default value, a system-defined default value, or null.

Inserting Data into Specific Columns

There are times when you need to add data to specific columns. Every column that is not included in the INSERT statement will receive its default value.

This operation can be accomplished only if the omitted columns accept nulls or have a default value definition. This means that you must specify a value for the columns defined as NOT NULL. This restriction excludes columns defined as NOT NULL WITH DEFAULT.

Let's insert a row into the TEST_TAKEN table. In the following example, we will insert data only for the columns CID, TCID, NUMBER, and SEAT_NO.

INSERT INTO db2cert.test_taken
(CID,TCID,NUMBER,SEAT_NO)
VALUES('888','TR01','508','1')

Remember that columns defined using WITH DEFAULT that are not listed in the INSERT statement will receive the null value or a default value.

NOTE

The TEST_TAKEN table has some referential integrity with other tables. If you want to insert a record into a TEST_TAKEN table, the appropriate values should be inserted into the other three tables in advance.

Inserting a Set of Values

Using SQL, you can insert the result of a SELECT statement into a different table. The SQL statement that generates the resulting set must follow these rules:

  • The number of columns from the SELECT statement must equal the number of columns in the INSERT column list.

  • The data type of each of the columns in the SELECT list must be compatible with the data type of those columns in the INSERT list.

  • Column names can be omitted from the INSERT list only if values are inserted into all the columns in the table.

  • Only columns defined to allow null or defined as NOT NULL WITH DEFAULT can be omitted from the INSERT list.

In some situations, it might be useful to create tables that are duplicates of others so that you can do multiple calculations against them. The next example uses a table called TEST_PASSED, which is a copy of the TEST_TAKEN table. This new table will be used to extract the information about those candidates who have passed any of the DB2 Certification exams.

INSERT INTO db2cert.test_passed
(cid,tcid,number,
date_taken,start_time,finish_time,
pass_fail,score,seat_no)
(SELECT cid,tcid,number,
date_taken,start_time,finish_time,
pass_fail,score,seat_no
FROM db2cert.test_taken
WHERE pass_fail='P')

The select list used in the fullselect in the above example can also be substituted by a select asterisk (*). This is possible because the TEST_PASSED table has the same column structure as the TEST_TAKEN table. However, to keep this query isolated from future table modifications, it is recommended that you use the select list instead of the asterisk.

When you use a SELECT statement to insert data into a table, you must enclose it between parentheses. You can also use a table expression to insert values into a table or view using the INSERT clause.

Inserting Large Amounts of Data

Using the SELECT or VALUES statements to insert data into a table can be very useful. However, it is not recommended to load large amounts of data into a table using the INSERT statement as the transaction logging overhead can become unmanageable.

DB2 provides you with the LOAD utility, which is designed to move large amounts of data into a table.

Updating Data Records

So far we have looked at the INSERT statement as a method of moving data into your DB2 table. You may wish to update only a column with values for a group of data records. There is an SQL UPDATE statement that can be used to specify the column and its new values. A table or a view can be referenced as the target for the UPDATE statement.

NOTE

Remember that you must have the correct privileges in order to perform the UPDATE operation.

The UPDATE statement can be used in two forms:

  • Searched update. This type of UPDATE statement is used to update one or more rows in a table. It requires a WHERE clause to establish the update condition (which rows are to be updated).

  • Positioned update. This kind of UPDATE statement is always embedded into a program. It uses cursors to update the row where the cursor is positioned. As the cursor is repositioned using the FETCH statement, the target row for the UPDATE statement changes.

We focus on searched updates in this chapter. Similar to the INSERT statement, all of the database constraint mechanisms are enforced during an UPDATE statement. There can be specific update constraint triggers and referential integrity (RI) constraints that could be different from the insert constraints. For example, the following is a transaction that updates candidate ID 888's exam day for the DB2 Fundamentals certification exam.

UPDATE db2cert.test_taken
SET date_taken=date_taken + 3 days
WHERE char(cid) ='888'
AND number='500'

In this example, we use an operation known as a labeled duration to add three days to the original date.

It is very important that you provide the proper WHERE clause to avoid updating unintended data records. In this example, we needed to specify the predicate number='500' to avoid changing the date for any of the other tests that the candidate can be scheduled for.

NOTE

DB2 labeled durations for date-time data types include years, months, days, hours, minutes, seconds, and microseconds.

The UPDATE statement can also be used with fullselects. In this case, the fullselect must return a row with exactly the same number of columns and compatible data types of the row that will be updated. Observe that this fullselect must return only one row.

Let's update a row using a SELECT statement to set the new value. Candidate ID 888 decides to take the DB2 Fundamentals test today in the test center located in Toronto, Canada.

UPDATE db2cert.test_taken
SET (date_taken,tcid)=
(SELECT current date,tcid FROM db2cert.test_center
WHERE substr(city,1,7)='Toronto'
AND country='Canada')
WHERE cid= '888' AND number='500';

In the above example, we update two different columns in the same operation. These columns are indicated in the parentheses following the SET clause.

After indicating which columns are going to be updated, we use a SELECT statement to retrieve the current date (today) and the test center ID for the test center located in Toronto, Canada. Notice the last WHERE clause in the statement will restrict the rows that will be updated.

NOTE

If you forget the update WHERE clause in a searched update, all of the data in your table will be updated.

The SQL statement that will update the DATE_TAKEN and TCID columns is known as a row fullselect. This name is given because it returns only one row. Observe that the scalar fullselect can be considered a special case of a row fullselect.

NOTE

CURRENT DATE is a DB2 special register that gives the system date. Some others include CURRENT TIME, CURRENT TIMESTAMP, CURRENT PACKAGESET, and USER (the authid).

Updating Large Amounts of Data

There are times when you need to update a large number of rows of a particular table. This can be accomplished by issuing a searched update. However, this also could allocate a large amount of transactional log space. You can accomplish updates using positioned updates, where you can easily control the commit frequency.

Removing Data

There are many methods available to remove data from a DB2 database. To remove all of the data within a database, perform the DROP DATABASE command. This may remove more data than you intended because the entire database, including its configuration, will be physically removed.

It is also possible to remove data using the DROP TABLESPACE or DROP TABLE statements. These statements are usually only issued by the SYSADM or DBADM, since they will remove large amounts of data. If you wish to remove all of the data records from a table, it is easier and quicker to perform the DROP TABLE statement. Even easier, and less destructive, is using the LOAD utility with the REPLACE option specifying an empty input file.

NOTE

A mass delete from a segmented tablespace limits logging and improves performance by merely updating the space map pages to indicate the deletion rather than deleting each data row.

If the table is dropped, it must be re-created before any data can be populated again in the table.

To remove a single data record or a group or records from a table, the DELETE statement should be used. The syntax of the DELETE statement is different from the SELECT and INSERT statements, because individual columns cannot be deletedonly rows can be deleted.

The DELETE statement can also be used with views. However, there are restrictions on the type of views that can be used within a DELETE statement.

NOTE

Remember that you must have the necessary privileges over a table to perform the DELETE operation.

In general, there are two kinds of DELETE statements:

  • Searched delete. This DELETE statement is used to delete one or multiple rows from a table. It can use a WHERE clause to establish the delete condition.

  • Positioned delete. This DELETE operation is always embedded into a program. It uses cursors to delete the row where the cursor is positioned.

In this section we focus on the searched delete. The following SQL statement deletes candidates who don't have a telephone number loaded into the table. We use a searched delete to accomplish this task.

DELETE FROM db2cert.candidate
WHERE hphone IS NULL
AND wphone IS NULL

This example uses a WHERE clause to delete the data that meets a specific criterion. To verify the result of the DELETE statement, you can issue a SELECT statement with the same WHERE clause. If the DELETE was successful, the SELECT will return an empty set.

A delete can also become more sophisticated by using subselects. The next SQL statement deletes all the candidates who took the DB2 Certification exams in February of any given year.

DELETE FROM db2cert.candidate
WHERE cid IN (SELECT cid FROM db2cert.test_taken
WHERE MONTH(date_taken)=2)

In this example, we use a subselect to retrieve the CID values of the candidates who took a DB2 Certification exam in the month of February. This list will be used to search for the candidates we want to delete.

Deleting All the Rows in a Table

You can delete all the rows in a table if you don't specify a search condition in your DELETE statement. You must be aware of the implications of this type of statement.

However, this is not the only way to delete all the rows in a table. You can also delete all the rows in a table if all the rows meet the search condition.

Deleting all the rows in a table by using a DELETE statement may not be the most efficient method. This kind of statement can consume a lot of log space when your tables are large.

View Classification

Now that we have examined various SQL DML statements, let's take a closer look at views. We have already discussed creating views. Now we'll examine the different types of views. Views are classified by the operations they allow, but are generally referred to as either read-only or non-read-only (updateable) views. The referential and check constraints are treated independently. They do not affect the view classification.

For example, you may not be able to insert a value into a table because of a referential constraint. If you create a view using that table, you also can't insert that value using the view. However, if the view satisfies the rules for a non-read-only view, it will still be considered an insertable, updateable, or deleteable view. This is because the insert restriction is located on the base table, not on the view definition.

Read-only Views

Depending on how a view is defined, a view can be read-only or can be the object of an INSERT, UPDATE, or DELETE. A view is read-only if one of the following statements is true of its definition:

  • The first FROM clause identifies more than one table or view, or identifies a table function.

  • The first SELECT specifies the keyword DISTINCT.

  • The outer fullselect contains a GROUP BY clause.

  • The outer fullselect contains a HAVING clause.

  • The first SELECT clause contains a column function.

  • It contains a subquery such that the base object of the outer fullselect and of the subquery is the same table.

  • The first FROM clause identifies a read-only view.

A read-only view cannot be the object of an INSERT, UPDATE, or DELETE statement. A view that includes GROUP BY or HAVING cannot be referred to in a subquery of a base predicate. The following is an example of a read-only view:

CREATE VIEW read_only_view
(name,work_phone,home_phone)
AS
SELECT DISTINCT fname,wphone,hphone
FROM db2cert.candidate c, db2cert.test_taken tt
WHERE c.cid=tt.cid

The view above is a read-only view as it uses the DISTINCT clause and the SQL statement involves more than one table.

Non-Read-only Views

A view must meet the rules listed above to be considered a non-read-only view. Below is an example of a view that can be used for a DELETE statement.

CREATE VIEW deletable_view
(tcid,cid,number,date_taken,start_time,seat_no,score)
AS
SELECT tcid,cid,number,date_taken,
start_time,seat_no,score
FROM db2cert.test_taken
WHERE tcid='TR01'

A view that can be the object of an UPDATE statement is a special case of a non-read-only view, as at least one of its columns must be updateable. A column of a view can be updated when all of the following rules are true:

  • The view is not a read-only view.

  • The column resolves to a column of a base table.

  • The FOR READ ONLY or FOR FETCH ONLY option is not specified

Even though the following view definition uses constant values that cannot be updated, it is a non-read-only view, and at least you can update one of its columns. Therefore, it can be the object of an UPDATE statement.

CREATE VIEW updatable_view
(tcid,cid,number,current_date,current_time,seat_no,score)
AS
SELECT tcid,cid,number,CURRENT DATE,
CURRENT TIME,seat_no,score
FROM db2cert.test_taken
WHERE tcid='TX01'

A view can be the object of an INSERT statement when all of its columns are updateable. Also, all of the columns that do not have a default value must be specified in the INSERT statement. The row being inserted must contain a value for each column in the view definition. The following is a view that can be used to insert rows.

CREATE VIEW insertable_view
(test_number,test_name,total_taken)
AS
SELECT number,name,totaltaken FROM db2cert.test

The view shown above would appear to allow inserts. However, an attempt to insert the view will fail. This is because there are columns in the base table that don't accept null values. Some of these columns are not present in the view definition. When you try to insert a value using the view, DB2 will try to insert a NULL into a NOT NULL column. This action is not permitted.

NOTE

Remember, the constraints defined on the base table are independent of the operations that can be performed using a view.


032 - Summary

Chapter 3. Basic SQL Coding

Summary

In this chapter, we discussed the Data Manipulation Language (DML). DML has four primary statements SELECT, UPDATE, INSERT, and DELETE. These statements enable all database object data manipulation.

The knowledge of basic SQL is mandatory for a DB2 database administrator and application developer. However, SQL is very powerful language, and the level of SQL will vary depending on the user's primary activity.

In this chapter, we covered many of the basic functions of SQL statements, including how to

  • retrieve rows

  • sort the result set

  • restrict the result with some conditions

  • retrieve rows from more than one table at a time

  • add a row to a table

  • remove a record

  • change the value of the table

If you are a business analyst, you may expect more analytical, statistical information from DB2. DB2 supports very powerful SQL functions for various business needs. We'll talk about some advanced SQL in the next chapter.


033 - Additional Resources

Chapter 3. Basic SQL Coding

Additional Resources

IBM DB2 UDB for OS/390 SQL Reference SC26-9944-01


034 - Chapter 4. Advanced SQL Coding

Part 2. Structured Query Language

Chapter 4. Advanced SQL Coding

  • Subqueries

  • Unions

  • Joins

  • Nested Table Expressions

  • CASE Expressions

  • Row Expressions

  • OLAP and Star Joins

This chapter covers some of the more advanced features found in DB2's SQL. We start with discussions on the constructs of subqueries, unions, and joins. Then we examine nested table expressions, the CASE expression with its ifthenelse logic, row expressions, and OLAP features.


035 - Subqueries

Chapter 4. Advanced SQL Coding

Subqueries

A subquery is an SQL statement specifying a search condition that contains either a subselect or a fullselect, and is used inside another SQL statement. A subquery can include search conditions of its own. Each search condition can also contain subqueries. Any SQL statement can contain a hierarchy of subqueries. The SQL query block that contains subqueries is at a higher level than the subqueries they contain. This is important for how columns are referenced between levels.

A subquery can contain search conditions that reference not only columns of the tables identified by its FROM clause, but also columns of tables identified at any higher level. The reverse, however, is not true. A query at a higher level cannot reference columns from a subquery, although outer query columns can be compared to the resultant columns from a subquery. A reference within a subquery to a column of a table from a higher level is called a correlated reference (or correlation predicate).

When specified in a search condition, many operands can be used and are generally categorized as either single-result, IN list, or existence subqueries.

NOTE

Quantified predicates are another form and compare a value (or values) to a collection of values by preceding the comparison operator (=, >, <, etc.) with either ANY, SOME, or ALL. To avoid confusion, quantified predicates will be ignored in this text.

This example demonstrates a single-result subquery to return the test center with the highest number of seats.

SELECT TCID,name,NOSEATS
FROM test_center
WHERE NOSEATS=
(SELECT MAX(NOSEATS) FROM test_CENTER)

The subquery can return only one result, either a null if there are no qualifying rows in the subquery table or a value that represents the maximum value of the column noseats in the TEST_CENTER table. This value is compared with the outer table rows, and only those rows that equal the maximum value for NOSEATS are returned.

This type of subquery is known as a noncorrelated subquery, because there is no correlation between the subquery and the outer query. The subquery is independent of the outer query and merely returns a single result to the outer query for comparison.

To demonstrate an IN list subquery, consider the difficulty of producing a report on the number of DB2 Certification exams if the name and number of the exams is unknown. The following SQL produces a report that includes the names and phone numbers of all the test centers that have candidates registered for the DB2 Certification exams. In the example, we use the word "db2" as the search string to find the numbers of the DB2 Certification program exams:

SELECT DISTINCT name,phone
FROM test_center tc, test_taken tt
WHERE tc.tcid=tt.tcid
AND number IN
(SELECT number FROM test
WHERE name LIKE 'DB2%')

In this example, the subquery appears as part of the IN clause. In the subquery, we are retrieving all the numbers for those tests that have the word "db2" in their name.

NOTE

You will never see the subquery output. The subquery is merely to create a list of values that will be used later by the outer SELECT statement.

Both previous examples have demonstrated a noncorrelated subquery. The most common forms of noncorrelated subqueries are the single-result and the IN list subqueries.

NOTE

The third alternative, an EXISTS subquery, is generally not coded for a noncorrelated subquery. Since an EXISTS subquery returns a true or false, it will be either true for every row of the outer table or false for every row of the outer table.

In contrast, a correlated subquery is a query in which the subquery references values of the immediate outer SELECT or any subselect at a higher level. The most common forms are the single-result and the EXISTS correlated subquery. Whereas the noncorrelated subquery is evaluated once and a result returned to the outer query, the correlated subquery is potentially evaluated once for every outer row.

NOTE

The IN subquery is generally not coded for a correlated subquery due to the potential for the IN list to be built numerous times.

As with the noncorrelated example, a single-result correlated subquery will return a single result for every execution. The difference is that a noncorrelated subquery is executed once rather than many times.

Consider a query to return the highest score for each test and the associated details. The following correlated subquery returns the desired result.

SELECT C.FNAME, TT.NUMBER, TT.DATE_TAKEN, TT.SCORE
FROM TEST_TAKEN TT, CANDIDATE C
WHERE C.CID = TT.CID
AND TT.SCORE =
(SELECT MAX(TT2.SCORE)
 FROM TEST_TAKEN TT2
 WHERE TT2.NUMBER = TT.NUMBER)

FNAME  NUMBER   DATE_TAKEN SCORE
------ -------- ---------- -----
Bill      501   02/02/2000    73
Susan     500   03/01/2000    82
Susan     502   03/02/2000    92
  3 record(s) selected.

For each outer row, the test number for that row is passed to the subquery, and the maximum score for that test is returned to the outer query for comparison. If the maximum score equals the score of the current row, then that row is returned. If not, then the row is discarded. It is possible for the outer query to return more than one row for each test if more than one person achieves the maximum score.

The next example is to demonstrate an EXISTS subquery in which we rewrite the previous noncorrelated IN list SQL example as a correlated subquery. This query produces a report that includes the names and phone numbers of all the test centers that have candidates registered for the DB2 Certification exams. To match the problem description to the query, the problem description can be rewritten as follows: Produce a report that includes the names and phone numbers of all test centers where there exists a candidate registered for the DB2 Certification exams.

SELECT name,phone
FROM test_center tc
WHERE exists
(SELECT * FROM test t, test_taken tt
WHERE t.name LIKE 'DB2%'
and   t.number = tt.number
and   tt.tcid=tc.tcid)

NOTE

As with standard WHERE clause predicates, the reverse condition can be achieved by prefixing the condition with the NOT keyword, such as NOT EXISTS or NOT IN. Remember, however, that a null will not qualify against either an IN or a NOT IN condition.

Observe the WHERE clause in the subquery in this example. It references a table that is listed in the outer FROM clause.

The EXISTS subquery will return a true or a false to the outer query. If true, then the outer row is considered to be a match and the row is returned to the application. The correlated EXISTS subquery will terminate after the first true condition is found or when a false can be determined, as the requirement is only to return a true or false condition, not to list how many occurrences match.

NOTE

Since DB2 prunes the SELECT list for EXISTS subqueries, it is not important for access path or performance what columns are listed in the subquery select list of an EXISTS subquery. Therefore, whether you specify SELECT * or SELECT 1, DB2 will still return a true or false and will not retrieve all columns as an outer query would if SELECT * were specified.


036 - Unions

Chapter 4. Advanced SQL Coding

Unions

The UNION operation lets you combine the results of two or more different SQL statements into one answer set. You can combine many different tables or SQL statements using the UNION (or UNION ALL) operator; the only restriction is that every table or SQL statement must have the same type, number, and order of columns. The term used to describe this is that they must be UNION-compatible.

Suppose you wanted to combine the minimum and maximum score for each DB2 Certification program exam on different output rows, and add a string constant that indicates which values are the maximum and minimum.

SELECT number,'Minimum:', MIN(score)
FROM test_taken
GROUP BY number
UNION
SELECT number,'Maximum:', MAX(score)
FROM test_taken
GROUP BY number
ORDER BY number,2

The UNION operator shows you the results of two or more separate queries as a single result. In our example, the first query calculates the minimum score of the TEST_TAKEN table. Then the second query calculates the maximum score value. Both queries have the same type, order, and number of columns.

In the above example, the two SQL statements are very similar. However, you can combine very different queries using the UNION operator. Just remember the restriction about the resulting rows.

The UNION operator removes duplicate rows from the resulting set. However, there will be times when you'll need to list all the rows processed by your SQL statements or when duplicates are not possible. SQL provides you with an operator clause that allows you to keep all the rows involved in a UNION operation. This is the ALL clause. Since the previous example can never produce duplicate rows, the ALL clause can be added to the UNION:

SELECT number,'Minimum:', MIN(score)
FROM test_taken
GROUP BY number
UNION ALL
SELECT number,'Maximum:', MAX(score)
FROM test_taken
GROUP BY number
ORDER BY number,2

NOTE

Always try to code a UNION ALL rather than UNION. Code a UNION only when duplicates are possible and are not desired. The UNION ALL offers better performance, since a UNION will always invoke a sort to remove duplicates, and a UNION ALL will not. However, you can't always substitute a UNION with a UNION ALL.

NOTE

A UNION (and UNION ALL) can be used between any combination of subselects and fullselects, and in subqueries, views, and table expressions.


037 - Nested Table Expressions

Chapter 4. Advanced SQL Coding

Nested Table Expressions

A nested table expression is a special kind of subquery. This subquery is used in the FROM clause of a SQL statement. Nested table expressions create logical temporary tables that are known only in the SQL statement that defines them. They may or may not result in a physically materialized local table being created, as the SQL may be merged with the outer SQL statement.

These subqueries can be considered temporary views and are also sometimes referred to as inline views. You can use nested table expressions to select from a grouped table or to obtain the same results that you expect from a view.

Consider the problem of obtaining the maximum average score for the DB2 Certification program exams. To gather this result, you must first obtain the averages and then select the maximum value from that list. In the following example, we use a nested table expression to accomplish this request:

SELECT MAX(avg_score)

FROM (
   SELECT number,
   avg(score) as avg_score
   FROM test_taken
   GROUP BY number) AS averages

In this example, the nested subselect creates a temporary table that will be used by the outer SELECT to obtain the maximum average score. This temporary table is called AVERAGES.

Although the number column is included in the nested table expression, it is not actually required to be able to gather the average for each one of the exams, since it is not referenced in the outer query. After the subquery is completed, the outer SELECT will be able to obtain the maximum value of the averages calculated in the nested table expression with or without the number column present in the nested table expression.

An advantage of using nested table expressions over views is that nested table expressions exist only during the execution of the query, so you don't have to worry about their maintenance. They reduce contention over the system catalog tables, and since they are created at execution time, they can be defined using host variables. They also give the SQL programmer more information about the SQL statement. Since views are hidden, it is possible that redundancy is introduced if the programmer is not aware of the full view description.

NOTE

The TABLE clause can also be used to denote that the subquery following it is a nested table expression. This keyword is mandatory if the nested table expression contains a correlated reference to a prior FROM clause table. The TABLE keyword is also used to denote a user-defined TABLE function. Refer to Chapter 15, "Object Relational Programming" for more information on UDFs.


038 - Joins

Chapter 4. Advanced SQL Coding

Joins

The heart of SQL in a relational system is the ability to perform relational joins. Joins are specified by using more than one table name in the FROM clause of a query. A joined table specifies an intermediate result table that is the result of either an inner join or an outer join.

NOTE

The maximum number of tables that can be coded in a single FROM clause is 15, but there can be up to 225 table references in an SQL statement. The 15 table limit can be increased by updating the macro SPRMMXT to a value greater than 15. Also, the 15 table limit does not apply to star join queries.

Inner Joins

The join operation used most often is the one we have been using in the book exercises, which is known as an inner join. An inner join combines each row of the left table with each row of the right table, keeping only the rows where the join condition is true. The result table may be missing rows from either or both of the joined tables. The following example shows an inner join without using the INNER JOIN syntax, which means that the inner join is implicitly defined. The tables in the FROM clause are separated by commas to indicate the join. This type of syntax is valid only for inner joins.

In the example following, we wish to find the scores of all DB2 tests taken by U.S. citizens in the small test centers year by year, in order of ascending year and descending score.

SELECT t.name, YEAR(tt.date_taken) AS year,
   tt.score
FROM test t, test_taken tt, test_center tc,
   candidate c
WHERE c.cid = tt.cid AND
   tc.tcid = tt.tcid AND
   t.number = tt.number AND
   t.name LIKE 'DB2%' AND
   c.country='USA' AND
   tc.noseats < 10
   ORDER BY YEAR(tt.date_taken), TT.SCORE DESC

If the inner join used the explicit syntax, it would appear as

SELECT t.name, YEAR(tt.date_taken) AS year,
   tt.score
FROM test t INNER JOIN test_taken tt
on t.number = tt.number
INNER JOIN test_center tcon tc.tcid = tt.tcid
 INNER JOIN candidate c
ON c.cid = tt.cid
WHERE t.name LIKE 'DB2%'
  AND c.country='USA'
  AND tc.noseats < 10
ORDER BY YEAR(tt.date_taken), TT.SCORE DESC

For the explicit join syntax, the keyword INNER is optional and, if omitted, implies an inner join. The ON clause determines the join predicates between the tables, and the WHERE clause applies the local or table access predicates. For an inner join, it does not impact the result if the local predicates appear in the WHERE or ON clause. For consistency with outer joins, it is recommended that join predicates appear only in the ON clause, and local predicates in the WHERE clause. For outer joins, the placement of predicates in either the ON or WHERE clause can dramatically change the result. This is demonstrated in the next section on outer joins.

Each join must be followed by its ON clause. The ON clause dictates the two tables that are being joined. The joined tables must appear in the FROM clause before they are referenced by join predicates in the ON clause. In the above example, the first join is between TEST and TEST_TAKEN. The second join is between TEST_CENTER and TEST_TAKEN as dictated by the ON clause. And the third is between CANDIDATE and TEST_TAKEN.

There is one exception to the rule that the ON clause must follow each join, and that is when nesting joins within other joins. For simplicity, this syntax is not recommended and can easily be recoded to suit the rule just mentioned. Deciding whether to code the explicit join syntax or to separate the joined tables with commas is purely a matter of preference and is not related to performance.

NOTE

The explicit join syntax has the following benefits: (1) compatibility with the outer join syntax; (2) improves readability of large SQL statements, as each join is followed by its join predicate; and (3) increases the likelihood that all join predicates will be coded correctly.

Outer Joins

Now, we will talk about a different kind of join operation, the outer join. The result set of an inner join consists only of those matched rows that are present in both joined tables. What happens when we need to include those values that are present in one or another joined table, but not in both of them? This is the case when we need to use an OUTER JOIN operation. Outer joins are designed to generate an answer set that includes those values that are present in joined tables and those that are not. This type of optional relationship between tables is very common. There are three types of outer joins: left outer join, right outer join, and full outer join.

Left Outer Join

A LEFT OUTER JOIN operation, also known as left join, produces an answer set that includes the matching values of both joined tables (inner join rows) and those values only present in the left joined table (rows exclusive to the left table). The left joined table is the one used in the left part of the LEFT OUTER JOIN operator when coding the join operation in the FROM clause.

In a left outer join, the left table is referred to as the preserved row table. If a row is unmatched between the two joined tables, it is still returned (preserved) from the left table. The opposite (right) table is the null-supplying table. When a row is unmatched from the left to the right table in the join, the row is supplied with nulls from the right table.

NOTE

With left and right outer joins, reversing the order of tables in the FROM clause may alter the result.

We have been requested to generate a report that includes the first name, the phone number, and the highest score for all the candidates present in the candidate table. If an inner join is used, the report will include data only for those candidates present in the TEST_TAKEN table.

Without utilizing the outer join syntax, this request could be solved using some SQL statements already discussed; however, the construction will be complex. Instead, we will use the left outer join to satisfy the request, as the following example shows.

SELECT C.fname, C.wphone, MAX(TT.score)
FROM candidate c
   LEFT OUTER JOIN test_taken tt
ON c.cid=tt.cid
GROUP BY fname, wphone

NOTE

The keyword OUTER is optional. Provided the JOIN is preceded by either LEFT, RIGHT, or FULL, then OUTER is implied.

Observe the syntax used to indicate a left outer join. The LEFT OUTER JOIN operator is used to indicate the left outer join operation. In this example, the answer set includes those candidates not present in the TEST_TAKEN table. The MAX(TT.SCORE) column will show nulls for those candidates.

It is important to note when coding outer joins the difference between WHERE and on clause predicates. From the previous example, say we want to retrieve only those candidates with a CID of 111, 333, or 444.

SELECT C.CID, C.fname, C.wphone, MAX(TT.score) AS MAX_SCORE
FROM candidate c
   LEFT OUTER JOIN test_taken tt
ON c.cid=tt.cid
WHERE c.cid IN (111, 333, 444)
GROUP BY C.CID, C.fname, C.wphone

CID FNAME WPHONE     MAX_SCORE
--- ----- ---------- ---------
111 Bill  1115551234        73
333 Susan 4442314244        92
444 Glen  5552143244         -
3 record(s) selected.

The WHERE clause predicate in this example is applied to the left or preserved row table. DB2 is able, therefore, to apply this predicate before the join to the CANDIDATE table and join only candidates 111, 333, and 444 to the TEST_TAKEN table. CID 444 in this example returns a MAX_SCORE of null because they have not taken any tests and are therefore not found in the TEST_TAKEN table.

Consider the result if the query was written to also exclude those rows with a score less than 75 if found.

SELECT C.CID, C.fname, C.wphone, MAX(TT.score) AS MAX_SCORE
FROM candidate c
   LEFT OUTER JOIN test_taken tt
ON c.cid=tt.cid
WHERE c.cid IN (111, 333, 444)
AND   tt.score >= 75
GROUP BY C.CID, C.fname, C.wphone

CID FNAME WPHONE     MAX_SCORE
--- ----- ---------- ---------
333 Susan 4442314244        92
1 record(s) selected.

There is only one row that qualifies from this query. The WHERE clause predicate on the preserved row table (WHERE c.cid IN (111, 333, 444)) can be applied before the join to limit the number of rows that must be joined. The additional WHERE clause predicate (AND tt.score >= 75) is applied after the join because it is not known until after the join what the value of tt.score will be. This predicate is applied to each row, with the following result:

  • Is Bill's score of 73 >= 75? FALSE

  • Is Susan's score of 92 >= 75? TRUE

  • Is Glen's score of NULL >= 75? UNKNOWN

Remember that for a row to be returned, the WHERE clause must evaluate to TRUE. Since the nulls introduced by the outer join are discarded by the WHERE clause applied to the null-supplying table, DB2 will actually rewrite the left join to an INNER JOIN, thus allowing the WHERE clause predicates to be applied to both tables before the joining of the rows occurs.

SELECT C.CID, C.fname, C.wphone, MAX(TT.score) AS MAX_SCORE
FROM candidate c
   INNER JOIN test_taken tt
ON c.cid=tt.cid
WHERE c.cid IN (111, 333, 444)
AND   tt.score >= 75
GROUP BY C.CID, C.fname, C.wphone

NOTE

The outer join simplification will be recorded in the JOIN_TYPE column of the plan table. If a left, right, or full join has been simplified to an inner join, the JOIN_TYPE value will be blank.

If you wish to maintain the null-supplied rows, then you must include an additional IS NULL predicate, such as:

SELECT C.CID, C.fname, C.wphone, MAX(TT.score) AS MAX_SCORE
FROM candidate c
   LEFT OUTER JOIN test_taken tt
ON c.cid=tt.cid
WHERE c.cid IN (111, 333, 444)
AND   (tt.score >= 75 OR tt.score IS NULL)
GROUP BY C.CID, C.fname, C.wphone

CID FNAME WPHONE     MAX_SCORE
--- ----- ---------- ---------
333 Susan 4442314244        92
444 Glen  5552143244         -
2 record(s) selected.

In this case, DB2 will not simplify the left outer join to an inner join because the null-supplied row is not discarded by the WHERE clause predicate. Thus, the row for Glen is included in the result set because it is null.

NOTE

WHERE clause predicates applied to the preserved row table can be applied before the join. Predicates applied to the null-supplying table will cause DB2 to simplify the join unless a predicate of the form OR COL IS NULL (or equivalent expression that retains nulls) is coded.

We've looked at WHERE clause predicates applied to either the preserved row or null-supplied tables. The next objective is to demonstrate the impact of coding local predicates in the ON clause. The following example displays the output if we specify the candidate predicate (111, 333, or 444) in the ON clause rather than in the WHERE clause.

SELECT C.CID, C.fname, C.wphone, MAX(TT.score) AS MAX_SCORE
FROM candidate c
   LEFT OUTER JOIN Test_taken tt
ON c.cid=tt.cid
AND c.cid IN (111, 333, 444)
GROUP BY C.CID, C.fname, C.wphone

CID FNAME  WPHONE     MAX_SCORE
--- -----  ---------- ---------
111 Bill   1115551234        73
222 George 2226543455         -
333 Susan  4442314244        92
444 Glen   5552143244         -
555 Jim    6662341234         -
666 Kevin  7773142134         -
777 Bert   8886534534         -
888 Paul   9992112212         -
8 record(s) selected.

Since there are no WHERE clause predicates to restrict the result, this query returns all rows of the CANDIDATE table. Columns from the TEST_TAKEN table are supplied only when the ON clause is true. Remember, WHERE clause predicates restrict the result, whereas ON clause predicates determine the criteria for the join. For the rows not matching the full ON clause (CID NOT IN (111, 333)note that 444 is not included because it will not be found in the TEST_TAKEN table), DB2 will preserve the row from the left table and supply nulls from the right table. Rows matching the ON clause (CID IN (111, 333)) will match and thus return columns from both tables.

NOTE

If DB2 can determine that the ON clause will fail before joining the rows, then it will automatically supply nulls for the null-supplied columns without attempting the join. This improves performance, since rows are not joined unnecessarily if the final result will not match regardless.

Right Outer Join

A RIGHT OUTER JOIN operation, also known as right join, produces an answer set that includes the matching values of both joined tables and those values only present in the right joined table. The right joined table is the one used in the right part of the RIGHT OUTER JOIN operator when coding the join operation.

For a right join, the right table is the preserved row table, and the left table is the null-supplied table for unmatched rows. This is the opposite of a left join. The example using a right outer join is shown below:

SELECT name, count(DISTINCT tt.cid)
FROM test_taken tt
RIGHT OUTER JOIN test t
ON tt.number = t.number

In this example, all test names present in the TEST table and the number of candidates who scheduled or took each test are requested. Notice there may be some tests for which no candidate was scheduled. You cannot report such tests using an inner join statement; however, you can do it using right outer join.

NOTE

The COUNT(DISTINCT TT.CID) will count unique occurrences of TT.CID after the exclusion of nulls. Thus, nulls introduced by the outer join will not be counted. This is intentional, as the addition of a null will falsely add one to the count. The right outer join is required, however, to also report those tests that have not been taken by any candidates.

As with a left join, the order of the tables in the FROM clause for a right join can impact the result. However, a right join can be converted to a left join by reversing the order of the tables in the FROM clause, and also by changing the RIGHT keyword to LEFT.

NOTE

DB2 converts all right joins to left joins at bind time. In the JOIN_TYPE column of the plan table will show an L for a right or a left join unless the join has been simplified to an inner. For this reason, it is recommended to avoid coding right joins to minimize confusion when evaluating the access path.

Full Outer Join

The FULL OUTER JOIN operation produces an answer set that includes the matching values of both joined tables and those values not present in one or the other of the tables. Thus, it returns the inclusive inner join rows plus the exclusive left and right outer rows.

To show a FULL OUTER JOIN operation, we will create two sample tables: CITY and COUNTRY. They show the relationship between a city and a country (CITY table) and a country and a continent (COUNTRY table). The CITY table is designed to have countries that are not in the COUNTRY table. The COUNTRY table is also designed to have countries that are not in the city table. The contents of both tables are shown below.

CITY_NAME            COUNTRY_NAME
---------------      ---------------
Sydney               Australia
London               England
Dublin               Ireland
Firenze              Italy
Milano               Italy
Mexico               Mexico
Lima                 Peru
Toronto              Canada
Vienna               Austria
Hannover             Germany
10 record(s) selected.

COUNTRY_NAME         CONTINENT
---------------      --------------------------
Australia            Australian Continent
England              European Continent
Ireland              European Continent
Italy                European Continent
Mexico               American Continent
Austria              European Continent
South Africa         African Continent
Spain                European Continent
8 record(s) selected.

We want to show all the countries, cities, and continents that are in the tables. Therefore, we are using a full outer join, as the following example shows:

SELECT ctry.continent, ctry.country_name,
cty.country_name, cty.city_name
FROM country ctry
   FULL OUTER JOIN city cty
ON cty.country_name=ctry.country_name
ORDER BY ctry.continent,
   cty.country_name,
   cty.city_name

CONTINENT              COUNTRY_NAME       COUNTRY_NAME     CITY_NAME
--------------         -------------      -------------    ----------
African Continent      South Africa       -                -
American Continent     Mexico             Mexico           Mexico
Australian Continent   Australia          Australia        Sydney
European Continent     Austria            Austria          Vienna
European Continent     England            England          London
European Continent     Ireland            Ireland          Dublin
European Continent     Italy              Italy            Firenze
European Continent     Italy              Italy            Milano
European Continent     Spain              -                -
-                      -                  Canada           Toronto
-                      -                  Germany          Hannover
-                      -                  Peru             Lima
12 record(s) selected.

As shown in the above example, the rows that have a null value were added by the outer join operation. The COUNTRY_NAME column is shown twice to see those countries present in the COUNTRY table that are not present in the CITY table and vice versa.

As shown by the full join example, both tables can preserve rows and also supply nulls for unmatched rows. Since WHERE clause predicates applied to null-supplied tables may cause DB2 to perform simplification of the outer join, predicates that are to be applied before the join to limit the result set must be coded within nested table expressions.

NOTE

DB2 can simplify a full join to either a left or inner join if the WHERE clause predicates discard nulls from one or both tables respectively. This is shown in the JOIN_TYPE column of the plan table as either an L for left or blank for inner join rather than F for a full join.

Consider the following example where we wish to list the information for only South Africa and Peru.

SELECT ctry.continent, ctry.country_name,
cty.country_name, cty.city_name
FROM (SELECT CONTINENT, COUNTRY_NAME
      FROM country
      WHERE COUNTRY_NAME IN ('South Africa', 'Peru')) as ctry
   FULL OUTER JOIN

     (SELECT COUNTRY_NAME, CITY_NAME
      FROM city
      WHERE COUNTRY_NAME IN ('South Africa', 'Peru')) as cty
ON cty.country_name=ctry.country_name
ORDER BY ctry.continent, cty.country_name,
   cty.city_name

CONTINENT              COUNTRY_NAME       COUNTRY_NAME      CITY_NAME
-----------------      -------------      -------------     ---------
African Continent      South Africa       -                 -
-                      -                  Peru              Lima
2 record(s) selected.

Since the country name can return null from either table, it is common to code the COALESCE or VALUE function to ensure that the value is always supplied (and not null). The select list for this example would be.

SELECT ctry.continent, COALESCE(ctry.country_name,cty.country_name)
    , cty.city_name

NOTE

COALESCE returns the first element in the list that is not null.

Combining Outer Joins

Up until now, we have discussed each outer join operation separately. Now, we will show a more complex example combining two outer joins in a single query. Let's display all the candidates and all the tests with their respective scores. To create this query, we need two outer joins. The first outer join will obtain all candidates and their scores, including candidates who did not schedule or take any tests. The second outer join will retrieve all the tests present in the TEST table even if no candidate scheduled or took those tests.

SELECT c.cid, t.name, score
FROM (candidate c
LEFT OUTER JOIN test_taken tt
ON tt.cid=c.cid)
   FULL OUTER JOIN test t
   ON tt.number = t.number
ORDER BY c.cid

The first outer join is enclosed in parentheses. The parentheses are used for readability and to indicate that the left outer join will be resolved first. In reality, the join sequence is determined by the precedence of the join predicates. For example, because the full join in this example joins to a column from the null-supplied table of the previous left join, the left join must precede the full join.

NOTE

When the join sequence is not dictated by the join predicates, DB2 will evaluate the most cost-effective join sequence.

The left outer join gathers all of the candidate IDs. We only need a left outer join here. Because of referential integrity constraints, table TEST_TAKEN can have candidates present only in the CANDIDATE table.

The second part is a full outer join. With this outer join, we take all the tests taken by the candidates, the result of the left outer join, and join them with all the tests in the TEST table. We need a full outer join this time, even though the TEST_TAKEN table can have only test numbers that are present in the TEST table, because the left table of this outer join, which is the result of the first join, may include null values as a test number. The TEST table does not have null values, so we need to use a full outer join. Even if the TEST table did contain nulls, a null will never equal another null unless the predicates of the form IS NULL are included in the join criteria. The results are shown below.

CID NAME                               SCORE
--- ------------------------------     -----
111 DB2 Fundamentals                   65
111 DB2 Administration                 73
111 DB2 Application Development        67
222 DB2 Fundamentals                   55
222 DB2 Application Development        53
222 DB2 Application Development        75
333 DB2 Fundamentals                   82
333 DB2 Administration                 -
333 DB2 Application Development        92
444 -                                  -
555 -                                  -
666 -                                  -
777 -                                  -
888 -                                  -
14 record(s) selected.

NOTE

Care must be taken when joining the result of an outer join to subsequent tables. If the join predicate refers to columns from a null-supplied table, then the join predicate must also cater for the occurrence of nulls. Where possible, code the join predicate from the preserved row table, and if the preceding join was a full join, then utilize the COALESCE function to ensure that the join predicate cannot be null.

Joins Versus Denormalization

One issue that needs to be examined when discussing joins is that of denormalization. Sometimes there is the perceived need to take tables that are always joined together and put them into a single table, in an effort to minimize the joins and improve performance. Since this is generally applied to tables in a one-to-many relationship, it results in multiple occurrences of the same data. This introduces update anomalies, the situation where a single piece of data occurs multiple times. When there is the attempt to update it, all occurrences must be found, and there is no fixed way to determine the number or location of the multiple occurrences.


039 - CASE Expressions

Chapter 4. Advanced SQL Coding

CASE Expressions

You can add ifthenelse logic to your SQL statements and output using CASE expressions. Consider the generation of a list of those candidates who have passed the DB2 Fundamentals exam. In the report, you want to print the score of the tests, but instead of printing the numeric score, you want to print a message. If the score is below the 65, you want to print Not Passed. If it is between the 65 and 90, you want to print Passed, and if the score is above 90, you want to print Excellent. The following SQL statement using a CASE expression accomplishes this:

SELECT fname,lname,
   CASE
      WHEN SCORE < 65 THEN 'Not Passed'
      WHEN SCORE <= 90 THEN 'Passed '
      ELSE
      'Excellent'
   END AS TEST_RESULT
FROM candidate c, test_taken tt
WHERE c.cid=tt.cid
AND TT.number='500'

The SQL statement presented above provides string messages based on the conditions of the CASE expression. In this example, the score column features a numeric value, but we use it to produce a character string. The column derived from the CASE expression has been assigned the name TEST_RESULT.

The order of the conditions for the CASE expression is very important. DB2 will process the first condition first, then the second, and so on. If you do not pay attention to the order in which the conditions are processed, you might be retrieving the same result for every row in your table. For example, if you coded the <= 90 option before the < 65, all the data that is lower than 91, even 64 or 30, will display the message "Passed".

CASE expressions can be used in places other than select lists, such as WHERE, ON, and HAVING clauses. CASE expressions can also be nested within other CASE expressions.

NOTE

You must use the END keyword to finish a CASE statement.

Using CASE Expressions in Functions

CASE expressions can be embedded as function parameters. This allows you to pass different parameters to the function in a single pass of the data. Suppose that the TEST_TAKEN table is very large and we have a requirement to count the following:

  • The number of tests taken with a score higher than 90

  • The number of tests taken with a score of 90

  • The number of tests taken with a score lower than 70

  • The number of DB2 Fundamentals exams taken

Without the use of CASE expressions, this will require four different queries that will potentially read the entire table. We want to do this in a single pass of the data, because the table is very large. The query will use four SUM functions to simulate the COUNT function, each one evaluating different criteria using a CASE expression.

SELECT SUM (CASE WHEN score > 90 then 1
   ELSE null
   END) AS moregb90,
   SUM (CASE WHEN score = 90 then 1
   ELSE null
   END) AS equalgb90,
   SUM (CASE WHEN score < 70 then 1
   ELSE null
   END) AS minorgb70,
   SUM (CASE WHEN number='500' then 1
   ELSE null
   END) AS equalgb500
FROM test_taken
WHERE score >= 90
   OR score < 70
   OR number = '500';

This type of query may be useful when performing data inspection analysis. Notice that the four different requirements are solved in a single pass of the data. The query was created using a different SUM function for each one of the conditions presented as a requirement. The conditions are evaluated in the CASE expression inside each function. When the condition evaluates true, it will return a value of 1 and the row will be summed. When the condition evaluates false, the case expression will return a null value and the row will not be summed. The SUM function is utilized to simulate a count, because the COUNT function cannot contain an expression.

NOTE

It is important for this type of example to remember to code the WHERE clause predicate. Although rows that do not qualify will not affect the result of the SUM functions, DB2 will still apply the CASE expression to these rows. If these rows are excluded by the WHERE clause, then there will be a performance improvement by avoiding unnecessary CASE expressions against these rows.


040 - Row Expressions

Chapter 4. Advanced SQL Coding

Row Expressions

Row expressions are an extension to predicates. They allow more than one set of comparisons in a single predicate, using a subquery that returns more than one column and even more than one row. In the following example, the WHERE clause predicate will be true when all three columns on the left equal the three values in any single row returned in the result set from the subquery. This will also allow the use of quantified predicates (such as = ANY, = SOME, or <> ALL) with row expressions.

SELECT * FROM TABLE
WHERE (col1, col2, col3) IN
   (SELECT cola, colb, colc
    from TABLE
    UNION ALL
    SELECT colx, coly, colz
    From ANOTHER_TABLE)


041 - OLAP Features

Chapter 4. Advanced SQL Coding

OLAP Features

Databases normally hold large amounts of data that can be updated, deleted, queried, and inserted on a daily basis. Databases in which data is constantly updated, deleted, and inserted are known as online transaction processing (OLTP) systems.

Databases that hold large amounts of data and do not have a heavy transaction work load but do have a large number of concurrent queries executing all the time, are known as decision support systems (DSS). Certain decision support systems have fewer queries, but each query can be very complex. These allow users to examine the data from different perspectives by performing online analytical processing (OLAP).

The functionality of the database is required to provide multidimensional views of relational data without a significant performance effect. DB2 provides a star join access path to assist in the processing of the star schema and snowflake (star schema with further normalized dimensions) data models.

Star Schemas

The concept of a star schema is illustrated in Figure 4-1. A business view of a highly normalized database often requires a number of attributes associated with one primary object. Each of these attributes is contained in separate tables.

Figure 4-1. Star schema in the DB2CERT database.

The following points are characteristic of a star schema design:

  • There is a large centralized fact table that is surrounded by normalized dimension tables. The fact table contains the fact or event. In Figure 4-1, the fact table is the TEST_TAKEN table. It contains detailed information on each test taken, including exactly which test was taken, in which center the test was taken, and who took the test.

  • There are a number of small dimension tables that typically hold descriptive information about an entity that has a relatively small number of rows. In Figure 4-1, the dimension tables are TEST, CANDIDATE, and TEST_CENTER.

  • The primary keys of the dimension tables involved in the star schema supply foreign key entries in the fact table. The concatenation of foreign keys from the dimension tables usually forms a small subset of the fact table. In Figure 4-1, the foreign keys are Candidate ID, Center ID, and Test ID.

This approach allows as few attributes as possible to be stored in the fact table. The benefit of this is that the fact table is usually very large, and therefore any data duplication in this table would be very costly in terms of storage and access times. If the DB2CERT database were used to store information on a university's entrance examinations, for example, the TEST_TAKEN table could grow enormously.

OLAP schemas such as the star schema, are frequently used for large databases in data warehousing and decision support systems. These schemas make it very important to access the data in these databases in the optimal manner. Otherwise, the joins involved in the schemas may result in poor performance due to the potentially large size and number of the rows and tables being joined.

OLAP Indexes

A typical star schema may include a large number of indexes. This is due to the ad hoc nature of queries in an OLAP environment. Such an environment is typically not subjected to constant insert or update activity and therefore does not have to suffer from significant performance degradation as a result of index maintenance.

The prime considerations of indexes in an OLAP environment are to facilitate the filtering of the large result set as quickly as possible and the joining of the tables. This is particularly important for the fact table, where multiple indexes are defined, especially on combinations of foreign key columns relating to the dimension tables. The benefit of multiple indexes in this environment is improved query performance against the fact table, as the query can focus on any combination of dimensions. Given that the fact table is the largest table, the application of restrictive join predicates and an efficient access path for the join to this table are of significant importance. The indexes defined on the tables could be either single-column or multicolumn indexes. However, the exploitation of DB2's star join access path utilizes the most cost-effective multicolumn index on the fact table for access.

There are also some maintenance issues to be considered when using multiple indexes in the OLAP environment. The first is that multiple indexes will require a certain amount of space, depending on the number of columns in each index and the size of the tables. The second is that there will be a significant one-time cost when building indexes, perhaps during a bulk load.

Star Joins

A typical query against databases designed with the star schema would consist of multiple local predicates referencing values in the dimension tables and containing join predicates connecting the dimension tables to the fact table, as shown in the following example. These types of queries are called star joins.

SELECT name, YEAR_TAKEN,
   AVG(SCORE) AS avgsc
FROM
(SELECT t.name, YEAR(tt.date_taken) AS YEAR_TAKEN, tt.score
FROM test t, test_taken tt, test_center tc, candidate c
WHERE c.cid = tt.cid AND
   tc.tcid = tt.tcid AND
   t.number = tt.number AND
   t.name LIKE 'DB2%' AND
   c.country='Canada' AND
   TC.NOSEATS < 10) AS STAR_TABLE
GROUP BY name, YEAR_TAKEN

NOTE

The nested table expression is required in this example purely to overcome the limitation that the GROUP BY clause can contain only columns and not expressions. The YEAR(TT.DATE_TAKEN) expression must be logically resolved first in the nested table expression. This is merely a syntactical limitation.

In this example, we wish to find the average score of DB2 tests taken by Canadian citizens in the small test centers year by year. A star join query can be difficult to execute efficiently. Even though the intersection of all dimensions with the fact table can produce a small result set, the predicates applied to a single dimension table are typically insufficient to reduce the enormous number of fact table rows.

If a join based upon related tables (dimension to fact table) does not provide adequate performance, then an alternative is to join unrelated tables. Joining of unrelated tables results in a Cartesian product, whereby every row of the first table is joined with every row of the second.

Performing a Cartesian join of all dimension tables before accessing the fact table may not be efficient. DB2 must decide how many dimension tables should be accessed first to provide the greatest level of filtering of fact table rows using available indexes. This can be a delicate balance, as further Cartesian products will produce a massive increase in the size of the intermediate result sets. Alternatively, minimal prejoining of unrelated dimension tables may not provide adequate filtering for the join to the fact table.


042 - Summary

Chapter 4. Advanced SQL Coding

Summary

In the chapter we looked at some of the advanced features of SQL, including all the different types of joins: inner, left outer, right outer, and full outer. Star joins, which are used in support of star schemas, were also examined.

SQL can become very useful for solving complex business problems by using such features as CASE expressions, nested table expressions, UNIONs and subqueries. These features allow us to push a lot of business logic into the SQL statement.


043 - Additional Resources

Chapter 4. Advanced SQL Coding

Additional Resources

IBM DB2 UDB for OS/390 SQL Reference SC26-9944-01


044 -

Part 3: Developing Applications

    Chapter 5. Using SQL in an Application Program

    Chapter 6. Binding an Application Program

    Chapter 7. Application Program Features

    Chapter 8. Stored Procedures

    Chapter 9. Testing and Debugging Applications

    Chapter 10. Accessing Distributed Data


045 - Chapter 5. Using SQL in an Application Program

Part 3. Developing Applications

Chapter 5. Using SQL in an Application Program

  • Application Environment

  • Embedded SQL

  • Host Variables

  • Using Cursors

  • Using Dynamic SQL


046 - DB2 Application Development Environment

Chapter 5. Using SQL in an Application Program

DB2 Application Development Environment

Suppose you are writing an application program to access data in a DB2 database. When your program executes a SQL statement, the program needs to communicate with DB2. When DB2 finishes processing an SQL statement, DB2 sends back a return code, and your program should test the return code to examine the results of the operation.

To communicate with DB2, you need to choose one of these methods:

  • Static SQL

  • Dynamic SQL

  • Open database connectivity (ODBC)

  • JDBC application support

ODBC lets you access data through ODBC function calls in your application. You execute SQL statements by passing them to DB2 through an ODBC function call. ODBC eliminates the need for precompiling and binding your application and increases the portability of your application by using the industry-standard ODBC interface, but the ODBC processor does issue dynamic SQL.

If you are writing your applications in Java, you can use the industry-standard JDBC application support to access DB2. JDBC is similar to ODBC but is designed specifically for use with Java and is therefore a better choice than ODBC for making DB2 calls from Java applications.


047 - Delimiting SQL in a Program

Chapter 5. Using SQL in an Application Program

Delimiting SQL in a Program

In order to distinguish SQL calls from the rest of the program, delimiters are used. Although used in languages, the actual delimiters and methods differ considerably by language. For all languages using the standard precompiler, however, the methods are very similar. For example, use EXEC SQL and END-EXEC to delimit a SQL statement in a COBOL program:

EXEC SQL
a SQL statement
END-EXEC.

NOTE

For REXX, precede the statement with EXECSQL. If the statement is in a literal string, enclose it in single or double quotation marks.


048 - Declaring Table and View Definitions

Chapter 5. Using SQL in an Application Program

Declaring Table and View Definitions

Before your program issues SQL statements that retrieve, update, delete, or insert data, you must declare the tables and views your program accesses. To do this, include a SQL DECLARE statement in your program.

You do not have to declare tables or views, but there are advantages if you do. One advantage is documentation. For example, the DECLARE statement specifies the structure of the table or view you are working with and the data type of each column. You can refer to the DECLARE statement for the column names and data types in the table or view. Another advantage is that the DB2 precompiler uses your declarations to make sure you have used correct column names and data types in your SQL statements. The DB2 precompiler issues a warning message when the column names and data types do not correspond to the SQL DECLARE statements in your program.

A way to declare a table or view is to code a DECLARE statement in the working-storage section or linkage section within the data division of your COBOL program. Specify the name of the table and list each column and its data type. When you declare a table or view, you specify the table name in the DECLARE statement regardless of whether the table name refers to a table or a view. For example, the DECLARE TABLE statement for the DB2USER1.TEST table looks like this:

EXEC SQL
DECLARE DB2USER1.TEST TABLE
  (NUMBER         CHAR(6)         NOT NULL,
   NAME           VARCHAR(50)     NOT NULL,
   TYPE           CHAR(1)         NOT NULL,
   CUT_SCORE      DECIMAL(6,2),
   LENGTH         SMALLINT        NOT NULL,
   TOTALTAKEN     SMALLINT        NOT NULL)
END-EXEC.

NOTE

An alternative to coding the DECLARE statement manually is to use DCLGEN, the declarations generator supplied with DB2. DCLGEN is covered later in this chapter.

NOTE

When a table or view is declared that contains a column with a distinct type, it is best to declare that column with the source type of the distinct type rather than with the distinct type itself. When the column is declared with the source type, DB2 can check embedded SQL statements that reference that column at precompile time.


049 - Host Variables and Host Structures

Chapter 5. Using SQL in an Application Program

Host Variables and Host Structures

A host variable is a data item declared in the host language for use within a SQL statement. Using host variables, you can

  • Retrieve data into the host variable for your application program's use.

  • Place data into the host variable to insert into a table or to change the contents of a row.

  • Use the data in the host variable when evaluating a WHERE or HAVING clause.

  • Assign the value in the host variable to a special register, such as CURRENT SQLID and CURRENT DEGREE.

  • Insert null values in columns using a host indicator variable that contains a negative value.

  • Use the data in the host variable in statements that process dynamic SQL, such as EXECUTE, PREPARE, and OPEN.

A host structure is a group of host variables that a SQL statement can refer to using a single name. You can use host structures in all languages except REXX. Use the host language statements to define the host structures.

Using Host Variables

Any valid host variable name can be used in a SQL statement. Host variables must be declared to the host program before they can be used. Host variables are used by DB2 to

  • Retrieve data and put it into the host variables for use by the application program.

  • Insert data into a table or update it from the data in the host variable.

  • Evaluate a WHERE or HAVING clause using the data in the host variable; however, host variables cannot be used to represent a table, column, or view.

To optimize performance, make sure the host language declaration maps as closely as possible to the data type of the associated data in the database. Table, view, or column names can be specified at runtime when using dynamic SQL. We discuss dynamic SQL later in this chapter.

Host variables follow the naming conventions of the host language. A colon (:) must precede host variables used in SQL to tell DB2 that the variable is not a column name. A colon must not precede host variables outside of SQL statements.

In the following example, :CANPHONE and :CIDNO are host variables. The values will be supplied at runtime.

EXEC SQL
   UPDATE CANDIDATE
      SET PHONE = :CANPHONE
      WHERE CID = :CIDNO
END-EXEC

The host variables can be used to specify a program data area to contain the column values of a retrieved row or rows.

Using Host Structures

A host structure can be used in place of one or more host variables. In the following example, assume that a COBOL program includes the following SQL statement:

EXEC SQL
   SELECT CID, LNAME, FNAME
   INTO :CIDHV,:LNAMEHV,:FNAMEHV
   FROM DB2USER1.CANDIDATE
   WHERE CID =:CIDHV
END-EXEC.

If you want to avoid listing host variables, you can substitute the name of a structure, say :CANDHS, that contains :CIDHV, :LNAMEHV, and :FNAMEHV. The example then reads

EXEC SQL
   SELECT CID, LNAME, FNAME
   INTO :CANDHS
   FROM DB2USER1.CANDIDATE
   WHERE CID =:CIDHV
END-EXEC.

Host structures can be declared manually, or DCLGEN can be used to generate a COBOL record description, PL/I structure declaration, or C structure declaration that corresponds to the columns of a table.

DCLGEN

The DCLGEN, the declarations generator supplied with DB2, produces a DECLARE statement for use in a C, COBOL, or PL/I program so that the declares for the tables do not need to be manually coded. DCLGEN generates a table declaration and puts it into a member of a partitioned data set that you can include in your program. When you use DCLGEN to generate a table's declaration, DB2 gets the relevant information from the DB2 catalog, which contains information about the table's definition and the definition of each column within the table. DCLGEN uses this information to produce a complete SQL DECLARE statement for the table or view and a matching PL/I or C structure declaration or COBOL record description.

NOTE

DCLGEN can be used only on existing tables.

The DCLGEN must be used and the DCLGEN name of the table or view must be supplied before the program is precompiled. In order to use the declarations generated by DCLGEN in the program, the SQL INCLUDE statement is used. The example below shows this INCLUDE statement for the CAND DCLGEN:

EXEC SQL
    INCLUDE CAND
END-EXEC

DB2 must be active before DCLGEN can be used. The DCLGEN utility can be started in several different ways:

  • From ISPF through DB2I: Select the DCLGEN option on the DB2I Primary Option Menu panel. Fill in the DCLGEN panel with the information it needs to build the declarations. Then press Enter.

  • Directly from TSO: Sign on to TSO, issue the TSO command DSN, and then issue the subcommand DCLGEN.

  • From a CLIST: Run a CLIST in TSO foreground or background that issues DSN, and then run DCLGEN.

  • With JCL: Supply the required information, using JCL, and run DCLGEN in batch.

Following is an example of the output from a DCLGEN.

***************************************************************
     DCLGEN TABLE(DB2USER1.TEST)
         LIBRARY(DB2U01.DCLGEN.LIB(TEST))
         LANGUAGE(COBOL)
         APOST
***************************************************************
   EXEC SQL DECLARE DB2USER1.TEST TABLE
     (NUMBER        CHAR(6)         NOT NULL,
      NAME           VARCHAR(50)     NOT NULL,
      TYPE           CHAR(1)         NOT NULL,
      CUT_SCORE      DECIMAL(6,2),
      LENGTH         SMALLINT        NOT NULL,
      TOTALTAKEN     SMALLINT        NOT NULL)
       END-EXEC.
***************************************************************
* COBOL DECLARATION FOR TABLE DB2USER1.TEST
***************************************************************
   01  DCLTEST.
       10 NUMBER                PIC X(63).
       10 NAME.
           49 NAME-LEN          PIC S9(4) COMP-4.
           49 NAME-TEXT         PIC X(50).
       10 TYPE                  PIC X(1).
       10 CUTSCRE               PIC S(4)V9(2) COMP-3.
       10 LENGTH                PIC 9(5) COMP.
       10 TOTALTKN              PIC 9(5) COMP.
***************************************************************
*    THE NUMBER OF COLUMNS DESCRIBED BY THIS DECLARATION IS 6
***************************************************************

Retrieving a Single Row of Data

The INTO clause of the SELECT statement names one or more host variables to contain the column values returned. The named variables correspond one-to-one with the list of column names in the SELECT list. In the following example, we retrieve CID, LNAME, and FNAME from the CANDIDATE table and populate the host variables. You can define a data area in your program to hold each column, then name the data areas with an INTO clause, as in the following example (notice that a colon precedes each host variable):

EXEC SQL
   SELECT CID, LNAME, FNAME
   INTO :CIDHV,:LNAMEHV,:FNAMEHV
   FROM DB2USER1.CANDIDATE
   WHERE CID =:CIDHV
END-EXEC.

In the DATA DIVISION of the program, the host variables CIDHV, LNAMEHV, and FNAMEHV must be declared and need to be compatible with the data types in the columns CID, LNAME, and FNAME of the DB2USER1.CANDIDATE table.

NOTE

If the SELECT statement returns more than one row, it will result in a-811 error code, and any data returned is undefined and unpredictable.

Retrieving Multiple Rows of Data

If the number of rows returned by DB2 is unknown, or if you expect more than one row to return, then you must use an alternative to the SELECT...INTO statement. A cursor enables an application to process a set of rows and retrieve one row at a time from the result table. We will take a look at cursors later in this chapter.

Inserting and Updating Data

You can set or change a value in a DB2 table to the value of a host variable. To do this, you use the host variable name in the SET clause of UPDATE or the VALUES clause of INSERT. This example changes a candidate's home phone number:

EXEC SQL
   UPDATE DB2USER1.CANDIDATE
      SET PHONENO =:HPHONEHV
      WHERE CID =:CIDHV
END-EXEC.

Searching Data

You can use a host variable to specify a value in the predicate of a search condition or to replace a constant in an expression. For example, if you have defined a field called CIDHV that contains a candidate number, you can retrieve the name of the candidate whose number is '012345678' with

MOVE '012345678' TO CIDHV.
EXEC SQL
   SELECT LNAME
   INTO :LNAMEHV
   FROM DB2USER1.CANDIDATE
   WHERE CID =:CIDHV
END-EXEC.


050 - SQL Execution Validation

Chapter 5. Using SQL in an Application Program

SQL Execution Validation

A program that includes SQL statements needs to have an area set apart for communication with DB2a SQL communication area (SQLCA). When DB2 processes a SQL statement in a program, it places return codes in the SQLCODE and SQLSTATE host variables or corresponding fields of the SQLCA.

The return codes indicate whether the executed statement succeeded or failed. Because the SQLCA is a valuable problem-diagnosis tool, it is a good idea to include instructions to display some of the information contained in the SQLCA in your application programs. For example, the contents of SQLERRD(3)which indicates the number of rows that DB2 updates, inserts, or deletescould be useful. If SQLWARN0 contains W, DB2 has set at least one of the SQL warning flags (SQLWARN1 through SQLWARNA). A description of the SQLCA is shown in Table 5-1.

Table 5-1. SQLCA

Name

Data Type

Purpose

SQLCAID

CHAR(8)

An "eye catcher" for storage dumps, containing the text 'SQLCA'.

SQLCABC

INTEGER

Contains the length of the SQLCA: 136.

SQLCODE

INTEGER

Contains the SQL return code.

Code

Means

0

Successful execution (though there might have been warning messages).

positive

Successful execution, with an exception condition.

negative

Error condition.

SQLERRML

SMALLINT

Length indicator for SQLERRMC, in the range 0 through 70. 0 means that the value of SQLERRMC is not pertinent.

SQLERRMC

VARCHAR(70)

Contains one or more tokens, separated by X'FF', that are substituted for variables in the descriptions of error conditions.

SQLERRP

CHAR(8)

Provides a product signature and, in the case of an error, diagnostic information such as the name of the module that detected the error. In all cases, the first three characters are DSN for DB2 for OS/390.

SQLERRD(1)

INTEGER

Contains an internal error code.

SQLERRD(2)

INTEGER

Contains an internal error code.

SQLERRD(3)

INTEGER

Contains the number of rows affected after INSERT, UPDATE, and DELETE (but not rows deleted as a result of CASCADE delete). Set to 0 if the SQL statement fails, indicating that all changes made in executing the statement were canceled. Set to 1 for a mass delete from a table in a segmented tablespace. SQLERRD(3) can also contain the reason code of a timeout or deadlock for SQLCODES 911 and 913.

SQLERRD(4)

INTEGER

Generally contains a timeron, a short floating-point value that indicates a rough relative estimate of resources required. It does not reflect an estimate of the time required. When preparing a dynamically defined SQL statement, you can use this field as an indicator of the relative cost of the prepared SQL statement. For a particular statement, this number can vary with changes to the statistics in the catalog. It is also subject to change between releases of DB2 for OS/390.

SQLERRD(5)

INTEGER

Contains the position or column of a syntax error for a PREPARE or EXECUTE IMMEDIATE statement.

SQLERRD(6)

INTEGER

Contains an internal error code.

SQLWARN0

CHAR(1)

Contains a W if at least one other indicator also contains a W; otherwise, contains a blank.

SQLWARN1

CHAR(1)

Contains a W if the value of a string column was truncated when assigned to a host variable.

SQLWARN2

CHAR(1)

Contains a W if null values were eliminated from the argument of a column function; not necessarily set to W for the MIN function because its results are not dependent on the elimination of null values.

SQLWARN3

CHAR(1)

Contains a W if the number of result columns is larger than the number of host variables. Contains a Z if fewer locators were provided in the ASSOCIATE LOCATORS statement than the stored procedure returned.

SQLWARN4

CHAR(1)

Contains a W if a prepared UPDATE or DELETE statement does not include a WHERE clause.

SQLWARN5

CHAR(1)

Contains a W if the SQL statement was not executed because it is not a valid SQL statement in DB2 for OS/390.

SQLWARN6

CHAR(1)

Contains a W if the addition of a month or year duration to a DATE or TIMESTAMP value results in an invalid day (for example, June 31). Indicates that the value of the day was changed to the last day of the month to make the result valid.

SQLWARN7

CHAR(1)

Contains a W if one or more nonzero digits were eliminated from the fractional part of a number used as the operand of a decimal multiply or divide operation.

SQLWARN8

CHAR(1)

Contains a W if a character that could not be converted was replaced with a substitute character.

SQLWARN9

CHAR(1)

Contains a W if arithmetic exceptions were ignored during COUNT DISTINCT processing. Contains a Z if the stored procedure returned multiple result sets.

SQLWARNA

CHAR(1)

Contains a W if at least one character field of the SQLCA or the SQLDA names or labels is invalid due to a character conversion error.

SQLSTATE

CHAR(5)

Contains a return code for the outcome of the most recent execution of a SQL statement.

SQLCODE and SQLSTATE

Whenever an SQL statement executes, the SQLCODE and SQLSTATE fields of the SQLCA receive a return code. Although both fields serve basically the same purpose (indicating whether the statement executed successfully), there are some differences between the two fields.

SQLCODE

DB2 returns the following codes in SQLCODE:

  • If SQLCODE = 0, execution was successful.

  • If SQLCODE > 0, execution was successful with a warning.

  • If SQLCODE < 0, execution was not successful.

  • SQLCODE 100 indicates no data was found.

The meaning of SQLCODEs other than 0 and 100 varies with the particular product implementing SQL.

SQLSTATE

SQLSTATE allows an application program to check for errors in the same way for different IBM database management systems. An advantage to using the SQLCODE field is that it can provide more specific information than SQLSTATE. Many of the SQLCODEs have associated tokens in the SQLCA that indicate, for example, which object incurred a SQL error.

To conform to the SQL standard, the SQLCODE and SQLSTATE (SQLCOD and SQLSTA in FORTRAN) can be declared as standalone host variables. If the STDSQL(YES) precompiler option is specified, these host variables receive the return codes, and a SQLCA does not need to be included in the program.


051 - Using Cursors

Chapter 5. Using SQL in an Application Program

Using Cursors

Use a cursor in an application program to retrieve multiple rows from a table or from a result set returned by a stored procedure. This sections looks at how an application program can use a cursor to retrieve rows from a table.

When the SELECT statement associated with the cursor is executed, a set of rows is retrieved. The set of rows returned is referred to as the result table or result set. In an application program, there needs to be a way to retrieve one row at a time from the result set into host variables. A cursor performs that function. A program can have several cursors, open at the same time.

DECLARE Cursor

To define and identify a set of rows to be accessed with a cursor, issue a DECLARE CURSOR statement. The DECLARE CURSOR statement names a cursor and specifies a SELECT statement. The SELECT statement defines the criteria for the rows that will make up the result table. The simplest form of the DECLARE CURSOR statement is as follows:

EXEC SQL
   DECLARE CERTCUR CURSOR FOR
      SELECT TCID, NAME, CODE
      FROM DB2USER1.TEST_CENTER
      WHERE TCID = :TCIDHV
END-EXEC.
Updating a Column

If any of the columns are to be updated in the rows of the identified table, include the FOR UPDATE clause. The FOR UPDATE clause has two forms: one form for when the columns to be updated are known and another for when the columns are not known. Use the following form when the columns intended for update are known:

EXEC SQL
   DECLARE CERTCUR CURSOR FOR
      SELECT TCID, NAME, CODE
      FROM DB2USER1.TEST_CENTER
      WHERE TCID = :TCIDHV
      FOR UPDATE OF CODE
END-EXEC.

If a cursor might be used to update any of the columns of the table, use the following form of the FOR UPDATE clause, which allows for updates to any columns of the table that can be updated:

EXEC SQL
   DECLARE CERTCUR CURSOR FOR
      SELECT TCID, NAME, CODE
      FROM DB2USER1.TEST_CENTER
      WHERE TCID = :TCIDHV
      FOR UPDATE
END-EXEC.

NOTE

DB2 must do more processing when you use the FOR UPDATE clause without a column list than when you use the FOR UPDATE OF clause with a column list. Therefore, if only a few columns of a table are going to be updated, the program can run more efficiently if a column list is included.

A column of the identified table can be updated even though it is not part of the result table. In this case, there is no need to name the column in the SELECT statement. When the cursor retrieves a row (using FETCH) that contains a column value you want to update, the UPDATE...WHERE CURRENT OF statement can be used to update the row.

NOTE

Some result tablesfor example, the result of joining two or more tablescannot be updated.

OPENing the Cursor

To tell DB2 you are ready to process the first row of the result table or result set, an OPEN statement must be issued. DB2 then uses the SELECT statement within the DECLARE CURSOR to identify a set of rows. If host variables are used in that SELECT statement, DB2 uses the current value of the variables to select the rows. The result table that satisfies the search conditions can contain zero, one, or many rows. The OPEN statement looks like this:

EXEC SQL
   OPEN CERTCUR
END-EXEC.

NOTE

There is no way in DB2 to determine the number of rows that qualified during the open. An empty result table or result set is identified by a SQLCODE of +100 on the subsequent FETCH, UPDATE, or DELETE statement.

When used with cursors, DB2 evaluates CURRENT DATE, CURRENT TIME, and CURRENT TIMESTAMP special registers once when the OPEN statement executes. There is more information on special registers later in this chapter. DB2 uses the values returned in the registers on all subsequent FETCH statements.

Two factors that influence the amount of time that DB2 requires to process the OPEN statement are

  • Whether DB2 must perform any sorts before it can retrieve rows from the result table.

  • Whether DB2 uses parallelism to process the SELECT statement associated with the cursor.

Executing SQL statements

Once a cursor is opened, one of the following SQL statements is executed using the cursor:

  • FETCH

  • positioned UPDATE

  • positioned DELETE

FETCH statements

Execute a FETCH statement for one of the following purposes:

  • To copy data from a row of the result table into one or more host variables.

  • To position the cursor before a positioned UPDATE or positioned DELETE operation is performed. The simplest form of the FETCH statement looks like this:

    EXEC SQL
   FETCH CERTCUR
   INTO :TCIDHV,:NAMEHV, ...
END-EXEC.

The SELECT statement within the DECLARE CURSOR statement identifies the result table from which to fetch rows, but DB2 does not retrieve any data until the application program executes a FETCH statement.

When the program executes the FETCH statement, DB2 uses the cursor to point to a row in the result table. That row is called the current row. DB2 then copies the current row contents into the program host variables that you specified in the INTO clause of FETCH. This sequence repeats for each subsequent FETCH until you have processed all the rows in the result table.

The row that DB2 points to when a FETCH statement is executed depends on whether the cursor is declared as scrollable or nonscrollable (covered later in this chapter). When querying a remote subsystem with FETCH, consider using BLOCK FETCH for better performance. BLOCK FETCH processes rows ahead of the current row.

NOTE

BLOCK FETCH cannot be used when a positioned UPDATE or DELETE is performed.

Positioned UPDATE

After the program has executed a FETCH statement to retrieve the current row, a positioned UPDATE statement can be used to modify the data in that row. An example of positioned UPDATE is as follows:

EXEC SQL
   UPDATE DB2USER1.TEST_CENTER
      SET CODE = 123456
      WHERE CURRENT OF CERTCUR
END-EXEC.

A positioned UPDATE statement updates the row that cursor name (CERTCUR) points to. A positioned UPDATE statement must meet these conditions:

  • The row cannot be updated if the update violates any unique, check, or referential constraints.

  • An UPDATE statement cannot be used to modify the rows of a created temporary table. However, it can be used to modify the rows of a declared temporary table (covered later in this chapter).

  • If the right side of the SET clause in the UPDATE statement contains a subselect, that subselect cannot include a correlated name for a table that is being updated.

Positioned DELETE

After the program has executed a FETCH statement to retrieve the current row, a positioned DELETE statement can be used to delete that row. An example of a positioned DELETE statement follows:

EXEC SQL
   DELETE FROM DB2USER1.TEST_CENTER
   WHERE CURRENT OF CERTCUR
END-EXEC.

A positioned DELETE statement deletes the row that CERTCUR points to. A positioned DELETE statement must meet these conditions:

  • A DELETE statement cannot be used with a cursor to delete rows from a created global temporary table. However, it can be used to delete rows from a declared temporary table.

  • After a row has been deleted, you cannot update or delete another row using that cursor until you execute a FETCH statement to position the cursor on another row.

  • A row cannot be deleted if the delete violates any referential constraints.

CLOSEing the Cursor

When the program is finished processing the rows of the result table, issue a CLOSE statement to close the cursor:

EXEC SQL
   CLOSE CERTCUR
END-EXEC.

This will destroy the result set that was created during the OPEN cursor.

Cursor WITH HOLD

A held cursor, which is declared WITH HOLD, does not close after a COMMIT operation. A cursor that is not declared WITH HOLD closes after a COMMIT operation. When a cursor is declared, the inclusion or exclusion of the WITH HOLD clause tells DB2 whether or not the cursor is to be held. After a COMMIT operation, a held cursor is positioned after the last row retrieved and before the next logical row of the result table to be returned.

A held cursor will close when

  • A CLOSE cursor, ROLLBACK, or CONNECT statement is issued.

  • A Call Attach Facility (CAF) CLOSE function call or an RRSAF TERMINATE THREAD function call is issued.

  • The application program terminates.

If the program abnormally terminates, the cursor position is lost. To prepare for restart, your program must reposition the cursor. The following restrictions apply to cursors that are declared WITH HOLD:

  • Do not use DECLARE CURSOR WITH HOLD with the new user sign-on from a DB2 attachment facility, because all open cursors are closed.

  • Do not declare a WITH HOLD cursor in a thread that could become inactive. If you do, its locks are held indefinitely.

There are also some restrictions when using CURSOR WITH HOLD with IMS or CICS programs. (Refer to IBM DB2 Application Programming Guide and SQL Guide for more details.)

NOTE

The use of CURSOR WITH HOLD also will prevent some options in DB2 that are used for performance (e.g., parallelism, drains needed for online REORG).

A simple example of declaring a held cursor is show below.

EXEC SQL
   DECLARE CERTCUR  CURSOR WITH HOLD FOR
      SELECT TCID, NAME, CODE
      FROM DB2USER1.TEST_CENTER
      WHERE TCID = :TCIDHV
END-EXEC.

Types of Cursors

Cursors can be scrollable or nonscrollable. They can also be held or not held. The following sections discuss these characteristics in more detail.

Scrollable and Nonscrollable

When you declare a cursor, you tell DB2 whether you want the cursor to be scrollable or nonscrollable by including or omitting the SCROLL clause. This clause determines whether the cursor moves sequentially forward through the data set or has random access to the data set. See Table 5-2.

Table 5-2. Types of Cursors

Cursor Type

Result Table

Visibility of Own Cursor's Changes

Visibility of Other Cursors' Changes

Updateability[a]

Nonscrollable (join, sort, etc.)

Fixed, work file

No

No

No

Nonscrollable

No work file, base table access

Yes

Yes

Yes

Insensitive Scroll

Fixed, declared temporary table

No

No

No

Sensitive Static Scroll

Fixed, declared temporary table

Yes (inserts not allowed)

Yes (not inserts)

Yes

Sensitive Dynamic Scroll (not supported yet)

No declared temporary table, base table access

Yes

Yes

Yes

[a] Updateability is affected by read-only properties.

NOTE

If the SELECT statement references more than one table or contains a GROUP BY or similar clause, then it becomes read-only!

Using a Nonscrollable Cursor

The simplest type of cursor is a nonscrollable cursor. A nonscrollable cursor always moves sequentially forward in the result table. When a cursor is opened, it is positioned before the first row in the result table. When the first FETCH is executed, the cursor is positioned on the first row. The next FETCH statement moves the cursor one row ahead for each FETCH.

After each FETCH statement, the cursor is positioned on the row that was fetched. After an execution of a positioned UPDATE or positioned DELETE operation, the cursor stays at the current row of the result table. Rows cannot be retrieved backward or moved to a specific position in a result table with a nonscrollable cursor.

Using a Scrollable Cursor

Scrollable cursors allow for movement to any row in the result table. DB2 uses declared temporary tables for processing scrollable cursors. The declaration for a scrollable cursor has the following form:

EXEC SQL
   DECLARE CERTCUR sensitivity STATIC SCROLL CURSOR FOR
      SELECT TCID, NAME, CODE
      FROM DB2USER1.TEST_CENTER
      WHERE TCID = :TCIDHV
END-EXEC.

STATIC SCROLL indicates that the cursor is scrollable and follows the static model.

The sensitivity in the DECLARE statement indicates whether changes that are made to the underlying table after the cursor is opened are visible to the result table. Sensitivity can be INSENSITIVE or SENSITIVE.

  • INSENSITIVE: Means that no changes to the underlying table after the cursor is opened are visible to the result table.

  • SENSITIVE: Means that some or all changes that are made to the underlying table after the cursor is opened are visible to the result table.

The sensitivity clause of the FETCH statement determines which changes to the underlying table are visible to the result table. When the cursor is opened, the cursor is positioned before the first row. A clause is included in each FETCH statement to tell DB2 where to position the cursor in the result table. The FETCH clause for a scrollable cursor has the following form:

EXEC SQL
   FETCH sensitivity cursor-position cursor-name
   INTO :host-variable1, :host-variable2 ...
END-EXEC.

Sensitivity in the FETCH statement indicates whether changes that are made to the underlying table by some means other than the cursor are visible to the result table. Sensitivity can be INSENSITIVE or SENSITIVE. INSENSITIVE means that the only time that changes to the underlying table are visible to the result table is when a positioned UPDATE or positioned DELETE using CERTCUR makes those changes. SENSITIVE means that the result table is updated when the underlying tables change. Table 5-3 is a summary of the sensitivity options.

Table 5-3. Cursor Sensitivity Options

DECLARE C1 INSENSITIVE SCROLL FETCH INSENSITIVE

DECLARE C1 SENSITIVE STATIC SCROLL FETCH INSENSITIVE

DECLARE C1 SENSITIVE STATIC SCROLL FETCH SENSITIVE

  • Read-only cursor

  • Not aware of updates or deletes in base table

  • Updateable cursor

  • Aware of own updates or deletes within cursor

  • Other changes to base table not visible to cursor

  • All inserts not recognized

  • Updateable cursor

  • Aware of own updates and deletes within cursor

  • Sees all committed updates and deletes

  • All inserts not recognized

Scrollable Cursor Fetching

There are several options when fetching with a scrollable cursor. Cursor positioning becomes very flexible, as you can fetch forward and backward, and do relative and absolute positioning. The following example shows several different fetching options.

FETCH
FETCH LAST (or FIRST)
FETCH ABSOLUTE +7
FETCH INSENSITIVE RELATIVE -3
FETCH CURRENT (or BEFORE or AFTER)
FETCH RELATIVE 2
FETCH PRIOR (or NEXT)

NOTE

In a distributed environment, you can use scrollable cursors only if you use DRDA access.


052 - Using Dynamic SQL

Chapter 5. Using SQL in an Application Program

Using Dynamic SQL

Before you decide to use dynamic SQL, some consideration should be taken for whether using static SQL or dynamic SQL is the best technique for the application. For most DB2 users, static SQLembedded in a host language program and bound before the program runsprovides a straightforward, efficient path to DB2 data. Static SQL should be used when the SQL statements the application needs to execute are known before runtime.

Dynamic SQL prepares and executes the SQL statements within a program while the program is running. There are four types of dynamic SQL:

  • Embedded dynamic SQL: The application puts the SQL source in host variables and includes PREPARE and EXECUTE statements that tell DB2 to prepare and run the contents of those host variables at runtime. The programs that include embedded dynamic SQL must go through the precompile and bind steps.

  • Interactive SQL: A user enters SQL statements through SPUFI, QMF, or other facility. DB2 prepares and executes these statements as dynamic SQL statements.

  • Deferred embedded SQL: Deferred embedded SQL statements are neither fully static nor fully dynamic. Like static statements, deferred embedded SQL statements are embedded within applications, but like dynamic statements, they are prepared at runtime. DB2 processes deferred embedded SQL statements with bind-time rules. For example, DB2 uses the authorization ID and qualifiers determined at bind time as the plan or package owner.

  • Dynamic SQL executed through ODBC functions: The application contains ODBC function calls that pass dynamic SQL statements as arguments. There is no need to precompile and bind programs that use ODBC function calls.

Coding Dynamic SQL in Applications

Applications using dynamic SQL use three types of SQL statements:

  • Dynamic SQL for non-SELECT statements: Those statements include DELETE, INSERT, and UPDATE. For execution, use either of the following SQL statements:

    - EXECUTE IMMEDIATE

    - PREPARE and then EXECUTE

  • Dynamic SQL for fixed-list SELECT statements: A SELECT statement is fixed-list if you know in advance the number and type of data items in each row of the result. For execution, use the following SQL statements:

    - PREPARE (a SQL cursor definition)

    - OPEN the cursor

    - FETCH from the cursor

    - CLOSE the cursor

  • Dynamic SQL for varying-list SELECT statements: A SELECT statement is varying-list if you cannot know in advance how many data items to allow for or what their data types are.

    - DECLARE CURSOR for the statement

    - PREPARE the statement

    - DESCRIBE the statement

    - OPEN cursor

    - FETCH using DESCRIPTOR

    - CLOSE cursor

There are many other variations to using dynamic SQL. Host variables can also be used, and the literal data can be put into the dynamic SQL statement. When using parameter markers in the dynamic SQL statement, to be replaced by the host variables later, the bind feature REOPT(VARS) can also be used to assist the optimizer in picking the right access path, based on the host variable data, at execution time.


053 - Summary

Chapter 5. Using SQL in an Application Program

Summary

In this chapter we looked at the various components of a DB2 application program. We looked at how to construct a program and have it communicate with DB2. DB2 can use data in an application program by means of host variables and host structures. We can move through result sets of our data by means of cursors. These cursors must be declared and opened before fetching rows of data is possible. Scrollable and nonscrollable cursors are the two types of cursors that can be used with various options.


054 - Additional Resources

Chapter 5. Using SQL in an Application Program

Additional Resources

DB2 Application Programming and SQL Guide SC26-9933 DB2 SQL Reference SC26-9944


055 - Chapter 6. Binding an Application Program

Part 3. Developing Applications

Chapter 6. Binding an Application Program

  • Precompile and Bind

  • Binding and Rebinding

  • Plans and Packages

  • Removing Plans and Packages

  • Authorities for Plans and Packages


056 - Precompile and Bind

Chapter 6. Binding an Application Program

Precompile and Bind

DB2 application programs include SQL statements. In order to compile these programs, the SQL statements must be converted into a language recognized by the compiler or assembler. The DB2 precompiler or a host-language compiler needs to be used to

  • Replace the SQL statements in the source programs with compilable code.

  • Create a database request module (DBRM), which communicates the SQL requests to DB2 during the bind process.

After the source program has been precompiled, a load module is created, and possibly one or more packages and an application plan are created. Creating a load module involves compiling and link-editing the modified source code that is produced by the precompiler. Creating a package or an application plan, a process unique to DB2, involves binding one or more DBRMs. See Figure 6-1.

Figure 6-1. Program preparation.

Precompile

The precompiler "prepares" the source program for compilation by replacing EXEC SQL by a CALL and by putting the SQL in comment. The precompiler performs the following:

  • Includes DCLGEN member.

  • Includes SQLCA.

  • Looks for SQL statements and for host-variable definitions.

  • Verifies the SQL syntax.

  • Matches each column and table name in the SQL to the DECLARE TABLE statements.

  • Prepares the SQL for compilation or assembly in the host language.

  • Produces a DBRM and stores it in a partitioned dataset (PDS).

  • Can be invoked in DB2I or in batch.

NOTE

DB2 is not accessed during this process.

The DBRM that is created contains extracted, somewhat modified, parsed SQL source code. It can be stored as a member in a PDS. One DBRM is created for each precompile, and it will then become the input to the BIND process.

The SQL statements are replaced during the precompile process with a call to the DSNHLI module. This call will contain the necessary parameters (DBRM name, timestamp, statement number, address of host variables, and address of SQLCA) in order to locate the access path needed to execute the SQL statement associated with the call when the DBRM and modified source are used together at execution time.

Binding

The bind process establishes a relationship between an application program and its relational data. This step is necessary before a program can be executed. DB2 allows two basic ways of binding a program: to a package or directly to an application plan.

NOTE

If the application uses DRDA access to distribute data, then you must use packages.

When a program is preprocessed for DB2, there are normally two outputs: a modified source program to be passed to a compiler where the original SQL statements have been replaced by statements to invoke the appropriate DB2 interface functions and another output containing information on how those SQL statements will be used by DB2. This second output, a DBRM, must be bound so that all the DB2 functions used in the program can be checked for validity and authorization, and so a proper access path can be determined. The bind process performs the following:

  • Checks SQL syntax.

  • Checks security.

  • Compares column and table names against DB2 catalog.

  • Builds access path strategy for each SQL statement.

These processes are discussed in more detail later in this chapter.

Plans and Packages

A DBRM can be bound in a package or directly into a plan. In addition, packages can be bound into logical groups called collections. These packages or collections can then be bound into a plan. A package can be bound for only a single SQL statement, for a subset of the program, or for an entire program, and it will contain information representing optimized SQL, which may just be an access path for the SQL to use to process the data required, or it could be information representing a SQL statement that was first rewritten by the optimizer.

A plan can be bound for multiple packages, collections, and/or DBRMs. Each package can be bound independently of a plan. If a DBRM is bound to a plan and then is rebound, all DBRMs are rebound as well. The output will contain the access path information for each SQL statement.

When determining the maximum size of a plan, several physical limitations must be considered, including the time required to bind the plan, the size of the environmental descriptor manager (EDM) pool, and fragmentation. There are no restrictions to the number of DBRMs that can be included in a plan. However, packages provide a more flexible method for handling large numbers of DBRMs within a plan.

Packages are database objects that contain executable forms of SQL statements. These packages contain statements that are referenced from a DB2 application. A package corresponds to a program source module. Packages are stored in the DB2 catalog tables. The packages contain the DB2 access plan that was selected by DB2 during the BIND or PREPARE process. This type of BIND is known as static binding, since it is performed prior to the execution of the SQL statement. Packages cannot be directly referenced in a SQL data manipulation (DML) statement.

Most applications that access a DB2 database will have a package or group of packages stored (bound) in the system catalog tables. The package is the input to the plan bind using the PKLIST options. A package must be bound into a plan before it is usable. An example of a plan bind is shown below:

BIND PLAN (certpln) PKLIST (col1.*)
Plan to Package Ratio

It is extremely difficult to justify the use of one plan containing all the packages for an installation or even for just all CICS transactions or batch jobs. Plans need to be granular. Large cumbersome plans cause performance degradation, buffer pool problems, and EDM pool problems. The number of packages put into a single plan needs to be based on functionality, such as all the packages supporting a particular function of an online application.

Advantages of Packages

Packages need to be used based on the application design and objectives. The following are a list of advantages provided by packages:

  • Ease of maintenance: With packages, there is no need to bind the entire plan again when a change is made to one SQL statement. Only the package associated with the changed SQL statement needs to be bound.

  • Incremental development of a program: Binding packages into package collections (discussed later) allows for the ability to add packages to an existing application plan without having to bind the entire plan again.

  • Versioning: This allows for the ability to maintain several versions of a plan without using packages requiring a separate plan for each version, and therefore separate plan names and RUN commands. This is discussed later in this section.

  • Flexibility in using bind options: The options of BIND PLAN apply to all DBRMs bound directly to the plan. The options of BIND PACKAGE apply only to the single DBRM bound to that package. The package options need not all be the same as the plan options, and they need not be the same as the options for other packages used by the same plan.

  • Flexibility in using name qualifiers: The bind option QUALIFIER can be used to name a qualifier for the unqualified object names in SQL statements in a plan or package. Using packages allows different qualifiers for SQL statements in different parts of an application. In order to redirect SQL statements, for example, from a test table to a production table, all that is required is a rebind.

  • CICS flexibility: With packages, there is no need to have dynamic plan selection and the associated exit routine. A package listed within a plan is not accessed until it is executed. However, it is possible to use dynamic plan selection and packages together. This can reduce the number of plans in an application, and hence require less effort to maintain the dynamic plan exit routine.

Collections

A collection is a group of associated packages. If a collection name is included in the package list when a plan is bound, any package in the collection becomes available to the plan. The collection can even be empty when the plan is first bound. Later, packages can be added to the collection, and existing packages can be dropped or replaced, without binding the plan again.

A collection is implicitly created at the first package bind that references a named collection. The name of the package is collection.packagename.

NOTE

Collections are used in order to group packages by application or function.

The CURRENT PACKAGESET special register will allow for package searches on specific collections and will disregard any other DBRMs. Below is an example of using the special register to search only the certcol collection:

EXEC SQL SET CURRENT PACKAGESET = 'certcol'

Without the use of CURRENT PACKAGESET, all the DBRMs would be searched, and then collections would be searched.

NOTE

It is also possible to have two different copies of a program by binding them into two different collections.

Versioning

Maintaining several versions of a plan without using packages requires a separate plan for each version and therefore separate plan names and RUN commands. Isolating separate versions of a program into packages requires only one plan and helps to simplify program migration and fallback. At precompile time the user can assign versions to the program, which allow multiple copies of the same package in the DB2 system. For example, separate development, test, and production levels of a program can be maintained by binding each level of the program as a separate version of a package, all within a single plan.

Binding and Rebinding

The BIND PACKAGE subcommand allows you to bind DBRMs individually. It provides the ability to test different versions of an application without extensive rebinding.

NOTE

Package binding is also the only method for binding applications at remote sites.

Even when DBRMs are bound into packages, all programs must be designated in an application plan. BIND PLAN establishes the relationship between DB2 and all DBRMs or packages in that plan. Plans can specify explicitly named DBRMs, packages, collections of packages, or a combination of these elements. The plan contains information about the designated DBRMs or packages and about the data the application program intends to use. It is stored in the DB2 catalog.

In addition to building packages and plans, the bind process

  • Validates the SQL statements using the DB2 catalog. During the bind process, DB2 checks the SQL statements for valid table, view, and column names. Because the bind process occurs as a separate step before program execution, errors are detected and can be corrected before the program is executed.

  • Verifies that the process binding the program is authorized to perform the data accessing operations requested by your program's SQL statements. When the BIND command is issued, an authorization ID can be specified as the owner of the plan or package. The owner can be any one of the authorization IDs of the process performing the bind. The bind process determines whether the owner of the plan or package is authorized to access the data the program requests.

  • Selects the access paths needed to access the DB2 data that the program wants to process. In selecting an access path, DB2 considers indexes, table sizes, and other factors. DB2 considers all indexes available to access the data and decides which ones (if any) to use when selecting a path to the data. BIND PLAN and BIND PACKAGE can be accomplished using DB2I panels, the DSNH CLIST, or the DSN subcommands BIND PLAN and BIND PACKAGE.

Depending upon how the DB2 application was designed, all DBRMs could be bound in one operation, creating only a single application plan. Or, you might bind some or all of your DBRMs into separate packages in separate operations. After that, the entire application must still be bound as a single plan, listing the included packages or collections and binding any DBRMs not already bound into packages.

NOTE

Regardless of what the plan contains, a plan must be bound before the application can run.

Binding or Rebinding a Package or Plan in Use

Packages and plans are locked during binding and execution. Packages that run under a plan are not locked until the plan uses them. If you execute a plan and some packages in the package list are never executed, those packages are never locked.

There is no ability to bind or rebind a package or a plan while it is running. However, a different version of a package that is running can be bound.

Options for Binding and Rebinding

There are a few methods used for BINDing and REBINDing packages and plans.

  • The BIND (ADD) option can be used to allow for the creation of a new plan or package.

  • The BIND (REPLACE) is used when the program has been changed.

  • REBINDing is used when a program has not changed but maybe an index has been added or RUNSTATS has been executed, and any access path changes need to be accounted for.

Several of the options of BIND PACKAGE and BIND PLAN can affect your program design. For example, there is a bind option that can be used to ensure that a package or plan can run only from a particular CICS connection or a particular information management systems (IMS) regionthis cannot be enforced in your code. An example is shown below:

BIND PLAN(CICSONLY)-
   MEMBER(CERTDBRM)-
   ACTION(ADD)-
   ISOLATION(CS)-
   OWNER(DB2USER1)-
   QUALIFIER(DB2USER1)-
   CACHESIZE(0)-
   ENABLE(CICS)CICS(CON1)

Several other options are discussed at length in later chapters, particularly the ones that affect the program's use of locks, such as the option ISOLATION. Table 6-1 lists options for BIND/REBIND and what it is valid for plans, packages, and trigger packages (REBIND only; trigger packages are discussed in Chapter 15, "Object Relational Programming"). The options chosen are recorded in the SYSPLAN and SYSPACKAGE catalog tables.

Table 6-1. Bind/Rebind Options

Option

Valid Values

Plan

Package

Trigger

ACQUIRE

USE, ALLOCATE

X

X

Determines whether to acquire resources specified in the DBRM at first access or allocation

ACTION

REPLACE, ADD

X, BO

X, BO

REPLACE(RPLVER)

X, BO

REPLACE(RETAIN)

X, BO

Determines whether the object (plan or package) replaces an existing object with same name or is new

CACHESIZE

Value of PLAN AUTH CACHE; decimal value

X

Determines the size (in bytes) of the authorization cache acquired in the EDM pool for the plan

COPY

Collection-id, package-id, COPYVER

X, BO

Determines that you are copying an existing package and names the package

CURRENTDATA

YES, NO

X

X

X

Determines whether to require data currency for RO and ambiguous cursors when isolation level is CS

CURRENTSERVER

Location-name

X

Determines the location to connect to before running the plan

DBPROTOCOL

DRDA, PRIVATE

X

X

Specifies which protocol to use when connecting to a remote site that is identified by a three-part name

DEFER

DEFER(PREPARE), NODEFER(PREPARE)

X

X

Whether to defer preparation of dynamic SQL that refer to remote objects or to prepare them immediately

DEGREE

1, ANY

X

X

Determines whether to attempt to run a query using parallel processing to maximize performance

DISCONNECT

EXPLICIT, AUTOMATIC, CONDITIONAL

X

Determines which remote connections to destroy during commit operations

DYNAMICRULES

RUN, BIND

X

X

DEFINEBIND, DEFINERUN, INVOKEBIND, INVOKERUN

X

Determines what values apply at runtime for dynamic SQL attributes

ENABLE DISABLE

BATCH, CICS, DB2CALL, DLIBATCH, IMS, IMSBMP, IMSMPP, RRSAF

X

X

REMOTE

X

Determines which connections can use the plan or package

ENCODING

ASCII, EBCIDIC, UNICODE, ccsid

X

X

Specifies the application encoding for all static statements in the plan or package

EXPLAIN

NO, YES

X

X

X

Determines whether or not to populate the PLAN_TABLE with information about the SQL statements

FLAG

I, W, E, C

X

X

X

Determines what messages to display

IMMEDIATE

NO, PH1, YES

X

X

Determines whether immediate writes will be done for updates made to GBP-dependent page sets/partitions

ISOLATION

RR, RS, CS, UR, NC

X

X

X

Determines how far to isolate an application from the effects of other running applications

KEEPDYNAMIC

NO, YES

X

X

Determines whether DB2 keeps dynamic SQL statements after commit points

LIBRARY

dbrm-pds-name (can be multiple for PLAN)

X, BO

X, BO

Determines what PDS to search for DBRMs listed in the member option

MEMBER

dbrm-member-name (can be multiple for PLAN)

X, BO

X, BO

Determines what DBRMs to include in the plan or package

OPTHINT

Hint-id

X

X

Controls whether query optimization hints are used for static SQL

OPTIONS

COMPOSITE, COMMAND

X, BC

Specifies which bind options to use for the new package

OWNER

Authorization-id

X

X

Determines the authorization ID or the owner of the object (plan or package)

PACKAGE

Location-name.collection-id.package-id (version-id)

X

([*])

X, RO

Determines what package or packages to bind or rebind

PATH

Schema-name, USER, (schema-name, (USER)…)

X

X

Determines the SQL path that DB2 uses to resolve unqualified UDTs, functions, and stored procedure name

PKLIST or NOPKLIST

(Location-name.collection-id.package-id…), PKLIST only

X

Determines what package to include for the package list in the plan

PLAN

Plan-name

X

([*])

X, RO

Determines what plan or plans to bind or rebind

QUALIFIER

Qualifier-name

X

X

Determines the implicit qualifier for unqualified names of objects in the plan or package

RELEASE

COMMIT, DEALLOCATE

X

X

X

Determines when to release resources that the program uses, either at commit or at termination

REOPT

NOREOPT(VARS), REOPT(VARS)

X

X

If access path should be determined at runtime with host variables, parameter markers, and special registers

SQLERROR

NOPACKAGE, CONTINUE

X

Determines whether to create a package if there is an SQL error in it

SQLRULES

DB2, STD

X

Determines if a Type 2 connection can be made according to DB2 rules for an existing connection

VALIDATE

RUN, BIND

X

X

Determines whether to recheck at runtime "not found" and "not authorized" errors found at bind time

[*] BO BIND only, BC BIND COPY, RO REBIND only

NOTE

If the values in BIND/REBIND PACKAGE are different from those in BIND/REBIND PLAN, then the values for the BIND/REBIND PACKAGE will prevail.

Preliminary Steps

Before performing a bind, consider the following:

  • Determine how the DBRMs should be bound (i.e., into packages, directly into plans, or a combination of both methods).

  • Develop a naming convention and strategy for the most effective and efficient use of the plans and packages.

  • Determine when the application should acquire locks on the objects it uses: on all objects when the plan is first allocated or on each object in turn when that object is first used. (For more details on locking, refer to Chapter 16, "Locking and Concurrency.)

Invalidations

If an object that a package depends on is dropped, the following occurs:

  • If the package is not appended to any running plan, the package becomes invalid.

  • If the package is appended to a running plan, and the drop occurs outside of that plan, the object is not dropped, and the package does not become invalid.

  • If the package is appended to a running plan, and the drop occurs within that plan, the package becomes invalid.

In all cases, the plan does not become invalid unless it has a DBRM referencing the dropped object. If the package or plan becomes invalid, automatic rebind occurs the next time the package or plan is allocated.

Rebinding a Package

The way in which the collection id (coll-id), package id (pkg-id), and version id (ver-id) on the REBIND PACKAGE subcommand are specified determines which packages are bound.

REBIND PACKAGE does not apply to packages for which you do not have the BIND privilege. An asterisk (*) used as an identifier for collections, packages, or versions does not apply to packages at remote sites.

The asterisk can be used on the REBIND subcommand for local packages, but not for packages at remote sites. Any of the following commands rebinds all versions of all packages in all collections, at the local DB2 system, for which you have the BIND privilege.

REBIND PACKAGE (*)
REBIND PACKAGE (*.*)
REBIND PACKAGE (*.*.(*))

Either of the following commands rebinds all versions of all packages in the local collection REGS for which you have the BIND privilege.

REBIND PACKAGE (REGS.*)
REBIND PACKAGE (REGS.*.(*))

Either of the following commands rebinds the empty string version of the package TESTPK in all collections, at the local DB2 system, for which you have the BIND privilege.

REBIND PACKAGE (*.TESTPK)
REBIND PACKAGE (*.TESTPK.())
Package Lists

Using the PKLIST keyword replaces any previously specified package list. Omitting the PKLIST keyword allows the use of the previous package list for rebinding. Using the NOPKLIST keyword deletes any package list specified when the plan was previously bound. The following example rebinds PLANTK and changes the package list.

REBIND PLAN(PLANTK) PKLIST(GROUP1.*) MEMBER(TEST)

The following example rebinds the plan and drops the entire package list.

REBIND PLAN(PLANTK) NOPKLIST

A list of REBIND subcommands can be generated for a set of plans or packages that cannot be described by using asterisks, using information in the DB2 catalog. You can then issue the list of subcommands through DSN.

One situation in which the technique is particularly useful is in completing a rebind operation that has terminated for lack of resources. A rebind for many objects, say REBIND PACKAGE (*) for an ID with SYSADM authority, terminates if a needed resource becomes unavailable. As a result, some objects are successfully rebound and others are not. If you repeat the subcommand, DB2 attempts to rebind all the objects again. But if you generate a REBIND subcommand for each object that was not rebound, and issue those, DB2 does not repeat any work already done and is not likely to run out of resources.

Automatic Rebinding

Automatic rebind might occur if an authorized user invokes a plan or package when the attributes of the data on which the plan or package depends have changed or if the environment in which the package executes changes. Whether the automatic rebind occurs depends on the value of the field AUTO BIND on installation panel DSNTIPO. The options used for an automatic rebind are the options used during the most recent bind process.

In most cases, DB2 marks a plan or package that needs to be automatically rebound as invalid. A few common situations in which DB2 marks a plan or package as invalid are

  • When a table, index, or view on which the plan or package depends is dropped.

  • When the authorization of the owner to access any of those objects is revoked.

  • When the authorization to execute a stored procedure is revoked from a plan or package owner, and the plan or package uses the CALL literal form to call the stored procedure.

  • When a table on which the plan or package depends is altered to add a TIME, TIMESTAMP, or DATE column.

  • When a created temporary table on which the plan or package depends is altered to add a column.

  • When a user-defined function on which the plan or package depends is altered.

  • Whether a plan or package is valid is recorded in column VALID of catalog tables SYSPLAN and SYSPACKAGE.

In the following cases, DB2 might automatically rebind a plan or package that has not been marked as invalid:

  • A plan or package is bound in a different release of DB2 from the release in which it was first used.

  • A plan or package has a location dependency and runs at a location other than the one at which it was bound. This can happen when members of a data sharing group are defined with location names, and a package runs on a different member from the one on which it was bound.

DB2 marks a plan or package as inoperative if an automatic rebind fails. Whether a plan or package is operative is recorded in column OPERATIVE of the SYSPLAN and SYSPACKAGE catalog tables.

Whether EXPLAIN runs during automatic rebind depends on the value of the field EXPLAIN PROCESSING on installation panel DSNTIPO, and on whether you specified EXPLAIN(YES). Automatic rebind fails for all EXPLAIN errors except "PLAN_TABLE not found."

NOTE

The SQLCA is not available during automatic rebind; therefore, some error messages may not be available.

Removing a Plan or Package

The only way to remove a plan or package is to use the FREE command. This command removes the object from the catalog tables, and it will no longer be available for use. The example below frees all of the packages in the CERTCL collection:

FREE PACKAGE (CERTCL.*)


057 - Plan or Package Ownership

Chapter 6. Binding an Application Program

Plan or Package Ownership

An application plan or a package can take many actions on many tables, all of them requiring one or more privileges. The owner of the plan or package must hold every required privilege. Another ID can execute the plan or package if it has only the EXECUTE privilege. In that way, another ID can exercise all the privileges that are used in validating the plan or package, but only within the restrictions that are imposed by the SQL statements in the original program.

The executing ID can use some of the owner's privileges, within limits. If the privileges are revoked from the owner, the plan or the package is invalidated. It must be rebound, and the new owner must have the required privileges.

The BIND and REBIND subcommands create or change an application plan or a package. On either subcommand, use the OWNER option to name the owner of the resulting plan or package. Keep these points in mind when naming an owner.

If the OWNER option is used:

  • Any user can name the primary or any secondary ID.

  • An ID with the BINDAGENT privilege can name the grantor of that privilege.

  • An ID with SYSCTRL or SYSADM authority can name any authorization ID on a BIND command, but not on a REBIND command.

If the OWNER option is omitted:

  • BIND primary ID becomes the owner.

  • REBIND the previous owner retains ownership.

Unqualified Objects

A plan or package can contain SQL statements that use unqualified table and view names. For static SQL, the default qualifier for those names is the owner of the plan or package. However, you can use the QUALIFIER option of the BIND command to specify a different qualifier.

For plans or packages that contain static SQL, using the BINDAGENT privilege and the OWNER and QUALIFIER options gives you considerable flexibility in performing bind operations. For plans or packages that contain dynamic SQL, the DYNAMICRULES behavior determines how DB2 qualifies unqualified object names.

For unqualified distinct types, user-defined functions, stored procedures, and trigger names in dynamic SQL statements, DB2 finds the schema name to use as the qualifier by searching schema names in the CURRENT PATH special register. For static statements, the PATH bind option determines the path that DB2 searches to resolve unqualified distinct types, user-defined functions, stored procedures, and trigger names.

However, an exception exists for ALTER, CREATE, DROP, COMMENT ON, GRANT, and REVOKE statements. For static SQL, specify the qualifier for these statements in the QUALIFIER bind option. For dynamic SQL, the qualifier for these statements is the authorization ID of the CURRENT SQLID special register.

Plan Execution Authorization

The plan or package owner must have authorization to execute all static SQL statements that are embedded in the plan or package. These authorizations do not need to be in place when the plan or package is bound, nor do the objects that are referred to, need to exist at that time.

A bind operation always checks whether a local object exists and whether the owner has the required privileges on it. Any failure results in a message. To choose whether the failure prevents the bind operation from completing, use the VALIDATE option of BIND PLAN and BIND PACKAGE, and also the SQLERROR option of BIND PACKAGE. If you let the operation complete, the checks are made again at runtime. The corresponding checks for remote objects are always made at runtime. Authorization to execute dynamic SQL statements is also checked at runtime.


058 - Summary

Chapter 6. Binding an Application Program

Summary

This chapter looked at what it takes to compile and bind an application program to DB2 and to be able to execute that program. This process must be completed in order to have a program access and to manipulate DB2 data. Packages and DBRMs are used in order to store the bound program and the plan is the actual executable object. We also looked at the special authorities needed to execute the plan.


059 - Additional Resources

Chapter 6. Binding an Application Program

Additional Resources

DB2 Application Programming and SQL Guide SC26-9933

DB2 Command Reference SC26-9934


060 - Chapter 7. Application Program Features

Part 3. Developing Applications

Chapter 7. Application Program Features

  • Commit and Rollback

  • Savepoints

  • Unit of Work

  • Temporary Tables

  • Fetching Limited Rows

  • Using Identity Columns


061 - Application Program Features

Chapter 7. Application Program Features

Application Program Features

All SQL programs execute as part of an application process. An application process involves the execution of one or more programs and is the unit to which DB2 allocates resources and locks. Different application processes might involve the execution of different programs or different executions of the same program. The means of initiating and terminating an application process are dependent on the environment.


062 - Commit, Rollback, and Savepoint

Chapter 7. Application Program Features

Commit, Rollback, and Savepoint

More than one application process might request access to the same data at the same time. Locking is used to maintain data integrity under such conditions, preventing, for example, two application processes from updating the same row of data simultaneously. For more information, refer to Chapter 16, "Locking and Concurrency."

DB2 implicitly acquires locks to prevent uncommitted changes made by one application process from being perceived by any other. DB2 implicitly releases all locks it has acquired on behalf of an application process when that process ends, but an application process can also explicitly request that locks be released sooner.

Commit and Rollback

A commit operation releases locks acquired by the application process and commits database changes made by the same process. There are two good reasons to commit:

  • Improve concurrency.

  • Prevent massive, long-running rollbacks when abnormal terminations occur.

Even programs that have no concurrency problems should at least do a commit every 10 minutes as a general rule.

If you design a good batch program, commit processing is part of it. If you do commit processing, you have to identify the unit of work (UOW) in your program and also design the batch program such that it is restartable.

When concurrency is an issue, you probably want a commit frequency somewhere between 2 seconds and 20 seconds. A very good practice is to make sure the commit frequency can be influenced from the outside. Identify a logical UOW in your program and execute this x number of times before doing a commit. The magic number x could come from a control card to your program or from a heuristic control table. This way, programs that cause concurrency problems can be tuned, and you could also have separate settings depending on the time of day. It is a good idea to have the same design in all of your programs. There are software solutions available from the independent software vendors (ISVs) that take care of all commit and restart problems.

It is not good practice to do intermittent committing in online transactions rather than commit at the end of the transaction. When you have a long-running (background) transaction (printing, for example), you should design your transaction such that it will reschedule itself and then terminate (doing an implicit commit). This way, all resources are released and the transaction server can shut down in an orderly way when needed.

DB2 also provides a way to back out uncommitted changes made by an application process. This might be necessary in the event of a failure on the part of an application process, or in a deadlock situation. An application process, however, can explicitly request that its database changes be backed out. This operation is called rollback. DB2 creates undo log records for rollbacks and redo log records for recovery for every row that is changed. DB2 also logs these records for changes to all affected indexes.

The interface used by a SQL program to explicitly specify these commit and rollback operations depends on the environment. If the environment can include recoverable resources other than DB2 databases, the SQL COMMIT and ROLLBACK statements cannot be used. Thus, these statements cannot be used in information management system (IMS), CICS (Customer Information Control System), or WebSphere environments.

Unit of Work

A UOW, sometimes called a logical UOW, is a recoverable sequence of operations within an application process. At any time, an application process has a single UOW, but the life of an application process can involve many UOWs as a result of commit or full rollback operations.

A UOW is initiated when an application process is initiated. A UOW is also initiated when the previous UOW is ended by something other than the end of the application process. A UOW is ended by a commit operation, a full rollback operation (either explicitly initiated by the application process or implicitly initiated by DB2), or the end of an application process. A commit or rollback operation affects only the changes made to recoverable resources within the UOW.

While changes (via insert, update, or delete) to data remain uncommitted, other application processes are unable to perceive them unless they are running with an isolation level of uncommitted read. The changes can still be backed out by a rollback. Once committed, these database changes are accessible by other application processes and can no longer be backed out by a rollback. Locks acquired by DB2 on behalf of an application process to protect uncommitted data are held at least until the end of a UOW.

The initiation and termination of a UOW define points of consistency within an application process. A point of consistency is a claim by the application that the data is consistent. For example, a banking transaction might involve the transfer of funds from one account to another. Such a transaction would require that these funds be subtracted from the first account and added to the second. Following the subtraction step, the data is inconsistent. Only after the funds have been added to the second account is consistency reestablished. When both steps are complete, the commit operation can be used to end the UOW, thereby making the changes available to other application processes.

Unit of Recovery

A DB2 unit of recovery (UR) is a recoverable sequence of operations executed by DB2 for an application process. If a UOW involves changes to other recoverable resources (e.g., VSAM or MQSeries), the UOW will be supported by those URs. If relational databases are the only recoverable resources used by the application process, then the scope of the UOW and the UR are the same, and either term can be used.

Rolling Back Work

DB2 can back out all changes or only selected changes made in a UR. Only backing out all changes results in a point of consistency.

The SQL ROLLBACK statement without the TO SAVEPOINT clause specified causes a full rollback operation. If such a rollback operation is successfully executed, DB2 backs out uncommitted changes to restore the data consistency that it assumes existed when the UOW was initiated. That is, DB2 undoes the work.

Savepoints

A savepoint enables milestones within a transaction or UR. An external savepoint represents the state of the data and schema at a particular point in time. After the savepoint is set, changes made to data and schemas by the transaction can be rolled back to the savepoint, as application logic requires, without affecting the overall outcome of the transaction.

EXEC SQL
SAVEPOINT name TEST516 (other options)
END-EXEC.

EXEC SQL
ROLLBACK TO SAVEPOINT name
END-EXEC.

ROLLBACK can be used to restore to a savepoint. This would be useful when a point has been reached during a unit of work and there is a need to back out without undoing the entire unit of work. Individual savepoints can be named and then ROLLBACK can be used to roll back work to whichever point is required based on the application processing requirements, skipping over individual savepoints if necessary.

If there are outstanding savepoints, access to a remote database management system (via DRDA or private protocol using aliases or three-part names) is not permitted because the scope of a savepoint is within the database management system on which it was set. DRDA access using a CONNECT statement is allowed; however, the savepoints are local to their site. DB2 does not restrict the use of aliases and three-part names to connect to a remote site when there are outstanding savepoints at the remote site. But this is not recommended. There is no limit the number of savepoints that can be set.

Establishing a Savepoint

In order to set a savepoint, you use the SAVEPOINT statement. You can choose the name for the savepoint, so the name can be meaningful if you wish. Application logic will determine if the savepoint name needs to be reused as the application progresses or that the savepoint name needs to denote a unique milestone. You can specify the UNIQUE option on the SAVEPOINT statement if you do not intend for the name to be reused. This will prevent an invoked procedure from unintentionally reusing the name. If a savepoint is coded in a loop, however, there is no choice; do not use UNIQUE.

If the name of the savepoint identifies a savepoint that already exists within the UR and the savepoint was not created with the UNIQUE option, the savepoint is destroyed and a new savepoint is created. Destroying a savepoint by reusing its name for another savepoint is not the same as releasing the savepoint. Reusing a savepoint name destroys only the one savepoint.

Releasing a savepoint releases the named savepoint and all savepoints that were subsequently set (releasing savepoints is described later).

The following statement shows an example of setting a unique savepoint named START_AGAIN. After executing this statement, the application program needs to check the SQL return code to verify that the savepoint was set.

EXEC SQL
SAVEPOINT START_AGAIN UNIQUE ON ROLLBACK RETAIN CURSORS
END-EXCE.

The SAVEPOINT statement sets a savepoint within a UR. This statement as well as the ROLLBACK and RELEASE statements can be imbedded in application programs, external user-defined functions, stored procedures (that is, defined as MODIFIES SQL DATA), or issued interactively. It cannot be issued from the body of a trigger. It is an executable statement that can be dynamically prepared only if DYNAMICRULES run behavior is implicitly or explicitly in effect. The syntax is as follows:

EXEC SQL
SAVEPOINT svptname
UNIQUE
  ON ROLLBACK RETAIN CURSORS
  ON ROLLBACK RETAIN LOCKS
END-EXEC.

Table 7-1 provides a brief description of each part of the SAVEPOINT syntax.

Table 7-1. Savepoint Syntax

Syntax

Description

svptname

Savepoint identifier that names the savepoint.

UNIQUE

Specifies that the application program cannot reuse this savepoint name within the UR. An error occurs if a savepoint with the same name as svptname already exists within the UR. If you do not use UNIQUE, then the application can reuse this savepoint name within the UR.

ON ROLLBACK RETAIN CURSORS

This option specifies that any cursors opened after the savepoint is set are not tracked, and thus are not closed upon rollback to the savepoint. Even though these cursors do remain open after rollback to the savepoint, they may not be useable.

ON ROLLBACK RETAIN LOCKS

This option specifies that any locks that are acquired after the savepoint is set are not tracked and therefore are not released upon rollback to the savepoint.

Restoring to a Savepoint

In order to restore to a savepoint, the ROLLBACK statement is used with the TO SAVEPOINT clause. The example below shows pseudocode for an application that sets and restores to a savepoint. The example (an IBM-supplied example) application makes airline reservations on a preferred date, and then makes hotel reservations. If the hotel is unavailable, the application then rolls back the airline reservations and repeats the process for a next-best date. Up to three dates are tried.

EXEC SQL SAVEPOINT START_AGAIN UNIQUE
            ON ROLLBACK RETAIN CURSORS;
   Check SQL code;
   Do i = 1 to 3 UNTIL got_reservation;
      Book_Air (dates(i),ok);
      If ok then
         Book_Hotel(dates(i),ok);
      If ok then
         got_reservations
      Else
         EXEC SQL ROLLBACK TO START_AGAIN;
      End loop;
EXEC SQL RELEASE SAVEPOINT START_AGAIN;

The ROLLBACK statement with the new TO SAVEPOINT option backs out data and schema changes that were made after a savepoint. This can be imbedded. The skeleton syntax is as follows:

EXEC SQL
ROLLBACK WORK
TO SAVEPOINT svptname
END-EXEC.

In the skeleton syntax, ROLLBACK WORK rolls back the entire UR. All savepoints that were set within the UR are released. TO SAVEPOINT specifies that the rollback of the UR occurs only to the specified savepoint. If there is no savepoint name specified, rollback is to the last active savepoint. svptname is the name of the savepoint to roll back to.

In the following example, the ROLLBACK TO SAVEPOINT statement will cause the rollback to savepoint two, which will cause the second and third sets of application code to be rolled back.

EXEC SQL
SAVEPOINT ONE ON ROLLBACK RETAIN CURSORS;
END-EXEC

First application code set ..

EXEC SQL
SAVEPOINT TWO ON ROLLBACK RETAIN CURSORS;
END-EXEC.

Second application code set..

EXEC SQL
SAVEPOINT THREE ON ROLLBACK RETAIN CURSORS;
END-EXEC.

Third application code set..

EXEC SQL
RELEASE SAVEPOINT THREE;
END-EXEC.

EXEC SQL
ROLLBACK TO SAVEPOINT;
END-EXEC.

If the named savepoint does not exist, an error will occur. Data and schema changes made after the savepoint was set are backed out. Because changes made to global temporary tables are not logged, they are not backed out, but a warning is issued A warning is also issued if the global temporary table is changed and there is an active savepoint. None of the following items are backed out:

  • opening or closing of cursors

  • changes in cursor positioning

  • acquisition and release of locks

  • caching of the rolled back statements

Savepoints that are set after the one to which rollback is performed are released. The savepoint to which rollback is performed is not released. For example, in the following scenario, the ROLLBACK TO SAVEPOINT TWO statement causes savepoint three to be released, but not savepoint two.

EXEC SQL
SAVEPOINT ONE ON ROLLBACK RETAIN CURSORS;
END-EXEC.

First application code set ..

EXEC SQL
SAVEPOINT TWO ON ROLLBACK RETAIN CURSORS;
END-EXEC.

Second application code set..

EXEC SQL
SAVEPOINT THREE ON ROLLBACK RETAIN CURSORS;
END-EXEC.

Third application code set..

EXEC SQL
ROLLBACK TO SAVEPOINT TWO;
END-EXEC.
Releasing a Savepoint

Releasing a savepoint involves the use the RELEASE SAVEPOINT statement. You cannot rollback to a savepoint after it is released. There is just a small amount of overhead to maintain a savepoint, but it is more important to release them because any outstanding savepoints will block any system-directed connections to remote locations. After it is no longer required for an application to roll back to that savepoint, you should release it. The following example releases a savepoint named START_AGAIN and all the savepoints that were subsequently set by the transaction.

EXEC SQL
RELEASE SAVEPOINT START_AGAIN;
END-EXEC.

The RELEASE SAVEPOINT statement releases the named savepoint and any subsequently established savepoints. Once a savepoint has been released, it is no longer maintained and rollback to the savepoint is no longer possible. The syntax is as follows:

EXEC SQL
RELEASE
      TO
SAVEPOINT svptname
END-EXEC.

The Svptname is the savepoint identifier that identifies the savepoint to be released. If there is no named savepoint, an error will occur. The named savepoint and all the savepoints that were subsequently established by the transaction are released.

Savepoints in a Distributed Environment

In a distributed environment, you can set savepoints only if you use DRDA access with explicit CONNECT statements. If you set a savepoint and then execute a SQL statement with a three-part name, a SQL error occurs.

The site at which a savepoint is recognized depends on whether the CONNECT statement is executed before or after the savepoint is set. For example, if an application executes the statement SET SAVEPOINT C1 at the local site before it executes a CONNECT TO S1 statement, savepoint C1 is known only at the local site. If the application executes CONNECT TO S1 before SET SAVEPOINT C1, the savepoint is known only at site S1. For more information on the CONNECT statement, refer to Chapter 10, "Accessing Distributed Data."


063 - Global Transactions

Chapter 7. Application Program Features

Global Transactions

Global transactions allow for several UOWs to share locks if they are all participants in a unit of work. The larger unit of work is referred to as a global transaction. This provides a way to avoid deadlocks between transactions. There are several reasons that you may want to consider combining several transactions into a large transaction. For example, this may be an option if you are adding OO (object-oriented) interfaces on existing transactions.

This simply is an extension of the distributed unit of work and adds the ability to share locks. It supports IMS, RRS (Recoverable Resource Services), and DDF (Distributed Data Facility) transactions. These transactions will be identified via a tokenglobal transaction ID or XID. All of the URs in a global transaction must run on the same subsystem, and each part can see uncommitted updates of other parts.

The sharing of locks is limited to normal transaction locks and an explicit LOCK TABLE statement, or partition key updates could still cause deadlocks or timeouts. There are many design issues to consider prior to the use of global transactions, and there are also additional risks and exposures.


064 - Global Temporary Tables

Chapter 7. Application Program Features

Global Temporary Tables

There are occasions when a table does not need to exist for a long period of time. For example, a table may be needed to act as a staging area for data for use by a program. Temporary tables can be used to accommodate this. There are two types of temporary tables: created or declared.

Created Temporary Tables

Created temporary tables (CTTs) can help improve performance in many different ways. Any time there is repetitive SQL being used to return a result set, producing exactly the same result each time, a CTT might provide benefit. A subquery that is used more than once is a prime example. It would be better to issue the subquery once, storing the result set rows in the CTT, and use the CTT in subsequent subqueries. The biggest advantage of CTTs is that no logging is done, since no recovery is possible. However, no indexing is done either, so a tablespace scan will always be used as the access path. Also, either an SQL UPDATE or DELETE can make no modifications to the data in the CTT. Only INSERTs are allowed. The CTT will exist for the duration of the unit of work, and will be automatically deleted when a commit is issued unless the table is used in a cursor definition using CURSOR WITH HOLD.

CTTs are very useful for stored procedures. For example, global temporary tables can be used as a holding area for nonrelational or non-DB2 data such as data extracted from VSAM files. The data will be held for the duration of the unit of work and can be referenced in SQL statements. This is particularly valuable when a left or full outer join is required using one DB2 table and one non-DB2 table (for example, using VSAM data). An INSERT statement can load the temporary table with the VSAM data, and then the following SQL statement can perform the outer join:

EXEC SQL
SELECT * FROM T1 LEFT JOIN global-temp-name ON join predicates
END-EXEC.

This technique logically fits in a stored procedure so that any other process that needs the result can just execute it. The benefit is that the DB2 join algorithms, instead of a homegrown program, are used to perform the outer join.

Another major benefit of CTTs is to use them when a materialized set is present for a result set, a view, or a table expression, and the materialized set needs to be used more than once.

Sometimes it is necessary to use a workaround in SQL due to the 15-table limit for an SQL statement. CTTs can be used to hold the results of some of the tables prior to a later statement, which would combine the global temporary table to the remaining tables.

The only access path available against a CTT is a tablespace scan, so keep the size of the scan in mind when doing performance analysis. When a CTT is used in a join, the access path will generally be a merge scan join that might require sorting the CTT.

A CTT can be held longer than a unit of work when it is used inside a cursor definition that is defined WITH HOLD.

Creating a Temporary Table

A created temporary table is created in the same manner as a normal table, through Data Definition Language (DDL), except that it is not physically created in a tablespace. These tables cannot be created with default values, and they cannot have unique, referential, or check constraints defined for them. The following example shows the creation of a created temporary table that will hold rows containing an amount and a date.

CREATE GLOBAL TEMPORARY TABLE SUMMARY
AMOUNT_SOLD DECIMAL(5,2) NOT NULL,
SOLD_DATE DATE NOT NULL)

An empty instance of the table is created when the first implicit or explicit reference is made to it in an SQL statement. In normal use, an insert would be the first statement issued. The temporary table exists only until the originating application commits, does a rollback, or terminates, unless the table is used in a cursor using the WITH HOLD option.

Determining How Often CTTs Are Materialized

CTTs are materialized in DSNDB07. If multiple global temporary tables are being continually materialized, you could run into a problem with the performance of all processes using DSNDB07 work files (e.g., sorting). In order to keep control over DSNDB07, you can monitor this materialization through DB2 traces.

Performance trace, class 8, IFCID 311 contains information about CTT materialization and cursor processing. Field QW0311CI shows if an instance of a temporary table was created in a work file. You can also see if a cursor was opened or closed. This will give you an idea of the amount of work occurring against the work file tablespace for temporary tables. If you find that there is a lot of activity occurring and feel it may be causing problems, you can also use the trace fields to determine what queries or programs are causing the materialization.

0017 QW0017TT  'TT'=TEMPORARY TABLE SCAN.

Declared Temporary Tables

Declared temporary tables (DTTs) give us the ability to declare a temporary table for use in a program. The DECLARE GLOBAL TEMPORARY TABLE statement defines a temporary table for the current session, not just for a UOW. The table description does not appear in the DB2 catalog. It is not persistent and cannot be shared (unlike a CTT).

This statement can be embedded in an application program or issued through the use of dynamic SQL statements. It is an executable statement that can also be dynamically prepared. Each session that defines a declared global temporary table of the same name has its own unique instantiation of the temporary table. When the session terminates, the temporary table is dropped. With DTTs, some of the locking, DB2 catalog updates, and DB2 restart forward and backward log recoveries that are associated with persistent tables are avoided. No authority is required to issue the DECLARE GLOBAL TEMPORARY TABLE statement, but there will be an authority required to use the new user temporary tablespace where the table will be materialized.

DTTs can be useful for applications that need to extract data from various sources and use them in SQL joins, or for data that needs to be used repetitively or kept separate from other online transaction processing (OLTP) processes. They can also be used as staging areas for data that comes from various sources so that the data can be manipulated before it is stored permanently in regular tables.

Following are a couple of examples of the syntax for DTTs.

EXEC SQL
DECLARE GLOBAL TEMPORARY TABLE SESSION.CERTTEST
    LIKE DB2USER1.TEST
INSERT INTO SESSION.CERTEST
    SELECT * FROM DB2USER1.TEST
END-EXEC.

EXEC SQL
DECLARE GLOBAL TEMPORARY TABLE SESSION.CERTEST
    AS
    (SELECT * FROM DB2USER1.TEST)
DEFINITION ONLY
END-EXEC.
Usage Considerations

These DTTs could be used as a way to temporarily hold or sort data within a program. DTTs are useful for relational online analytical processing (ROLAP) and multidimensional online analytical processing (MOLAP) queries for warehouse tools and as staging area for IMS of VSAM data so it is SQL- and ODBC-accessible. The word SESSION must be the qualifier for a DTT and can be named explicitly in the table name or can be in the QUALIFIER BIND option on the plan or package.

Only Undo records are logged and the full range of Data Manipulation Language (DML) (INSERT, UPDATE, SELECT, DELETE) can be performed on them. DTTs are supported by rollback to savepoint or last commit point. The table exists until thread termination, or if thread reuse is being used, it will exist until it is implicitly dropped (which may or may not be desirable, depending on the application).

No locks are taken (PAGE, ROW, or TABLE) on DTTs; however, there are locks taken on tablespace and DBD in share mode. They also do not require a declared cursor to hold rows across commits.

Static SQL referencing a DTT will be incrementally bound at runtime. The cost associated with a DTT is equivalent to the cost of executing a dynamic SQL statement. High-volume transaction applications need careful evaluation when planning to use DTTs.

NOTE

Any dynamic SQL statements that reference DTTs will not be able to use the dynamic SQL cache.

There are some restrictions when using DTTs. They do not support the following:

  • LOBs or ROWIDs

  • Referential integrity

  • Use in a CREATE TABLE LIKE statement

  • Sysplex Query Parallelism

  • Dynamic SQL Caching

  • ODBC/JDBC functions that rely on the catalog definitions

  • Thread reuse for DDF pool threads

  • Use within triggers

TEMP Database

DTTs are not materialized in DSNDB07, but rather in a segmented TEMP tablespace. There must be a TEMP database created prior to the creation of the DTTs. This database is not sharable across data sharing members, each member must have own. There will need to be several segmented tablespaces created. DB2 will decide where tables are created. PUBLIC will automatically have authority to create DTTs in these tablespaces.

The DTTs cannot span tablespaces. This fact does give you the ability to have small tablespaces and be able to control the size of any DTT that is created. There may be a need to have different tablespaces for 4K, 8K, 16K, and 32K pages. DB2 will choose the appropriate one, and if one does not exist, the DECLARE fails.

NOTE

It is recommended to use the same sized pages for each tablespace and spread the datasets across several volumes.

NOTE

It is important to size this database accordingly to accommodate growth and concurrent transactionsthose transaction that are all using DTTs at a given point in time


065 - Fetch for Limited Rows

Chapter 7. Application Program Features

Fetch for Limited Rows

During cursor processing, the ability to tell DB2 to only fetch the first or top n rows is a requirement in many applications. There are ways in SQL and the application program to do this; however, they are not the most efficient. For example, a query could be written as follows:

EXEC SQL
SELECT *
  FROM EMPLOYEE A
  WHERE 5 >= (SELECT COUNT(*)
     FROM EMPLOYEE B
     WHERE B.EMPNO <= A.EMPNO)
END-EXEC.

However, this results in terrible performance, because DB2 will have to read rows proportional to square of the numbers of table rows.

With the FETCH FIRST clause of a fullselect, DB2 has this functionality with improved performance, as the clause sets a maximum number of rows that can be retrieved through a cursor. The application specifies that it does not want to retrieve more than some fixed number of rows, regardless of how many rows qualified for the result set.

FETCH FIRST and OPTIMIZE FOR

The OPTIMIZE FOR n ROWS clause, which provides additional information to the optimizer about the intent, is different from the FETCH FIRST clause. The OPTIMIZE FOR clause could allow the entire answer set to be retrieved. In contrast, the FETCH FIRST n ROWS ONLY stops processing after the specified number of rows. This provides direct control to the application programmer over the size of the result table. For example, an implementation limit on the number of rows displayed for an online screen can now be enforced. The following example shows the use of the FETCH FIRST n ROWS ONLY clause with the OPTIMIZE FOR n ROWS.

EXEC SQL
DECLARE FIRST_FIVE CURSOR FOR
  SELECT EMPNO
  FROM EMPLOYEE
  ORDER BY EMPNO
  FETCH FIRST 5 ROWS ONLY
  OPTIMIZE FOR 5 ROWS
END-EXEC.

Using FETCH FIRST for Existence Checking

The FETCH FIRST clause is valid for singleton SELECTs, whereas the OPTIMIZE clause is not. This makes the FETCH FIRST clause a perfect solution for optimal existence checking. It will perform a maximum of only one fetch to determine existence, and there is no internal second fetch for the 811 return code required. It automatically implies OPTIMIZE FOR 1 ROW and therefore discourages sequential prefetch, multi-index access and list prefetch. This technique requires minimal coding to support singleton select, and no cursor logic is required. It can also be coded within an application program or dynamically (Query Management Facility, DSNTEP2, etc.). The following is an example of FETCH FIRST for existence checking:

EXEC SQL
  SELECT 1 INTO :hv-check
  FROM TABLE
  WHERE COL1 = :hv1
  FETCH FIRST 1 ROW ONLY
END-EXEC.


066 - Identity Columns

Chapter 7. Application Program Features

Identity Columns

Identity columns provide a way to have DB2 automatically generate unique, sequential, and recoverable values for each row in a table. The new identity column is defined with the AS IDENTITY attribute provided in column definition. Each table can have only one identity column defined to it. Identity columns are ideally suited for the task of generating unique primary key values such as employee number, order number, item number, or account number. Identity columns can also be used to alleviate concurrency problems caused by application-generated sequence numbers.

An identity column value can be always generated by DB2 or by default. DB2 always generates the column value and guarantees its uniqueness for identity columns defined as GENERATED ALWAYS. Applications cannot provide an explicit value for a column defined this way. If an identity column is defined as GENERATED BY DEFAULT, an application can provide an explicit value for the column, but if absent, DB2 will generate a value. But DB2 will guarantee the uniqueness of the value only if it is always generated by DB2. The use of GENERATED BY DEFAULT is intended for data propagation (copying the contents of an existing table or unloading and reloading a table).

Identity column counters are increased or decreased independently of the transaction. There may be gaps between two numbers that are generated, because several transactions may concurrently increment the same identity counter by inserting rows into the same table. Exclusive locks should be taken on the tables that contain identity columns if an application must have a consecutive range of numbers. Gaps in the generated identity column numbers can also appear if a transaction that generated a value for the identity column gets rolled back or a DB2 subsystem that has a range of identity values cached terminates abnormally. As a general rule, gaps in identity values should not cause a great deal of concern (unless you are still using preprinted forms). Additional properties of identity column values include:

  • Values must have a numeric data type.

  • SMALLINT, INTEGER, or DECIMAL with a scale of zero (or a distinct type based on one of these types).

  • Can specify the difference between consecutive values.

  • Counter value for the identity column is recoverable from the DB2 log.

  • Identity column values are incremented across multiple members in a data sharing group.

  • Identity column values can be cached for better performance.

The CREATE TABLE, ALTER TABLE, INSERT, and UPDATE have all been enhanced to support the identity columns. The following gives a brief description of these changes as well as some examples.

CREATE and ALTER Table

The AS IDENTITY attribute can be specified as part of the table definition on the CREATE TABLE statement or when adding a column with the ALTER TABLE statement to create an identity column. In addition, when a table is being created LIKE another table that contains an identity column, a new option on the LIKE clause can be used to specify whether the identity column attributes are inherited. A skeleton example (not exact syntax) of the new syntax is as follows.

COLUMN-DEFINITION:
 column-name  data-type  column-options
COLUMN-OPTIONS:
   NOT NULL
   UNIQUE
   PRIMARY KEY
   FIELDPROC
   references clause
   check constraint
   generated column spec
GENERATED COLUMN SPEC:
WITH
DEFAULT default clause
GENERATED ALWAYS
    BY DEFAULT identity spec
IDENTITY SPEC:
AS IDENTITY
    START WITH 1|n
    INCREMENT BY 1|n
CACHE n
NO CACHE
LIKE-clause (CREATE TABLE)
 LIKE  table-name
       view-name
INCLUDING IDENTITY column attributes

Table 7-2 describes the values used for identity column definition.

Table 7-2. Identity Column Values

Value

Description

GENERATED

DB2 generates values for the column. This column must specify GENERATED if the column is to be considered an identity column (or if the data type is a ROWID or a distinct type that is based on a ROWID).

ALWAYS

DB2 will always generate a value for the column when a row is inserted into the table.

BY DEFAULT

DB2 generates a value for the column when a row is inserted into the table unless a value is specified. This is recommended only when using data propagation.

AS IDENTITY

Specifies that the column is an identity column for the table. A table can have only one identity column. AS IDENTITY can be specified only if the data type for the column is an exact numeric type with a scale of zero (SMALLINT, INTEGER, DECIMAL with a scale of zero or a distinct type based on one of these types). An identity column is implicitly not null.

START WITH n

This is a numeric constant that provides the first value for the identity column. The value can be a positive or negative value that could be assigned to the column. There are no nonzero digits allowed to the right of the decimal point. Default is 1.

INCREMENT BY n

This is a numeric constant that provides the interval between consecutive values of the identity column. This value can be any positive or negative value that is not 0, and the default is 1. With a positive value, the sequence of values for the identity column will ascend, and if it is negative, the sequence of identity column values will descend.

CACHE

Indicates whether or not preallocated values will be kept in memory. This will help improve performance for inserting rows into a table that has an identity column.

CACHE n

Provides the number of values of the identity column sequence that DB2 preallocates and keeps in memory. The default is 20. If a system fails, all cached identity column values will never be used. The value specified for CACHE also represents the maximum number of identity column values that may be lost during a system failure. With a data sharing environment, each member has its own range of consecutive values to use. For instance, if using CACHE 30, DB2T may get values 1 to 30, and DB2U may use values 31 to 60. The values that are assigned might not be in the order in which they are requested if transactions from different members generate values for the same identity column.

NO CACHE

Caching is not to be used. Use NO CACHE if you need to guarantee that the identity values are generated in the order in which they are requested for nonaffinity transactions in a data sharing environment.

CYCLE

Specifies whether the identity column should continue to generate values after reaching either the maximum or minimum value of the sequence. If the column values are ascending, it will start with the lowest value. If the column values are descending, it will start with the highest value. The MAXVALUE and MINVALUE are used to determine these ranges. Note that when CYCLE is in effect, duplicate values can occur. If a unique index exists, an error will occur.

MAXVALUE

Specifies the maximum value that can be generated for the identity column. Value can be positive or negative, but must be greater than the MINVALUE.

MINVALUE

Specifies the minimum value that is generated for the identity column. Can be positive or negative, but must be less than the MAXVALUE.

LIKE-clause

Create table like (columns/attributes) another table. For an identity column, the newly created table will inherit only the data type of the identity column. No other column attributes are inherited unless the INCLUDING IDENTITY clause is used.

INCLUDING IDENTITY COLUMN ATTRIBUTES

Used to allow the new table (created by LIKE) to inherit all of the column attributes of the identity column.

There are some restrictions to using identity columns. They cannot be specified on a table that has an edit procedure defined. An identity column cannot be defined with the FIELDPROC clause or the WITH DEFAULT clause. When updating an identity column, you cannot update the value of an identity column that is defined as GENERATED ALWAYS. If you are doing an ALTER table to add an identity column to a table that is not empty, the tablespace that contains the table is placed in the REORG pending state. When the REORG utility is executed, DB2 will generate the values for the identity column for all existing rows and the REORG pending status will be removed. The values are guaranteed to be unique, and their order is determined by the system.

A quick creation of a table with an identity column is as follows:

CREATE TABLE ACCOUNT_TRANS
     (ACCOUNT_NO     INTEGER GENERATED ALWAYS AS IDENTITY,
      TYPE         CHAR(4),
      LAST_NAME    CHAR(40),
      BALANCE      DECIMAL(8,2)
      DATE1         DATE)
IN ACCTDB.ACCTTS

This will create an ACCOUNT_TRANS table with an identity column named ACCOUNT_NO. The identity column is defined so that DB2 will always generate the values for the column. It will use the default (1) for the first value to be assigned and for the incremental difference between the subsequently generated consecutive numbers.

INSERTs and UPDATEs

The DEFAULT keyword can be used in the VALUES clause for identity columns. This allows DB2 to generate the value to be inserted into the column.

EXEC SQL
  INSERT INTO ACCOUNT_TRANS (ACCOUNT_NO, TYPE, LAST_NAME)
  VALUES (DEFAULT, :type, :lname)
END-EXEC.

DB2 always generates the value for an identity column that is defined as GENERATED ALWAYS. Even if you specify a value to insert, DB2 will either issue an error or ignore the value. DB2 will ignore the value and generate a value for insertion if the OVERRIDING USER VALUE clause is used. Because the value is not used in the statement below, it will produce an error.

EXEC SQL
  INSERT INTO ACCOUNT_TRANS (ACCOUNT_NO, TYPE, LAST_NAME)
   VALUES (:account, :type, :lname)
END-EXEC.

DB2 will use a specified value if the identity column is defined as GENERATED BY DEFAULT. But DB2 will not verify the uniqueness of the value, and it might be a duplicate of another value in the column, if you do not have a unique index defined on the column.

The rules for an insert with a subselect are similar to those for an insert with a VALUES clause. If you want the value implicitly specified in the column list to be inserted into a table's identity column, the column of the table that the data is being selected from must be defined as GENERATED BY DEFAULT. If you want to have DB2 ignore the value and insert a generated value into the identity column of the table being inserted into, the identity column of the table being selected from must be defined as GENERATED ALWAYS, and the INSERT statement must include the OVERRIDING USER VALUE clause. The following is an example of this clause.

EXEC SQL
  INSERT INTO ACCOUNT_TRANS OVERRIDING USER VALUE
  SELECT * FROM ACCOUNT_UPDT;
END-EXEC.

Updates are allowed on a value in an identity column, but only if the identity column is defined as GENERATED BY DEFAULT. DB2 does not verify the value to guarantee uniqueness during the update. You cannot make updates to identity columns defined with GENERATED ALWAYS.

You can find the last column number generated by using the following:

EXEC SQL
SET :HV = IDENTITY_VAL_LOCAL()
EXEC SQL.

The result will be returned as DECIMAL(31,0). If a commit or rollback occurred since the insert, a null will be returned. It is recommend you store the value after the insert and check return code checking.

Summary

In this chapter we looked at the various features that can be used in a DB2 application program. We looked at how a unit of work is defined and how to use commits, rollbacks, and savepoints to protect the integrity of the data being manipulated by the program. Other features such as temporary tables and identity columns were looked at in terms of how to make use of them in a program. Some coding techniques were also examinedsuch as FETCH FIRST n ROWSand different usages of this feature were also discussed. Many of these features can be utilized in our application program for enhanced functionality and optimal performance.

Additional Resources

IBM DB2 Administration Guide SC26-9931

IBM DB2 Application Programming and SQL Guide SC26-9933

IBM DB2 SQL Reference SC26-9944


067 - Chapter 8. Stored Procedures

Part 3. Developing Applications

Chapter 8. Stored Procedures

  • Benefits

  • Writing Stored Procedures

  • Defining Stored Procedures

  • Execution Environment

  • SQL Procedures

  • Stored Procedure Builder


068 - Stored Procedures

Chapter 8. Stored Procedures

Stored Procedures

A stored procedure is essentially a program that is stored and executed within the control of the DBMS. Some DBMS products limit stored procedures to a subset of SQL functionality. DB2 implements stored procedures as externally compiled programs that run within specialized DB2 address spaces.

All DB2 stored procedures are compiled programs stored in a load library available at the DB2 server. The DB2 server can be either the local DB2 subsystem or a remote DB2 subsystem. These programs can execute SQL statements, connect to other DB2 servers, and retrieve data from non-database sources. A stored procedure typically contains two or more SQL statements and some manipulative or logical processing in a host language. A client application program uses the SQL CALL statement to invoke a stored procedure.

EXEC SQL
CALL MYSP (:parm1, :parm2, :parm3)
END-EXEC.


069 - Benefits

Chapter 8. Stored Procedures

Benefits

One of the main reasons for using stored procedures is to reduce the network traffic in a distributed environment caused by client application programs that execute many remote SQL statements. Remote SQL statements can create many network send and receive operations to the server. A stored procedure can encapsulate many of the application's SQL statements into a single message to DB2, thus reducing network traffic.

Another reason for using stored procedures is to encapsulate a business function into a single module, coded once, and stored at the server for all processes to use. (See Figure 8-1.)

Figure 8-1. Stored procedure network improvements.

Additional Benefits

Some of the additional benefits of stored procedures include the following:

  • Simplifies development and maintenance.

  • Removes client dependency on database design at server.

  • Allows for the ability to dynamically change application programs.

  • Code is changed and refreshed at the server.

  • Client code does not need any change.

  • Client code can continue to run while changes are made.

  • Most of an application can exist at the server, not the client.

  • Less code needs to be globally changed at all client locations.

  • Reusable code.

  • Improved security.

  • Eliminates the need for end-user table authority.

  • Moves processing away from end users.

  • Provides the ability to access and update data that is not stored in DB2, such as virtual storage access method (VSAM) or information management systems (IMS) data.


070 - Writing Stored Procedures

Chapter 8. Stored Procedures

Writing Stored Procedures

The programs that implement stored procedures can be written in several different languages. The currently available languages are

  • C, C++

  • COBOL, OO COBOL

  • PL/1

  • Assembler

  • REXX

  • Java

  • SQL Procedure Language

The calling program and the stored procedure program can be implemented in different languages. For example, the client code could be COBOL and the stored procedure could be C. The connection is through the DB2 thread, so individual coding does not matter. With the exception of REXX, the stored procedure code is compiled and stored at the server. It can contain static SQL and dynamic SQL as well as IFI calls and can issue DB2 commands. The stored procedure program can also access external resources like VSAM files and even call CICS transactions.

Language Environment

The Language Environment product libraries are used to load and execute the stored procedures in one of the stored procedure address spaces. When you create a stored procedure, you may pass runtime options for Language Environment to use when the stored procedure is executed. Language Environment is used because it establishes a common runtime environment for the many different languages used for building stored procedures. It provides a consistent set of interfaces for essential runtime services. When using Language Environment, you do not have to specify language-specific libraries in the Job Control Language (JCL) procedure of the stored procedure address space.

Language Environment performs several functions for DB2. It hides the differences among programming languages, provides the ability to make a stored procedure resident in the stored procedures address space, and supports a large number of runtime options. Language Environment, along with the language compiler, provides the ability to debug your program using the IBM Debug Tool (also known as CODE/370). Stored procedure programs can be debugged in batch mode or interactively using the VisualAge Debugger.

Stored procedure programs should be created to be reentrant and reusable. This allows Language Environment to share a single copy of the program in memory. You can also use the STAY RESIDENT YES option, which will keep the program in memory for the next stored procedure call to avoid having to retrieve the module from disk again.

Parameters

Stored procedures usually have parameters that are passed in and possibly out. From the caller, the parameters are passed in the same manner as the commonly available CALL syntax:

EXEC SQL
   CALL SP1(:parm1, :parm2, :parm3);
END-EXEC.

Here, the parameters are host variables. Each parameter can be defined as input to the stored procedure, output from the stored procedure, or both input and output. The calling program must define appropriate storage areas for each parameter. Null values are passed by using indicator variables, as in

EXEC SQL
   CALL SP1(:parm1 :ind1, :parm2 :ind2, :parm3 :ind3);
END-EXEC.

The parameters uses by the stored procedure program must match the parameters defined on the CREATE PROCEDURE statement. DB2 cannot verify that the stored procedure program handles the correct number and type of parameters, so the programmer must make sure they do this correctly. DB2 will validate that the calling program specified the correct parameters as compared to the CREATE PROCEDURE statement and will set up the parameter list accordingly.

Parameter Style

The PARAMETER STYLE option of the CREATE PROCEDURE statement controls the number and method of passing parameters into the stored procedure program. To illustrate the differences in parameter passing, we'll use a stored procedure program written in C and defined as follows:

CREATE PROCEDURE YLA.TWOTOONE
                ( IN  PARM1 CHAR(8)
                , IN  PARM2 CHAR(5)
                , OUT PARM3 CHAR(80)
                )
                EXTERNAL NAME SP1
                LANGUAGE C
                PROGRAM TYPE SUB
                PARAMETER STYLE xxxxxxx
                COLLID TEST
                STAY RESIDENT YES
                WLM ENVIRONMENT WLMENV1;

PARAMETER STYLE GENERAL conforms to the way DB2 passed parameters to stored procedures prior to Version 6. In this style, the parameters passed to the program are essentially the same parameters that are defined in the CREATE PROCEDURE statement. The function declaration would look like this:

void sp1(char   parm1[9],      /* Input parm1 */
         char   parm2[6],      /* Input parm2 */
         char   parm3[81],     /* Output parm3 */
         )

Generally, C programs use a null-terminated character array to hold character string fields. DB2 handles the conversion from fixed-length character fields to null-terminated strings automatically for the stored procedure program. This is why the parameter fields in our example are one byte longer than the parameters specified on the CREATE PROCEDURE statement.

PARAMETER STYLE GENERAL WITH NULLS extends the GENERAL style to pass null indicators back and forth. The null indicators are input/output variables passed in an array, as in

void sp1(char   parm1[9],      /* Input parm1 */
         char   parm2[6],      /* Input parm2 */
         char   parm3[81],     /* Output parm3 */
         short* p_indparm[3]   /* Indicators for parms */
         )

The newest way of passing parameters, PARAMETER STYLE DB2SQL, is the recommended style for new stored procedures. It is the default for all languages except COMPJAVA and is invalid for REXX. With the DB2SQL specification, the parameters passed to the stored procedure program look like this:

void sp1(char   parm1[9],      /* Input parm1 */
         char   parm2[6],      /* Input parm2 */
         char   parm3[81],     /* Output parm3 */
         short* p_indparm1,    /* Indicator for parm1 */
         short* p_indparm2,    /* Indicator for parm2 */
         short* p_indparm3,    /* Indicator for parm3 */
         char   p_sqlstate[6], /* sqlstate to return */
         char   p_proc[28],    /* stored procedure name */
         char   p_spec[19],    /* specific name */
         char   p_diag[71],    /* message to return */
         )

As you can see, DB2SQL passes null indicators as separate variables and includes several additional parameters. The most significant of these are the p_sqlstate and p_diag parameters, which allow the stored procedure program to pass error information back to the caller without using additional output parameters. This simplifies error checking in the client programs. The actual values allowed for the returned SQLSTATE are:

  • 00000 returns SQLCODE 0

  • 01Hxx returns SQLCODE +462

  • 02000 returns SQLCODE +100

  • 38001 returns SQLCODE 487

  • 38002 returns SQLCODE 577

  • 38003 returns SQLCODE 751

  • 38004 returns SQLCODE 579

  • 38yxx returns SQLCODE 443

The p_diag message area is limited to 70 bytes, but the caller will not receive the entire string. DB2 takes the message text from this field and appends it to the SQLERRMC field in the SQLCA. DB2 includes other information at the beginning of the SQLERRMC field, so your message may be truncated.

The last available style is PARAMETER STYLE JAVA and is used only for Java stored procedures.

DBINFO

If desired, the stored procedure program can get an additional block of information from DB2 when called. This is requested by adding the DBINFO clause to the CREATE or ALTER PROCEDURE statement. When specified, DB2 passes the DBINFO block as the last parameter to the stored procedure program. This block contains

  • Location Name Length: The length of the location name

  • Location Name: The current location name

  • Authorization ID Length: The length of the authorization ID

  • Authorization ID: The authorization ID of the application

  • Subsystem Code Page: A structure that provides information about the CCSIDs and encoding scheme of the subsystem

  • Table Qualifier Length: The length of the table qualifier

  • Table Qualifier: The qualifier of the table that is specified in table name

  • Table Name Length: The length of the table name

  • Table Name: The name of the table for a user-defined function (UDF)

  • Column Name Length: The length of the column name

  • Column Name: The name of the column for a UDF

  • Product Information: Identifies the product on which the program executes. This field has the form DSNvvrrm, where

    - vv is a 2-digit version identifier

    - rr is a 2-digit release identifier

    - m is a 1-digit modification-level identifier

  • Operating System: Identifies the operating system on which the program that invokes the UDF runs

  • Number of Entries in Table Function Column List: Not used for stored procedures

  • Reserved Area: 24 bytes

  • Table Function Column List Pointer: Not used for stored procedures

  • Unique Application Identifier: Pointer to a string that uniquely identifies the application's connection to DB2

  • Reserved area: 20 bytes

Result Sets

In addition to returning parameters, a stored procedure can return one or more result sets. A result set is a relational table implemented as a cursor from which the client program can fetch rows. This way, an ODBC client can retrieve data from DB2 without the end user requiring privileges to the underlying tables. The user requires only execute privileges for the stored procedure.

Result sets from DB2 or nonrelational sources can be returned from either base tables or temporary tables to clients on any DB2 server. In order for a stored procedure to return result sets to clients, the following must be present:

  • The procedure needs to be defined for returning result sets.

  • Cursors must be opened using the WITH RETURN clause.

  • Distributed Relational Database Architecture (DRDA) client needs to support Level 3 result sets.

Client programs on platforms other than z/OS and OS/390 must use the ODBC/CLI interfaces. DB2 for z/OS and OS/390 implements enhancements that allow embedded SQL programs to also retrieve result sets. The following is a skeleton example of coding to receive a stored procedure result set when the application program is running on the same OS/390 server running the stored procedure.

EXEC SQL BEGIN DECLARE SECTION;
EXEC SQL RESULT_SET_LOCATOR VARYING locater1;
EXEC SQL END DECLARE SECTION;
EXEC SQL CALL SP1(:parm1, :parm2, ...);
EXEC SQL ASSOCIATE LOCATOR (:locater1) WITH PROCEDURE SP1;
EXEC SQL ALLOCATE CSR1 CURSOR FOR RESULT SET :locater1;
EXEC SQL FETCH CSR1 INTO :acctno, :billingno;

To allow for result sets to be returned from the stored procedure on the server, the WITH RETURN clause must be used in the cursor definition in the stored procedure, and the cursors may not be closed before the program ends. DB2 will return the rows in the result set from the opened cursors to the application program when the stored procedure ends. The following example shows the stored procedure code necessary to return the result set to the application code shown in the previous example.

EXEC SQL DECLARE SP_CSR1 CURSOR
                  WITH RETURN FOR
                SELECT ACCT_NO, BILLING_NO
                  FROM ORDER_TABLE
                 WHERE ITEM = :parm1;
EXEC SQL OPEN SP_CSR1;
RETURN;

When returning a result set from a stored procedure, care must be taken to avoid unintentionally closing the cursor. The cursor that the stored procedure opens will be closed if the unit of work (UOW) is terminated by a commit. This includes the commit generated internally by DB2 if the COMMIT ON RETURN option is specified during the creation of the stored procedure.

Dynamically Identifying Result Sets

From a design standpoint, most of the result sets will be of the previous variety. But there is a very powerful way to build totally dynamic stored procedures and still be able to interface with client processes. This can be very significant as we move forward with Web-enabled applications that are providing dynamic pages to a client.

The DESCRIBE PROCEDURE statement can be used to retrieve all the information about a procedure's result set. It is not required if result sets are predefined, and it cannot be dynamically prepared. It returns information that a "dynamic" client needs to use the result sets. The SQLDA contains the number of result sets, with one SQLVAR entry for each result set in the stored procedure. The SQLDATA(x) contains the result set locator value, and the SQLNAME(x) contains the server application's cursor name. This is invoked by using either of the following:

EXEC SQL DESCRIBE PROCEDURE SP1 INTO :sqlda
EXEC SQL DESCRIBE PROCEDURE :hv INTO :sqlda

The DESCRIBE CURSOR statement can be used to retrieve information about a cursor that was left open inside a stored procedure and returned as a result set. This works for any allocated cursor but is not needed for predefined result sets. This statement cannot be dynamically prepared. This feature returns information needed by dynamic clients, such as the name, length, and type for columns contained in a result set. The output SQLDA is very similar to what is produced from the DESCRIBE of a PREPAREd statement. This is invoked by using either of the following:

DESCRIBE CURSOR SPC1 INTO sqlda
DESCRIBE CURSOR :hv INTO sqlda

Unit of Work

Stored procedures execute using the same logical unit of work as the client program that executes the SQL CALL statement. Starting with Version 7, stored procedure programs can issue COMMIT statements. This commit will impact the entire unit of work, including any uncommitted changes made by the caller prior to invoking the stored procedure.

COMMIT ON RETURN

In addition to issuing a commit within a stored procedure program, the stored procedure can be defined to commit upon successful completion. This is done using the COMMIT ON RETURN clause on the CREATE or ALTER PROCEDURE statement.

The COMMIT ON RETURN option for stored procedures reduces network traffic and allows locking in a stored procedure to be performed on a predictable basis. Without COMMIT ON RETURN, the locks would be held until the client application issues the commit. The client commit could be some time later, and additional network messages would be required. With the COMMIT ON RETURN option, the locks are freed as soon as the stored procedure ends.

There are always tradeoffs. COMMIT ON RETURN cannot be used in nested stored procedures. The design of nested stored procedures, starting with V6, requires some delicate planning.

Issuing COMMITS

In the first instantiation of stored procedures, there was no commit at all. Then came the ability to COMMIT ON RETURN to reduce the network traffic. In V7 the ability to commit or roll back in stored procedure was added. This has implications only on new stored procedures or on careful enhancements to existing stored procedures and will not be needed in the majority of stored procedures that exist already, since they were written with the knowledge that a stored procedure was just a continuation of an existing thread. But with more movement to object-oriented programming, using stored procedures as one way of introducing classes and methods, this feature will have more use.

Nesting

Stored procedures and UDFs can be nested. This means that a stored procedure program can itself issue a SQL CALL statement or include a UDF within another SQL statement. Triggers can also call UDFs or stored procedures. With nesting, careful planning is required to avoid looping. DB2 has a limit of 16 nesting levels for triggers, UDFs, and stored procedures.

There are obvious impacts to nesting in resource consumption and the scope of special registers. When nesting stored procedures, the following list of DB2 special registers is saved when pushing deeper and restored when popping back up:

  • CURRENT DATE

  • CURRENT DEGREE

  • CURRENT PACKAGESET

  • CURRENT PATH

  • CURRENT RULES

  • CURRENT SERVER

  • CURRENT SQLID

  • CURRENT TIME

  • CURRENT TIMESTAMP

  • CURRENT TIMEZONE

  • CURRENT USER

And there are some very important limitations when nesting stored procedures:

  • Nesting between DB2-managed and Workload Manager (WLM)-managed address spaces is not allowed (another reason to move away from DB2-managed address spaces).

  • No COMMIT ON RETURN is executed when nested.

  • Query result sets are returned onto the previous nesting level.

Careful communication between the application programmers, database procedural programmers, system programmers, and database administrators in order to balance needs and make sure that unnecessary levels, trigger cascading, and looping cannot occur.


071 - Defining Stored Procedures

Chapter 8. Stored Procedures

Defining Stored Procedures

The following statement shows an example of creating a stored procedure. There are many options when creating stored procedures, but some of the main ones include a parameter list, the language, and its external program name. The actual definition is stored in the SYSIBM.SYSROUTINES catalog table, and the parameter definitions are stored in SYSIBM.SYSPARMS. The CREATE PROCEDURE statement creates a stored procedure.

CREATE PROCEDURE SYSPROC.MYSP1
      ( IN    PARM1  SMALLINT,
        INOUT PARM2  CHAR(10),
        OUT   CODE   INTEGER )
      EXTERNAL NAME 'CERTSP1'    -- Load module name
      LANGUAGE COBOL             -- language
      PARAMETER STYLE GENERAL    -- type of parameter list
      COLLID DB2SPS              -- collection ID
      ASUTIME LIMIT 2000         -- maximum amount of SUs allowed
      STAY RESIDENT YES          -- make memory resident
      DYNAMIC RESULT SETS 3      -- 3 result sets returned
      NOT DETERMINISTIC          -- different results with each call
      MODIFIES SQL DATA          -- Issues SQL
      WLM ENVIRONMENT MYAPPS     -- requires a WLM environment
      PROGRAM TYPE MAIN          -- main, not subprogram
      RUN OPTIONS('TRAP(ON)')    -- specifies the LE run options
      COMMIT ON RETURN NO        -- do not commit on exit

The ALTER PROCEDURE statement can be used to modify the options of a stored procedure.

ALTER PROCEDURE SYSPROC.MYSP1 STAY RESIDENT NO

The ALTER PROCEDURE command will take effect immediately if the stored procedure is not already active in the system. If the stored procedure is active, it will have to be stopped and restarted. If the stored procedure is running in a WLM environment, that environment should also be refreshed.

Removing Stored Procedures

Procedures are removed from the system by using the DROP PROCEDURE command, as in

DROP PROCEDURE MYSPAP RESTRICT

This will drop the stored procedure unless the rules identified by the required keyword RESTRICT hold true. RESTRICT prevents the procedure from being dropped if a trigger definition contains a CALL statement with the name of the procedure.

When a procedure is directly or indirectly dropped, all privileges on the procedure are also dropped. In addition, any plans or packages that are dependent on the procedure are made inoperative.

Schema Qualification

Stored procedure names are implicitly or explicitly qualified by a schema name. If no schema name is used to qualify the name, then it is qualified by the following rules:

  • If the CREATE PROCEDURE statement is embedded in a program, the schema name is the authorization ID specified in the QUALIFIER bind option when the plan or package was created or last rebound. If QUALIFIER was not specified, the schema name is the owner of the plan or package.

  • If the CREATE PROCEDURE statement is dynamically prepared, the schema name is the SQL authorization ID in the CURRENT SQLID special register.

When calling a stored procedure, the CURRENT PATH special register is used to identify unqualified procedure names. If no path is specified, the default path is used:

  1. SYSIBM

  2. SYSFUN

  3. SYSPROC

  4. value of CURRENT SQLID

NOTE

SYSFUN is a schema used for additional functions shipped from other servers in the DB2 product family. Although DB2 for OS/390 and z/OS does not have the SYSFUN schema, it can be useful to have SYSFUN in the path when doing distributed processing that involves a server that uses the SYSFUN schema.


072 - Execution Environments

Chapter 8. Stored Procedures

Execution Environments

Stored procedures on z/OS and OS/390 execute under the control of DB2. There are two execution environments for stored procedures:

  • DB2 Stored Procedure Address Space (DSNSPAS)

  • WLM-managed environments

Administration of stored procedures for either environment includes the use of the following commands:

  • START PROCEDURE and STOP PROCEDURE, which allow queuing options for callers to dynamically start and stop the ability to use or execute the stored procedure. It is possible to start or stop procedures with the SCOPE(GROUP) option for data sharing

  • DISPLAY PROCEDURE provides the ability to display the status of a stored procedure.

The START and STOP can be issued for individual stored procedures or can include wildcards to affect multiple procedures.

The DISPLAY PROCEDURE command will yield information about the status of any stored procedure currently started or executing, but does not display any information on the individual threads using the stored procedure. For that, the DISPLAY THREAD command must be used. Following is an example of the DISPLAY PROCEDURE command.

-DISPLAY PROCEDURE
DSNX940I -DSNX9DIS DISPLAY PROCEDURE REPORT FOLLOWS -
PROCEDURE   STATUS   ACTIVE    QUEUED   MAXQUE TIMEOUT WLM_ENV
APPL1       STARTED   1 0         0        0
APPL2       STARTED   1 0         0        0
APPL2       STARTED   0 1         2        0
APPL5       STOPREJ   0 0         0        0
APPL6       STOPABN   0 0         0        0
PROC1       STOPQUE   0 0         0        0
DSNX9DIS    DISPLAY  PROCEDURE   REPORT    COMPLETE

Stored Procedure Address Space (SPAS)

DSNSPAS is a single address space that is started by DB2 when it initializes. The address space is stopped by DB2 if a STOP PROCEDURE(*.*) command is issued, and it is restarted with a START PROCEDURE(*.*) command. All stored procedures that are associated with the DB2 established address space execute in that one address space. If one procedure fails, its can affect the others that are also executing in that address space.

Stored procedures in this environment execute at the priority of the address space. There is no support for two-phase commit when updating nonrelational data.

Stored procedures that execute in the SPAS environment use the Call Attach Facility (CAF) implicitly. The DSNALI interface module must be linked into the application load module, but the program must not make any DSNALI calls.

Workload Manager

While stored procedures can run in a DB2-establish SPAS, it is highly recommended that they execute in a WLM goal-mode application environment, because WLM can support multiple address spaces.

There can be many WLM-managed environments for each DB2 subsystem, each with its own JCL. This means that the stored procedure programs for different applications can execute in different environments. You can also create separate test and Q/A environments for the same application within the same subsystem, using different load libraries to allow for different levels of application code.

Stored procedures that execute in WLM-managed environments use the performance characteristics of the calling application. This provides a much more granular level of performance management than SPAS.

The impact of program failures is limited to the execution address space, reducing the likelihood of impacting other critical stored procedures. Stored procedures that execute in WLM-managed environments use the Recoverable Resource Manager Services Attachment Facility (RRSAF) implicitly. The DSNRLI interface module must be linked into the application load module, but the program must not make any DSNRLI calls. Two-phase commit is supported for any access to nonrelational data updates if the data is managed by RRSAF.

Program Type

Programs that run in WLM environments can be defined to execute as subprograms or main programs. Subprograms execute more efficiently, but must take care to clean up resources and close files. Specify PROGRAM TYPE SUB on the CREATE PROCEDURE statement and make sure the program is properly coded to execute as a subprogram. Programs that run as subprograms must be dynamically fetchable. For COBOL, there is no real difference between a main program and a subprogram. PL/I subprograms may not perform I/O. C programs must be defined as fetchable, as in the following:

#include <sqludf.h>
#pragma linkage(sprslt,fetchable)
void sprslt (const char   parmCreator[9]
            ,short      * pIndCreator
            ,char       p_sqlstate[6]
            ,char       p_proc[28]
            ,char       p_spec[19]
            ,char       p_diag[71]
            )
Managing WLM Environments

Administration of stored procedures, when being used in a WLM-managed address space, is under the control of WLM. The START and STOP PROCEDURE commands are the same but work a little differently. They stop and start the procedure, but do not cause the load module to be reloaded by DB2. To refresh a stored procedure load module, you must use the following command from the console:

VARY WLM,APPLENV=wlmenv,REFRESH

The WLM refresh command recycles all WLM address spaces that run with that environment. New environment address spaces are started and any new work is routed to the new address spaces. Threads executing in the existing address spaces are allowed to continue in the old environment before it is brought down.

The WLM environment as a whole can be stopped and restarted using the following commands:

VARY WLM,APPLENV=wlmenv,QUIESCE
VARY WLM,APPLENV=wlmenv,RESUME
Goal Mode

The WLM can execute in two different modes. Compatibility mode uses the older non-WLM system performance definitions to control task priorities. When running in compatibility mode, the executing of WLM environments must be controlled manually, and the number of environments is limited.

Goal mode uses rule-based guidelines to adjust task priorities. When running in goal mode, WLM automatically starts and stops application environments base on the definition for each environment. WLM will start a new address space if a stored procedure is executed and an existing environment is not already available or the running environments are busy executing other stored procedures. Goal mode execution is highly recommended for z/OS and OS/390 systems that will run DB2 stored procedures.


073 - SQL Procedure Language

Chapter 8. Stored Procedures

SQL Procedure Language

The SQL Procedure Language is a procedural language that was designed only for writing stored procedures and is available across the entire DB2 family, including the AS/400. It is based on the ANSI/ISO standard language SQL/PSM. Its major benefit is that users can create stored procedures very quickly, using a simple, easily understood language, without the headaches of precompilers, compilers, link editors, binding, and special authorizations. This is because stored procedures written using SQL Procedure Language will be mostly managed by DB2; this automates the process and allows programmers and users to simply write the logic and pass if off to DB2.

SQL procedures support multiple parameters for input, output, and returning output results sets to clients. SQL procedures are defined in the DB2 catalog, and the source can be stored there also. The following shows an SQL procedure that was created from a client workstation using the Stored Procedure Builder (SPB) tool. It accepts one input parameter and returns a result set to the client.

CREATE PROCEDURE DW.SQLProc1 ( IN gender char(6) )
    SPECIFIC DW.Genders       RESULT SETS 1
    LANGUAGE SQL
P1: BEGIN
    DECLARE gender_value CHAR(1);
    DECLARE bad_gender CONDITION FOR SQLSTATE '99001';
    CASE gender
       WHEN 'MALE' THEN
           SET gender_value = 'M';
       WHEN 'FEMALE' THEN
           SET gender_value = 'F';
       ELSE SIGNAL bad_gender;
    END CASE;
    -- Declare cursor
    DECLARE cursor1 CURSOR WITH RETURN FOR
        SELECT E.EMPNO, E.LASTNAME, E.HIREDATE, D.DEPTNO,
               D.DEPTNAME
        FROM DW.DEPARTMENT D, DW.EMPLOYEE E
        WHERE E.WORKDEPT = D.DEPTNO
          AND E.SEX = :gender_value
        ORDER BY E.WORKDEPT;
    -- Cursor left open for client application
    OPEN cursor1;
END P1

The language itself is primarily SQL (DML and DDL) with local variables, cursors, assignment statements, flow control, and signal/resignal conditions. The real difference with the SQL Procedure Language is how it becomes a stored procedure, since all the programmer does is write a CREATE PROCEDURE…LANGUAGE SQL…name: BEGIN…END name DDL statement. All the code is in the body of the create statement. The procedure body includes

  • Compound statements

  • Declaration statements

  • Assignment statements

  • Conditional statements

  • Iterative control structures

    - Loop

    - Repeat

    - While

  • Exception handling

  • Calling another stored procedure

The primary language statements that show the strength of this approach are

  • IF, CASE, and LEAVE

  • LOOP, REPEAT, and WHILE

  • FOR, CALL, and RETURN

  • GET DIAGNOSTICS

  • SIGNAL and RESIGNAL

Developing SQL Stored Procedures

DB2 implements SQL stored procedures as external C programs. The DB2 precompiler can take an SQL procedure as input and write out a C source module. An SQL procedure is created using one of the following three methods:

  • SPB

  • Directly invoking DSNTPSMP

  • Using JCL or CLIST to prepare

When an SQL procedure is built using the SPB tool (discussed later in this chapter), all the "code" is developed on the client workstation, and the completed procedure is passed to the DSNTPSMP stored procedure. DSNTPSMP is the OS/390 SQL Procedure Processor, a REXX stored procedure, and it is also fully customizable. This processor invokes the following steps:

  • SQL precompile

  • C precompile

  • C compile

  • Prelink

  • Link

  • Procedure definition

  • Bind

Once the procedure is built in this fashion, it is immediately executable. When using the other two methods for developing an SQL procedure, they basically just bypass the SPB and either directly invoke DSNTPSMP or execute the steps listed above under manual control.


074 - Stored Procedure Builder

Chapter 8. Stored Procedures

Stored Procedure Builder

The SPB (Figure 8-2) is a graphical Windows-based application that supports the rapid development of DB2 stored procedures written in either Java or SQL. It can work as a Microsoft Visual Studio plug-in, with Microsoft Visual Basic, with IBM VisualAge for Java, or standalone. It is used to generate a stored procedure, which DB2 will build into an external C language load module without requiring the user to log on to TSO. The SPB supports the entire DB2 family from a single development environment. There are many options, and we will examine each of them.

Figure 8-2. Using SPB to Create Stored Procedures

Using SPB, you can perform the following tasks:

  • Create new stored procedures.

  • Build stored procedures on local and remote DB2 servers.

  • Modify and rebuild existing stored procedures.

  • Run stored procedures to test the execution of installed stored procedures.

The SPB is implemented with Java, and all database connections are managed by using JDBC, so you can connect to any local DB2 alias or any other database for which you can specify a host name, port, and database name.

There is a stored procedure SmartGuide and SQL Assistant to help you develop stored procedures using the SPB. You launch the stored procedure SmartGuide from the Project window of the SPB. But the most important feature is that you can create stored procedures in Java and SQL. Creating stored procedures in Java and SQL produces stored procedures that are highly portable. You can use the code editor to modify the stored procedure so that it contains highly sophisticated stored procedure logic.

NOTE

Using the SPB is also a nice way to very rapidly develop a C program that can then be maintained and developed further simply as C source code.

When creating a stored procedure, you can choose to return a single result set, multiple result sets, or output parameters only. You can use the stored procedure SmartGuide to define input and output parameters for a stored procedure so that it receives values for host variables from the client application. When you finish building a stored procedure on a target database, the SPB process will drive the create procedure process in DB2, so there is nothing more to do other than use the SPB.

After successfully building a stored procedure, the SPB will allow you to work with existing stored procedures in order to modify, rebuild, run, or test a procedure. When you open a stored procedure, the stored procedure source code is displayed in the editor pane on the right side. The editor pane has a language-sensitive editor for stored procedures written by using Java. Colors are used to designate between user code, syntax, reserved words, and so on. To test a stored procedure using this tool, you can run it from within the SPB to make sure that it is correctly installed. Testing stored procedures this way makes programming a lot easier, and you know that the stored procedure is correctly installed on the DB2 database server. You can also drop a stored procedure or copy it to another database connection from within the SPB.


075 - Summary

Chapter 8. Stored Procedures

Summary

Stored procedures provide a powerful mechanism for storing application code on the database server. They improve performance while enhancing the security of the application and can support legacy data sources to DB2-based programs running both on the mainframe and other platforms.


076 - Additional Resources

Chapter 8. Stored Procedures

Additional Resources

General: www.ibm.com/software/data/db2

OS/390 z/OS SQL Procedures: www.ibm.com/software/data/db2/os390/sqlproc

DB2 Stored Procedure Builder: www.ibm.com/software/data/db2/os390/spb

Microsoft Add-ins: www.ibm.com/software/data/db2/udb/ide

IBM RedbookDeveloping Crossplatform DB2 Stored Procedures: SQL Procedures and the DB2 Stored Procedure Builder SG24-5485


077 - Chapter 9. Testing and Debugging Applications

Part 3. Developing Applications

Chapter 9. Testing and Debugging Applications

  • Establishing Test Environments

  • Testing in CICS, IMS, TSO

  • Testing/Debugging Stored Procedures

This chapter discusses the high-level basics of how to set up a test environment, test SQL statements, debug your programs, and read output from the precompiler. It is representative of some common techniques used by programmers to debug programs. Organizations and programmers usually develop their own methods for testing and debugging that work best for a particular environment.


078 - Establishing a Test Environment

Chapter 9. Testing and Debugging Applications

Establishing a Test Environment

This section describes how to design a test data structure and how to fill tables with test data.

Designing a Test Data Structure

When you test an application that accesses DB2 data, you should have DB2 data available for testing. To do this, you can create test tables and views. For information on the DDL to create tables and views, refer to Chapter 2.

Test Views of Existing Tables

If your application does not change a set of DB2 data and the data exists in one or more production-level tables, you might consider using a view of existing tables. To create a test table, you need a database and tablespace. Normally, a database administrator (DBA) can make sure that a database and tablespaces are available for your use.

If the data that you want to change already exists in a table, consider using the LIKE clause of CREATE TABLE. If you want others besides yourself to have ownership of a table for test purposes, you can specify a secondary ID as the owner of the table. For information about ownership and privileges, refer to Chapter 2.

If your location has a separate DB2 system for testing, you can create the test tables and views on the test system, then test your program thoroughly on that system. This chapter assumes that you do all testing on a separate system and that the person who created the test tables and views has an authorization ID of TEST. The table names are TEST.EMP, TEST.PROJ, and TEST.DEPT.

Analyzing Application Data Needs

To design test tables and views, first analyze your application's data needs.

  1. List the data your application accesses and describe how it accesses each data item. For example, suppose you are testing an application that accesses the DSN8710.EMP, DSN8710.DEPT, and DSN8710.PROJ tables. You might record the information about the data as shown below.

    Table or View Name

    Insert Rows?

    Delete Rows?

    Column

    Name Data Type

    Update Access?

    DSN8710.EMP

    No

    No

    EMPNO

    CHAR(6)

    LASTNAME

    VARCHAR(15)

    WORKDEPT

    CHAR(3)

    Yes

    PHONENO

    CHAR(4)

    Yes

    JOB

    DECIMAL(3)

    Yes

    DSN8710.DEPT

    No

    No

    DEPTNO

    CHAR(3)

    MGRNO

    CHAR (6)

    DSN8710.PROJ

    Yes

    Yes

    PROJNO

    CHAR(6)

    DEPTNO

    CHAR(3)

    Yes

    RESPEMP

    CHAR(6)

    Yes

    PRSTAFF

    DECIMAL(5,2)

    Yes

    PRSTDATE

    DECIMAL(6)

    Yes

    PRENDATE

    DECIMAL(6)

    Yes

  2. Determine the test tables and views you need to test your application.

Create a test table on your list when either:

  • The application modifies data in the table.

  • You need to create a view based on a test table because your application modifies the view's data.

To continue the example, create these test tables:

  • TEST.EMP, with the following format:

    EMPNO

    LASTNAME

    WORKDEPT

    PHONENO

    JOB

  • TEST.PROJ, with the same columns and format as DSN8710.PROJ, because the application inserts rows into the DSN8710.PROJ table.

To support the example, create a test view of the DSN8710.DEPT table. Because the application does not change any data in the DSN8710.DEPT table, you can base the view on the table itself (rather than on a test table). However, it is safer to have a complete set of test tables and to test the program thoroughly using only test data. The TEST.DEPT view has the following format:

DEPTNO

MGRNO

Obtaining Authorization

Before you can create a table, you need to be authorized to create tables and to use the tablespace in which the table is to reside. You must also have authority to bind and run programs you want to test. Your DBA can grant you the authorization needed to create and access tables and to bind and run programs.

If you intend to use existing tables and views (either directly or as the basis for a view), you need privileges to access those tables and views. Your DBA can grant those privileges. To create a view, you must have authorization for each table and view on which you base the view. You then have the same privileges over the view that you have over the tables and views on which you based the view. Before trying the examples, have your DBA grant you the privileges to create new tables and views and to access existing tables. Obtain the names of tables and views you are authorized to access (as well as the privileges you have for each table) from your DBA.

Creating a Comprehensive Test Structure

The following SQL statements shows how to create a complete test structure to contain a small table named SPUFINUM. The test structure consists of

  • A storage group named SPUFISG

  • A database named SPUFIDB

  • A tablespace named SPUFITS in SPUFIDB and using SPUFISG

  • A table named SPUFINUM within the tablespace SPUFITS

    CREATE STOGROUP SPUFISG
VOLUMES (user-volume-number )
VCAT DSNCAT ;

CREATE DATABASE SPUFIDB ;

CREATE TABLESPACE SPUFITS
IN SPUFIDB
USING STOGROUP SPUFISG ;

CREATE TABLE SPUFINUM
   (XVAL CHAR(12)NOT NULL,
   ISFLOAT FLOAT,
   DEC30 DECIMAL(3,0),
   DEC31 DECIMAL(3,1),
   DEC32 DECIMAL(3,2),
   DEC33 DECIMAL(3,3),
   DEC10 DECIMAL(1,0),
   DEC11 DECIMAL(1,1),
   DEC150 DECIMAL(15,0),
   DEC151 DECIMAL(15,1),
   DEC1515 DECIMAL(15,15))
IN SPUFIDB.SPUFITS ;

For details about each CREATE statement, refer to Chapter 2.

Filling the Tables with Test Data

There are several ways in which you can put test data into a table:

  • INSERT...VALUES (an SQL statement) puts one row into a table each time the statement executes.

  • INSERT...SELECT (an SQL statement) obtains data from an existing table (based on a SELECT clause) and puts it into the table identified with the INSERT statement.

  • The LOAD utility obtains data from a sequential file (a non-DB2 file), formats it for a table, and puts it into a table.

  • The DB2 sample UNLOAD program (DSNTIAUL) can unload data from a table or view and build control statements for the LOAD utility.

  • The UNLOAD utility can unload data from a table and build control statements for the LOAD utility.

Testing SQL Statements Using SPUFI

You can use SPUFI (an interface between ISPF and DB2) to test SQL statements in a TSO/ISPF environment. With SPUFI panels, you can put SQL statements into a dataset that DB2 subsequently executes. The SPUFI main panel has several functions that permit you to

  • Name an input dataset to hold the SQL statements passed to DB2 for execution.

  • Name an output dataset to contain the results of executing the SQL statements.

  • Specify SPUFI processing options.

SQL statements executed under SPUFI operate on actual tables (in this case, the tables you have created for testing). Consequently, before you access DB2 data,

  • Make sure that all tables and views your SQL statements refer to exist.

  • If the tables or views do not exist, create them (or have your DBA create them). You can use SPUFI to issue the CREATE statements used to create the tables and views you need for testing.


079 - Debugging Application Programs

Chapter 9. Testing and Debugging Applications

Debugging Application Programs

Many sites have guidelines regarding what to do if your program abends. The following suggestions are some common ones.

Debugging Programs in TSO

Documenting the errors returned from testing helps you investigate and correct problems in the program. The following information can be useful:

  • The application plan name of the program

  • The input data being processed

  • The failing SQL statement and its function

  • The contents of the SQLCA (SQL communication area) and, if your program accepts dynamic SQL statements, the SQLDA (SQL descriptor area)

  • The date and time of day

  • The abend code and any error messages

When your program encounters an error that does not result in an abend, it can pass all the required error information to a standard error routine. Online programs might also send an error message to the terminal.

Language Test Facilities

For information on the compiler or assembler test facilities, see the publications for the compiler or CODE/370. The compiler publications include information on the appropriate debugger for the language you are using.

The TSO TEST Command

The TSO TEST command is especially useful for debugging assembler programs. The following example is a command procedure (CLIST) that runs a DB2 application named MYPROG under TSO TEST, and sets an address stop at the entry to the program. The DB2 subsystem name in this example is DB4.

PROC 0
TEST 'prefix.SDSNLOAD(DSN)'CP
DSN SYSTEM(DB4)
AT MYPROG.MYPROG.+0 DEFER
GO
RUN PROGRAM(MYPROG)LIBRARY('L186331.RUNLIB.LOAD(MYPROG)')

ISPF Dialog Test is another option to help you in the task of debugging.

Debugging Programs in IMS

Documenting the errors returned from testing helps you investigate and correct problems in the program. The following information can be useful:

  • The program's application plan name

  • The input message being processed

  • The name of the originating logical terminal

  • The failing statement and its function

  • The contents of the SQLCA and, if your program accepts dynamic SQL statements, the SQLDA

  • The date and time of day

  • The program's PSB name

  • The transaction code that the program was processing

  • The call function (that is, the name of a DL/I function)

  • The contents of the PCB that the program's call refers to

  • If a DL/I database call was running, the SSAs, if any, that the call used

  • The abend completion code, abend reason code, and any dump error messages

When your program encounters an error, it can pass all the required error information to a standard error routine. Online programs can also send an error message to the originating logical terminal.

An interactive program also can send a message to the master terminal operator, giving information about the program's termination. To do that, the program places the logical terminal name of the master terminal in an express PCB and issues one or more ISRT calls.

Some sites run a BMP at the end of the day to list all the errors that occurred during the day. If your location does this, you can send a message using an express PCB that has its destination set for that BMP.

Batch Terminal Simulator (BTS)

The Batch Terminal Simulator (BTS) allows you to test IMS application programs. BTS traces application program DL/I calls and SQL statements, and simulates data communication functions. It can make a TSO terminal appear as an IMS terminal to the terminal operator, allowing the end user to interact with the application as though it were online. The user can use any application program under the user's control to access any database (whether DL/I or DB2) under the user's control. Access to DB2 databases requires BTS to operate in batch BMP or TSO BMP mode.

Debugging Programs in CICS

Documenting the errors returned from testing helps you investigate and correct problems in the program. The following information can be useful:

  • The program's application plan name

  • The input data being processed

  • The ID of the originating logical terminal

  • The failing SQL statement and its function

  • The contents of the SQLCA and, if your program accepts dynamic SQL statements, the SQLDA

  • The date and time of day

  • Data peculiar to CICS that you should record

    - Abend code and dump error messages

    - Transaction dump, if produced

Using CICS facilities, you can have a printed error record; you can also print the SQLCA (and SQLDA) contents.

Debugging Aids for CICS

CICS provides the following aids to the testing, monitoring, and debugging of application programs:

  • Execution (Command Level) Diagnostic Facility (EDF): EDF shows CICS commands for all releases of CICS. If you are using an earlier version of CICS, the CALL TO RESOURCE MANAGER DSNCSQL screen displays a status of .ABOUT TO EXECUTE... or .COMMAND EXECUTION COMPLETE.

  • Abend recovery: You can use the HANDLE ABEND command to deal with abend conditions, and the ABEND command to cause a task to abend.

  • Trace facility: A trace table can contain entries showing the execution of various CICS commands, SQL statements, and entries generated by application programs; you can have it written to main storage and, optionally, to an auxiliary storage device.

  • Dump facility: You can specify areas of main storage to dump onto a sequential dataset, either tape or disk, for subsequent offline formatting and printing with a CICS utility program.

  • Journals: For statistical or monitoring purposes, facilities can create entries in special datasets called journals. The system log is a journal.

  • Recovery: When an abend occurs, CICS restores certain resources to their original state so that the operator can easily resubmit a transaction for restart.

You can use the SYNCPOINT command to subdivide a program so that you only need to resubmit the uncompleted part of a transaction.

CICS Execution Diagnostic Facility

The CICS EDF traces SQL statements in an interactive debugging mode, enabling application programmers to test and debug programs online without changing the program or the program preparation procedure.

EDF intercepts the running application program at various points and displays helpful information about the statement type, input and output variables, and any error conditions after the statement executes. It also displays any screens that the application program sends, making it possible to converse with the application program during testing just as a user would on a production system.

EDF displays essential information before and after an SQL statement while the task is in EDF mode. This can be a significant aid in debugging CICS transaction programs containing SQL statements. The SQL information that EDF displays is helpful for debugging programs and for error analysis after an SQL error or warning.

Using this facility reduces the amount of work you need to do to write special error handlers.

The following code is an example of an EDF screen before it executes an SQL statement. The names of the key information fields on this panel are in boldface. The DB2 SQL information in this screen is as follows:

  • EXEC SQL statement type: This is the type of SQL statement to execute. The SQL statement can be any valid SQL statement, such as COMMIT, DROP TABLE, EXPLAIN, FETCH, or OPEN.

  • DBRM=DBRM name: The name of the database request module (DBRM) currently processing. The DBRM, created by the DB2 precompiler, contains information about an SQL statement.

  • STMT=statement number: This is the DB2 precompiler-generated statement number. The source and error message listings from the precompiler use this statement number, and you can use it to determine which statement is processing. This number is a source line counter that includes host language statements. A statement number greater than 32,767 displays as 0.

  • SECT=section number: The section number of the plan that the SQL statement uses.

    TRANSACTION:XC05 PROGRAM:TESTC05 TASK NUMBER:0000668 DISPLAY:00
STATUS:ABOUT TO EXECUTE COMMAND
CALL TO RESOURCE MANAGER DSNCSQL
EXEC SQL INSERT
DBRM =TESTC05,STMT =00368,SECT =00004
IVAR 001: TYPE=CHAR,LEN=00007,IND=000 AT X'03C92810'
DATA=X'F0F0F9F4F3F4F2'
IVAR 002:TYPE=CHAR,LEN=00007,IND=000 AT X'03C92817'
DATA=X'F0F1F3F3F7F5F1'
IVAR 003:TYPE=CHAR,LEN=00004,IND=000 AT X'03C9281E'
DATA=X'E7C3F0F5'
IVAR 004:TYPE=CHAR,LEN=00040,IND=000 AT X'03C92822'
DATA=X'E3C5E2E3C3F0F540E2C9D4D7D3C540C4C2F240C9D5E2C5D9E3404040'...
IVAR 005:TYPE=SMALLINT,LEN=00002,IND=000 AT X'03C9284A'
DATA=X'0001'

OFFSET:X'001ECE'LINE:UNKNOWN EIBFN=X'1002'

ENTER:CONTINUE
PF1 :UNDEFINED            PF2 :UNDEFINED          PF3 :UNDEFINED
PF4 :SUPPRESS DISPLAYS    PF5 :WORKING STORAGE    PF6 :USER DISPLAY
PF7 :SCROLL BACK          PF8 :SCROLL FORWARD     PF9 :STOP CONDITIONS
PF10:PREVIOUS DISPLAY     PF11:UNDEFINED          PF12:ABEND USER TASK
SQL Statements Containing Input Host Variables

The IVAR (input host variables) section and its attendant fields only appear when the executing statement contains input host variables.

The host variables section includes the variables from predicates, the values used for inserting or updating, and the text of dynamic SQL statements being prepared. The address of the input variable is AT 'nnnnnnnn'. Additional host variable information:

  • TYPE=data type: Specifies the data type for this host variable. The basic data types include character string, graphic string, binary integer, floating-point, decimal, date, time, and timestamp.

  • LEN=length: Length of the host variable.

  • IND=indicator variable status number: Represents the indicator variable associated with this particular host variable. A value of 0 indicates that no indicator variable exists. If the value for the selected column is null, DB2 puts a negative value in the indicator variable for this host variable.

  • DATA=host variable data: The data, displayed in hexadecimal format, associated with this host variable. If the data exceeds what can display on a single line, three periods (…) appear at the far right to indicate more data is present.

The following code shows an example of the first EDF screen displayed after the executing an SQL statement. The names of the key information fields on this panel are in boldface. The DB2 SQL information in this screen is as follows:

  • P.AUTH=primary authorization ID: The primary DB2 authorization ID.

  • S.AUTH=secondary authorization ID: If the resource access control facility (RACF) list of group options is not active, then DB2 uses the connected group name that the CICS attachment facility supplies as the secondary authorization ID. If the RACF list of group options is active, then DB2 ignores the connected group name that the CICS attachment facility supplies, but the value appears in the DB2 list of secondary authorization IDs.

  • PLAN=plan name: The name of plan that is currently running. The plan represents the control structure produced during the bind process and used by DB2 to process SQL statements encountered while the application is running.

  • SQL Communication Area (SQLCA): The SQLCA contains information about errors, if any occur. After returning from DB2, the information is available. DB2 uses the SQLCA to give an application program information about the executing SQL statements.

Plus signs (+) on the left of the screen indicate that you can see additional EDF output by using PF keys to scroll the screen forward or back. The OVAR (output host variables) section and its attendant fields only appear when the executing statement returns output host variables.

TRANSACTION:XC05 PROGRAM:TESTC05 TASK NUMBER:0000698 DISPLAY:00
STATUS:COMMAND EXECUTION COMPLETE
CALL TO RESOURCE MANAGER DSNCSQL
EXEC SQL FETCH        P.AUTH =SYSADM ,S.AUTH =
PLAN =TESTC05,DBRM =TESTC05,STMT =00346,SECT =00001
SQL COMMUNICATION AREA:
SQLCABC      =136                 AT X'03C92789'
SQLCODE      =000                 AT X'03C9278D'
SQLERRML     =000                 AT X'03C92791'
SQLERRMC     =''                  AT X'03C92793'
SQLERRP      ='DSN'               AT X'03C927D9'
SQLERRD(1-6)     =000,000,00000,-1,00000,000     AT X'03C927E1'
SQLWARN(0-A)     ='___________'                   AT X'03C927F9'
SQLSTATE =00000                   AT X'03C92804'
+OVAR 001:TYPE=INTEGER, LEN=00004,IND=000 AT X'03C920A0'
  DATA=X'00000001'

OFFSET:X'001D14'                  LINE:UNKNOWN EIBFN=X'1802'

ENTER:CONTINUE
PF1 :UNDEFINED            PF2 :UNDEFINED          PF3 :END EDF SESSION
PF4 :SUPPRESS DISPLAYS    PF5 :WORKING STORAGE    PF6 :USER DISPLAY
PF7 :SCROLL BACK          PF8 :SCROLL FORWARD     PF9 :STOP CONDITIONS
PF10:PREVIOUS DISPLAY     PF11:UNDEFINED          PF12:ABEND USER TASK

The attachment facility automatically displays SQL information while in the EDF mode. The following code is the remaining output from the example.

TRANSACTION:XC05 PROGRAM:TESTC05 TASK NUMBER:0000698 DISPLAY:00
STATUS:COMMAND EXECUTION COMPLETE
CALL TO RESOURCE MANAGER DSNCSQL
+OVAR 002:  TYPE=CHAR,   LEN=00008,IND=000    AT X'03C920B0'
DATA=X'C8F3E3E3C1C2D3C5'
OVAR 003:TYPE=CHAR,      LEN=00040,IND=000    AT X'03C920B8'
DATA=X'C9D5C9E3C9C1D340D3D6C1C440404040404040404040404040404040'...

OFFSET:X'001D14'LINE:UNKNOWN EIBFN=X'1802'

ENTER:CONTINUE
PF1 :UNDEFINED            PF2 :UNDEFINED          PF3 :END EDF SESSION
PF4 :SUPPRESS DISPLAYS    PF5 :WORKING STORAGE    PF6 :USER DISPLAY
PF7 :SCROLL BACK          PF8 :SCROLL FORWARD     PF9 :STOP CONDITIONS
PF10:PREVIOUS DISPLAY     PF11:UNDEFINED          PF12:ABEND USER TASK


080 - Locating the Problem

Chapter 9. Testing and Debugging Applications

Locating the Problem

If your program does not run correctly, you need to isolate the problem. If the DB2 did not invalidate the program's application plan, you should check the following items:

  • Output from the precompiler, which consists of errors and warnings. Ensure that you have resolved all errors and warnings.

  • Output from the compiler or assembler. Ensure that you have resolved all error messages.

  • Output from the linkage editor.

    - Have you resolved all external references?

    - Have you included all necessary modules in the correct order?

    - Did you include the correct language interface module? The correct language interface module is

    • DSNELI for TSO

    • DFSLI000 for IMS

    • DSNCLI for CICS

    • DSNALI for the call attachment facility

    - Did you specify the correct entry point to your program?

  • Output from the bind process.

    - Have you resolved all error messages?

    - Did you specify a plan name?

    • If not, the bind process assumes you want to process the DBRM for diagnostic purposes, but do not want to produce an application plan.

    • Have you specified all the DBRMs and packages associated with the programs that make up the application and their partitioned dataset (PDS) names in a single application plan?

  • Your JCL.

    - If you are using IMS, have you included the DL/I option statement in the correct format?

    - Have you included the region size parameter in the EXEC statement? Does it specify a region size large enough for the storage required for the DB2 interface, the TSO, IMS, or CICS system, and your program?

    - Have you included the names of all datasets (DB2 and non-DB2) that the program requires?

  • Your program.

    - You can also use dumps to help localize problems in your program. For example, one of the more common error situations occurs when your program is running and you receive a message that it abended. In this instance, your test procedure might be to capture a TSO dump. To do so, you must allocate a SYSUDUMP or SYSABEND dump dataset before calling DB2. When you press the Enter key (after the error message and READY message), the system requests a dump. You then need to FREE the dump dataset.

Analyzing Precompiler Error and Warning Messages

Under some circumstances, the statements that the DB2 precompiler generates can produce compiler or assembly error messages. You must know why the messages occur when you compile DB2-produced source statements. For more information about warning messages, refer to the individual host language.

SYSTERM Output from the Precompiler

The DB2 precompiler provides SYSTERM output when you allocate the DD name SYSTERM. If you use the Program Preparation panels to prepare and run your program, DB2I allocates SYSTERM according to the TERM option you specify.

The SYSTERM output provides a brief summary of the results from the precompiler, all error messages that the precompiler generated, and the statement in error, when possible. Sometimes, the error messages by themselves are not enough. In such cases, you can use the line number provided in each error message to locate the failing source statement. The following code shows the format of SYSTERM output. Note the superscript numbers 1 through 7 in the code, which correspond to the notes following the example.

DB2 SQL PRECOMPILER MESSAGES
DSNH104I E DSNHPARS LINE 32 COL 26 ILLEGAL SYMBOL "X"VALID SYMBOLS
ARE:,FROM1
SELECT VALUE INTO HIPPO X;2
DB2 SQL PRECOMPILER STATISTICS
SOURCE STATISTICS 3
SOURCE LINES READ:36
NUMBER OF SYMBOLS:15
SYMBOL TABLE BYTES EXCLUDING ATTRIBUTES:1848
THERE WERE 1 MESSAGES FOR THIS PROGRAM.4
THERE WERE 0 MESSAGES SUPPRESSED BY THE FLAG OPTION.5
111664 BYTES OF STORAGE WERE USED BY THE PRECOMPILER.6
RETURN CODE IS 87
Code Notes

  1. Error message.

  2. Source SQL statement.

  3. Summary statements of source statistics.

  4. Summary statement of the number of errors detected.

  5. Summary statement indicating the number of errors detected but not printed. That value might occur if you specify a FLAG option other than I.

  6. Storage requirement statement telling you how many bytes of working storage that the DB2 precompiler actually used to process your source statements. That value helps you determine the storage allocation requirements for your program.

  7. Return code: 0 = success; 4 = warning; 8 = error; 12 = severe error; 16 = unrecoverable error.

SYSPRINT Output from the Precompiler

SYSPRINT output is what the DB2 precompiler provides when you use a procedure to precompile your program. When you use the Program Preparation panels to prepare and run your program, DB2 allocates SYSPRINT according to TERM option you specify (on line 12 of the Program Preparation: Compile, Prelink, Link, and Run panel). As an alternative, when you use the DSNH command procedure (CLIST), you can specify PRINT(TERM) to obtain SYSPRINT output at your terminal, or you can specify PRINT(qualifier) to place the SYSPRINT output into a dataset named authorizationid.qualifier.PCLIST. Assuming that you do not specify PRINT as LEAVE, NONE, or TERM, DB2 issues a message when the precompiler finishes, telling you where to find your precompiler listings. This helps you locate your diagnostics quickly and easily.

The SYSPRINT output can provide information about your precompiled source module if you specify the options SOURCE and XREF when you start the DB2 precompiler. The format of SYSPRINT output is as follows:

  • A list of the DB2 precompiler options (see following code example and notes) in effect during the precompilation (if you did not specify NOOPTIONS).

    DB2 SQL PRECOMPILER             Version 7
OPTIONS SPECIFIED:HOST(PLI),XREF,SOURCE1
OPTIONS USED -SPECIFIED OR DEFAULTED2
APOST
APOSTSQL
CONNECT(2)
DEC(15)
FLAG(I)
NOGRAPHIC
HOST(PLI)
NOT KATAKANA
LINECOUNT(60)
MARGINS(2,72)
ONEPASS
OPTIONS
PERIOD
SOURCE
STDSQL(NO)
SQL(DB2)
        XREF
Code Notes

  1. This section lists the options specified at precompilation time. This list does not appear if one of the precompiler option is NOOPTIONS.

  2. This section lists the options that are in effect, including defaults, forced values, and options you specified. The DB2 precompiler overrides or ignores any options you specify that are inappropriate for the host language.

  • A listing (see the following code example and notes) of your source statements (only if you specified the SOURCE option).

    DB2 SQL PRECOMPILER TMN5P40:PROCEDURE OPTIONS (MAIN):PAGE 2
1 TMN5P40:PROCEDURE OPTIONS(MAIN);00000100
2 /*******************************************************00000200
3 *program description and prologue 00000300
...
1324 /*************************************************/00132400
1325 /*GET INFORMATION ABOUT THE PROJECT FROM THE */00132500
1326 /*PROJECT TABLE.*/00132600
1327 /*************************************************/00132700
1328 EXEC SQL SELECT ACTNO,PREQPROJ,PREQACT 00132800
1329 INTO PROJ_DATA 00132900
1330 FROM TPREREQ 00133000
1331 WHERE PROJNO =:PROJ_NO;00133100
1332 00133200
1333 /*************************************************/00133300
1334 /*PROJECT IS FINISHED.DELETE IT.*/00133400
1335 /*************************************************/00133500
1336 00133600
1337 EXEC SQL DELETE FROM PROJ 00133700
1338 WHERE PROJNO =:PROJ_NO;00133800
...
1523 END;00152300
DB2 SQL PRECOMPILER SYMBOL CROSS-REFERENCE LISTING PAGE 29
DATA NAMES DEFN REFERENCE
"ACTNO"****FIELD
1328
"PREQACT"****FIELD
1328
"PREQPROJ"****FIELD
1328
"PROJNO"****FIELD
1331 1338
...
PROJ_DATA 495 CHARACTER(35)
1329
PROJ_NO 496 CHARACTER(3)
1331 1338
"TPREREQ"****TABLE
1330 1337
Code Notes

  1. The left column of sequence numbers, which the DB2 precompiler generates, is for use with the symbol cross-reference listing, the precompiler error messages, and the BIND error messages.

  2. The right column of sequence numbers come from the sequence numbers supplied with your source statements.

  • A list of the symbolic names used in SQL statements (this listing appears only if you specify the XREF option):

    - DATA NAMES identifies the symbolic names used in source statements. Names enclosed in quotation marks (") or single quotation marks (') are names of SQL entities such as tables, columns, and authorization IDs. Other names are host variables.

    - DEFN is the number of the line that the precompiler generates to define the name. **** means that the object was not defined or the precompiler did not recognize the declarations.

    - REFERENCE contains two kinds of information: what the source program defines the symbolic name to be, and which lines refer to the symbolic name. If the symbolic name refers to a valid host variable, the list also identifies the data type or STRUCTURE.

  • A summary of the errors detected by the DB2 precompiler and a list of the error messages generated by the precompiler. See the following code example and notes.

    DB2 SQL PRECOMPILER STATISTICS
SOURCE STATISTICS
SOURCE LINES READ:15231
NUMBER OF SYMBOLS:1282
SYMBOL TABLE BYTES EXCLUDING ATTRIBUTES:64323
THERE WERE 1 MESSAGES FOR THIS PROGRAM.4
THERE WERE 0 MESSAGES SUPPRESSED.5
65536 BYTES OF STORAGE WERE USED BY THE PRECOMPILER.6
RETURN CODE IS 8.7
DSNH104I E LINE 590 COL 64 ILLEGAL SYMBOL:'X';VALID SYMBOLS ARE:,FROM8
Code Notes

  1. Summary statement indicating the number of source lines.

  2. Summary statement indicating the number of symbolic names in the symbol table (SQL names and host names).

  3. Storage requirement statement indicating the number of bytes for the symbol table.

  4. Summary statement indicating the number of messages printed.

  5. Summary statement indicating the number of errors detected but not printed. You might get this statement if you specify the option FLAG.

  6. Storage requirement statement indicating the number of bytes of working storage actually used by the DB2 precompiler to process your source statements.

  7. Return code: 0 = success; 4 = warning; 8 = error; 12 = severe error; and 16 = unrecoverable error.

  8. Error messages (this example detects only one error).


081 - Testing and Debugging Stored Procedures

Chapter 9. Testing and Debugging Applications

Testing and Debugging Stored Procedures

Testing and debugging a stored procedure is quite a bit different than teting other programs. There are different tools that can be used to help in this effort.

Testing a Stored Procedure

Some commonly used debugging tools, such as TSO TEST, are not available in the environment where stored procedures run. Here are some alternative testing strategies to consider.

Standalone Program on a Workstation

If you have debugging support on a workstationI (such as with Stored Procedure Builder [SPB]; see Chapter 5), you might choose to do most of your development and testing on a workstation, before installing a stored procedure on MVS. This results in very little debugging activity on MVS.

Debug Tool and IBM VisualAge COBOL

If you have VisualAge COBOL installed on your workstation and the Debug Tool installed on your OS/390 system, you can use the VisualAge COBOL Edit/Compile/Debug component with the Debug Tool to debug a COBOL stored procedure that runs in a WLM-established stored procedures address space. After you write your COBOL stored procedure and set up the WLM environment, follow these steps to test the stored procedure with the Debug Tool:

  1. When you compile the stored procedure, specify the TEST and SOURCE options. Ensure that the source listing is stored in a permanent dataset. VisualAge COBOL displays that source listing during the debug session.

  2. When you define the stored procedure, include runtime option TEST with the suboption VADTCPIP&ipaddr in your RUN OPTIONS argument. VADTCPIP& tells the Debug Tool that it is interfacing with a workstation that runs VisualAge COBOL and is configured for TCP/IP communication with your OS/390 system. ipaddr is the IP address of the workstation on which you display your debug information. For example, the RUN OPTIONS value in this stored procedure definition indicates that debug information should go to the workstation with IP address 9.63.51.17:

    CREATE PROCEDURE WLMCOB
(IN INTEGER,INOUT VARCHAR(3000),INOUT INTEGER)
MODIFIES SQL DATA
LANGUAGE COBOL EXTERNAL
PROGRAM TYPE MAIN
WLM ENVIRONMENT WLMENV1
RUN OPTIONS 'POSIX(ON),TEST(,,,VADTCPIP&9.63.51.17:*)'

  3. In the JCL startup procedure for WLM-established stored procedures address space, add the dataset name of the Debug Tool load library to the STEPLIB concatenation. For example, suppose that ENV1PROC is the JCL procedure for application environment WLMENV1. The modified JCL for ENV1PROC might look like this:

    //DSNWLM PROC RGN=0K,APPLENV=WLMENV1,DB2SSN=DSN,NUMTCB=8
//IEFPROC EXEC PGM=DSNX9WLM,REGION=&RGN,TIME=NOLIMIT,
//PARM='&DB2SSN,&NUMTCB,&APPLENV'
//STEPLIB DD DISP=SHR,DSN=DSN710.RUNLIB.LOAD
//DD DISP=SHR,DSN=CEE.SCEERUN
//DD DISP=SHR,DSN=DSN710.SDSNLOAD
//DD DISP=SHR,DSN=EQAW.SEQAMOD <==DEBUG TOOL

  4. On the workstation, start the VisualAge Remote Debugger daemon. This daemon waits for incoming requests from TCP/IP.

  5. Call the stored procedure. When the stored procedure starts, a window that contains the debug session is displayed on the workstation. You can then execute Debug Tool commands to debug the stored procedure.
Debug Tool and C/C++ Productivity Tools for OS/390

If you have the C/C++ Productivity Tools for OS/390 installed on your workstation and the Debug Tool installed on your OS/390 system, you can debug an SQL procedure or a C or C++ stored procedure that runs in a WLM-established stored procedures address space. The code against which you run the debug tools is the C source program that is produced by the program preparation process for the stored procedure.

After you write your C++ stored procedure or SQL procedure and set up the WLM environment, follow these steps to test the stored procedure with the Distributed Debugger feature of the C/C++, Productivity Tools for OS/390, and the Debug Tool:

  1. When you define the stored procedure, include runtime option TEST with the suboption VADTCPIP&ipaddr in your RUN OPTIONS argument. VADTCPIP& tells the Debug Tool that it is interfacing with a workstation that runs VisualAge C++ and is configured for TCP/IP communication with your OS/390 system. ipaddr is the IP address of the workstation on which you display your debug information. For example, this RUN OPTIONS value in a stored procedure definition indicates that debug information should go to the workstation with IP address 9.63.51.17:

    RUN OPTIONS 'POSIX(ON),TEST(,,,VADTCPIP&9.63.51.17:*)'

  2. Precompile the stored procedure. Ensure that the modified source program that is the output from the precompile step is in a permanent, catalogued dataset. For an SQL procedure, the modified C source program that is the output from the second precompile step must be in a permanent, catalogued dataset.

  3. Compile the output from the precompile step. Specify the TEST, SOURCE, and OPT(0) compiler options.

  4. In the JCL startup procedure for the stored procedures address space, add the dataset name of the Debug Tool load library to the STEPLIB concatenation. For example, suppose that ENV1PROC is the JCL procedure for application environment WLMENV1. The modified JCL for ENV1PROC might look like this:

    //DSNWLM PROC RGN=0K,APPLENV=WLMENV1,DB2SSN=DSN,NUMTCB=8
//IEFPROC EXEC PGM=DSNX9WLM,REGION=&RGN,TIME=NOLIMIT,
//PARM='&DB2SSN,&NUMTCB,&APPLENV'
//STEPLIB DD DISP=SHR,DSN=DSN710.RUNLIB.LOAD
//DD DISP=SHR,DSN=CEE.SCEERUN
//DD DISP=SHR,DSN=DSN710.SDSNLOAD
//DD DISP=SHR,DSN=EQAW.SEQAMOD <==DEBUG TOOL

  5. On the workstation, start the Distributed Debugger daemon. This daemon waits for incoming requests from TCP/IP.

  6. Call the stored procedure. When the stored procedure starts, a window that contains the debug session is displayed on the workstation. You can then execute Debug Tool commands to debug the stored procedure.
Debugging with CODE/370

You can use the CoOperative Development Environment/370 licensed program, which works with Language Environment, to test multiple virtual system (MVS) stored procedures written in any of the supported languages. You can use CODE/370 either interactively or in batch mode.

Using CODE/370 Interactively

To test a stored procedure interactively using CODE/370, you must use the CODE/370 PWS Debug Tool on a workstation. You must also have CODE/370 installed on the MVS system where the stored procedure runs. To debug your stored procedure using the PWS Debug Tool, do the following:

  • Compile the stored procedure with option TEST. This places information in the program that the Debug Tool uses during a debugging session.

  • Invoke the Debug Tool. One way to do that is to specify the Language Environment runtime option TEST. The TEST option controls when and how the Debug Tool is invoked. The most convenient place to specify runtime options is in the RUN OPTIONS parameter of the CREATE PROCEDURE or ALTER PROCEDURE statement for the stored procedure. For example, if you code the option TEST(ALL,*,PROMPT,JBJONES%SESSNA:), the parameter values in the statement cause the following things to happen:

    - ALL: The Debug Tool gains control when an attention interrupt, abend, or program or Language Environment condition of Severity 1 and above occurs. Debug commands will be entered from the terminal.

    - PROMPT: The Debug Tool is invoked immediately after Language Environment initialization.

    - JBJONES%SESSNA: CODE/370 initiates a session on a workstation identified to APPC/MVS as JBJONES with a session ID of SESSNA.

If you want to save the output from your debugging session, issue a command that names a log file. For example, the following command starts logging to a file on the workstation called dbgtool.log.

SET LOG ON FILE dbgtool.log;

This should be the first command that you enter from the terminal or include in your commands file.

Using CODE/370 in Batch Mode

To test your stored procedure in batch mode, you must have the CODE/370 MFI Debug Tool installed on the MVS system where the stored procedure runs. To debug your stored procedure in batch mode using the MFI Debug Tool, do the following:

  • If you plan to use the Language Environment runtime option TEST to invoke CODE/370, compile the stored procedure with option TEST. This places information in the program that the Debug Tool uses during a debugging session.

  • Allocate a log dataset to receive the output from CODE/370. Put a DD statement for the log dataset in the startup procedure for the stored procedures address space.

  • Enter commands in a dataset that you want CODE/370 to execute. Put a DD statement for that dataset in the startup procedure for the stored procedures address space. To define the commands dataset to CODE/370, specify the commands dataset name or DD name in the TEST runtime option. For example, the following tells CODE/370 to look for the commands in the dataset associated with DD name TESTDD.

    TEST(ALL,TESTDD,PROMPT,*)

The first command in the commands dataset should be

SET LOG ON FILE ddname ;

That command directs output from your debugging session to the log dataset you defined in the previous step. For example, if you defined a log dataset with DD name INSPLOG in the stored procedures address space startup procedure, the first command should be

SET LOG ON FILE INSPLOG;

  • Invoke the Debug Tool. Two possible methods are

    - Specify the runtime option TEST. The most convenient place to do that is in the RUN OPTIONS parameter of the CREATE PROCEDURE or ALTER PROCEDURE statement for the stored procedure.

    - Put CEETEST calls in the stored procedure source code. If you use this approach for an existing stored procedure, you must recompile, relink, and bind it, then issue the STOP PROCEDURE and START PROCEDURE commands to reload the stored procedure.

You can combine the runtime option TEST with CEETEST calls. For example, you might want to use TEST to name the commands dataset but use CEETEST calls to control when the Debug Tool takes control.

Using the MSGFILE Runtime Option

Language Environment supports the runtime option MSGFILE, which identifies a JCL DD statement used for writing debugging messages. You can use the MSGFILE option to direct debugging messages to a DASD file or job entry subsystem (JES) spool file. The following considerations apply:

  • For each MSGFILE argument, a DD statement must be added to the JCL procedure used to start the DB2 stored procedures address space.

  • Execute ALTER PROCEDURE with the RUN OPTIONS parameter to add the MSGFILE option to the list of runtime options for the stored procedure.

  • Because multiple task control blocks (TCBs) can be active in the DB2 stored procedures address space, you must serialize I/O to the dataset associated with the MSGFILE option. For example,

    - To prevent multiple procedures from sharing a dataset, each stored procedure can specify a unique DD name with the MSGFILE option.

    - If you debug your applications infrequently or on a DB2 test system, you can serialize I/O by temporarily running the DB2 stored procedures address space with NUMTCB=1 in the stored procedures address space startup procedure. (This normally can be done by the system administrator.)

Using Driver Applications

A small driver application can be written that calls the stored procedure as a subprogram and passes the parameter list supported by the stored procedure. You can then test and debug the stored procedure as a normal DB2 application under TSO. TSO TEST can now be used as well as other commonly used debugging tools.

Using SQL INSERTs

SQL inserts can be used to get debugging information into a DB2 table. This allows other machines in the network (such as a workstation) to easily access the data in the table using DRDA access. DB2 discards the debugging information if the application executes the ROLLBACK statement. To prevent the loss of the debugging data, code the calling application so that it retrieves the diagnostic data before executing the ROLLBACK statement.

Testing a Java Stored Procedure

To help you debug your Java stored procedures, include a JSPDEBUG DD statement in your WLM startup procedure. This DD statement specifies a dataset to which DB2 writes debug information as stored procedures execute. For more information on debugging and testing Java programs refer to Chapter 13, "Java Programming."


082 - Summary

Chapter 9. Testing and Debugging Applications

Summary

There are many options for coding your application programs. This means that the method for debugging and testing your application will depend on the method of coding. There are also several methods to choose from for each coding environment. Regardless of which you choose, it is always important to test and debug DB2 application programs to ensure quality of code and integrity of data.


083 - Additional Resources

Chapter 9. Testing and Debugging Applications

Additional Resources

IBM OS/390 TSO/E Command Reference SC28-1969

IBM Debug Tool Users Guide and Reference SC09-2137

IBM CoOperative Development Environment/370: Debug Tool SC09-1623

IBM CICS for MVS/ESA Application Programming Reference SC33-0512

IBM IMS Batch Terminal Simulator General Information GH20-5522


084 - Chapter 10. Accessing Distributed Data

Part 3. Developing Applications

Chapter 10. Accessing Distributed Data

  • CONNECT Statements

  • Three-Part Names

  • DRDA

  • Update Coordination

  • Remote Query Performance


085 - Distributed Data

Chapter 10. Accessing Distributed Data

Distributed Data

Using the distributed data facility (DDF) of DB2 allows for access to data held by other data management systems or makes your DB2 data accessible to other systems. A DB2 application program can use SQL to access data controlled by database management systems (DBMSs) other than the DB2 at which the application's plan is bound. This DB2 is known as the local DB2. The local DB2 and the other DBMSs are called application servers (AS). Any application server other than the local DB2 is considered a remote server (RS), and access to its data is a distributed operation. DB2 provides two methods of accessing data at remote application servers: DRDA and DB2 private protocol access. For application servers that support the two-phase commit process, both methods allow for updating data at several remote locations within the same unit of work.

The location name of the DB2 subsystem is defined during DB2 installation. The communications database (CDB) records the location name and the network address of a remote DBMS. The tables in the CDB are part of the DB2 catalog.

DRDA: Distributed Relational Database Architecture

Communicating between platforms introduces several issues ranging from character conversion to definition of the actions that you want executed on the other platform. Several years ago with DB2 for MVS/ESA, Version 2, Release 3, IBM introduced a set of protocols known as Distributed Relational Database Architecture (DRDA). It was an open standard that could be licensed by other companies and provided for communication between a client (application requester) and a server (application server). The basic ideas of the protocol were to maximize the functionality and to reduce the overhead when communicating between like platforms.

The overhead for like platforms and the maximization of the functionality are achieved by putting the work on the platform that receives the message. For example: the request to fetch from a cursor will be processed by the application server, and the rows that are returned will be translated by the application requester. The support of ASCII tables in DB2 for OS/390 allows you to have both the application server and the application requester on the same data representation model (code page), thereby effectively eliminating any data conversion. The original specifications identified four different levels of support:

Remote request: A single request to one remote DBMS. The remote request consists of one SQL statement. This level does not allow you to define a unit of work. Every SQL statement is an independent unit of work.

Remote unit of work (RUW): A unit of work requesting services to a single remote DBMS. RUW provides integrity within a single DBMS. Several statements can be grouped together in a single unit of work, but these statements cannot span more than one DBMS.

Distributed unit of work (DUW): A unit of work requesting services to two or more DBMSs. DUW provides integrity across multiple DBMSs. However, access is to only a single DBMS in an SQL statement. The changes at all DBMSs are backed out if the execution of one SQL statement is not successful.

Distributed request: Request to two or more remote DBMSs residing on the same or different locations. Distributed request provides integrity across multiple locations and access to more than one location in an SQL statement.

There are no immediate plans to extend the DRDA architecture and include the distributed request functionality. The implementation of a standard technique to solve the distributed request problem is much more complicated, as it would require the addition of optimization-related concepts such as network performance and estimation of the cost of the remote SQL component. With DB2, however, you can find a solution for the distributed request, which is based on logic that is not part of the DRDA architecture but which is part of DB2's unique design.

You need to differentiate the two potential target data locations of the distributed request. If you want to combine DB2 data (on any platform), you can use a different solution than if you want non-DB2 data. The first question, how to perform a distributed request, is answered by any DB2 for UNIX, Windows, or OS/2 (DB2 UWO) manual that is at least version 7. The section in nicknames explains the steps required to make this work. What you need to remember is that you have full read/write access to any DB2 DRDA-enabled data source. Furthermore, that version of DB2 will also, as will any DRDA server, provide the full flavor of SQL syntax available on that platform. This includes recursion, rollup, cube, and many other SQL functions that do not exist on the OS/390.

The second question, how to incorporate non-DB2 data sources, requires a dual answer. The full support for distributed request functionality is currently available only when using DataJoiner. DataJoiner uses a private solution to solve this problem and does not use the DRDA extensions. DB2 UWO Version 7 implements this solution partially by integrating the read only (R/O) part of the DataJoiner code. Non-DB2 R/O access to Oracle is provided by the Relational Connect option, of which several versions are available, including Oracle, Sybase, SQL Server, Informix, and Life Sciences. The current DataJoiner and DB2 UWO Version 7 solution has a performance model of the target database and uses a copy of the remote object statistics to help the optimizer decide on the optimal placement of the SQL parts. The information required to determine this best access plan is based on information added by the system administrator, such as relative network speed and processor capacity, and information obtain by extracting the catalog of the remote system.

With DRDA (the recommended method), the application connects to a server at another location and executes packages that have been previously bound at that server. The application uses a CONNECT statement, a three-part name, or an alias (if bound with DBPROTOCOL [DRDA]) to access the server. For more information on bind options, refer to Chapter 6, "Binding an Application Program."

Queries can originate from any system or application that issues SQL statements as an application requester in the formats required by DRDA. DRDA access supports the execution of dynamic SQL statements and SQL statements that satisfy all of the following conditions:

  • The static statements appear in a package bound to an accessible server.

  • The statements are executed using that package.

  • The objects involved in the execution of the statements are at the server where the package is bound. If the server is a DB2 subsystem, three-part names and aliases can be used to refer to another DB2 server.

DRDA communication conventions are invisible to DB2 applications and allow a DB2 to bind and rebind packages at other servers and to execute the statements in those packages. For two-phase commit using System Network Architecture (SNA) connections, DB2 supports both presumed abort and presumed nothing protocols that are defined by DRDA. If you are using TCP/IP, DB2 uses the sync point manager defined in the documentation for DRDA Level 3.

NOTE

DRDA protocols are documented by the Open Group Technical Standard in DRDA Volume 1: Distributed Relational Database Architecture (DRDA).

DB2 Private Protocol

An application program running under DB2 can refer to a table or view at another DB2. This is done with private protocol. With private protocol, the application must use an alias or three-part name to direct the SQL statement to a given location. Private protocol only works between application requesters and application servers that are both DB2 for OS/390 subsystems.

A statement is executed using DB2 private protocol access if it refers to objects that are not at the current server and is implicitly or explicitly bound with DBPROTOCOL(PRIVATE).The current server is the DBMS to which an application is actively connected. DB2 private protocol access uses DB2 private connections. The statements that can be executed are SQL INSERT, UPDATE, and DELETE, and SELECT statements with their associated SQL OPEN, FETCH, and CLOSE statements.

The location name identifies the other DB2 to the DB2 application server. A three-part name consists of a location, an authorization ID, and an object name. For example, the name NYSERVER.DB2USER1.TEST refers to a table named DB2USER1.TEST at the server whose location name is NYSERVER. Alias names have the same allowable forms as table or view names. The name can refer to a table or view at the current server or to a table or view elsewhere.

NOTE

Private protocol does not support many distributed functions, such as TCP/IP or stored procedures. The newer data types, such as LOB or user-defined types, are also not supported by private protocol. It is not the recommended method to use and is no longer being enhanced. Also, private protocol support is going away with v7.

Communications Protocols

The DDF uses TCP/IP or SNA to communicate with other systems. Figure 10-1 shows the connectivity options you have with DB2's DDF.

Figure 10-1. Connectivity options.

Setting up a network for use by DBMSs requires knowledge of both database management and communications. Thus, you must put together a team of people with those skills to plan and implement the network.

SNA

SNA is the description of the logical structure, formats, protocols, and operational sequences for transmitting information through and controlling the configuration and operation of the networks. It is one of the two main network architectures used for network communications to the enterprise servers.

VTAM

DB2 also uses Virtual Terminal Access Method (VTAM) for communicating with remote databases. This is done by assigning two names for the local DB2 subsystem: a location name and a logical unit name (LU name). A location name distinguishes a specific DBMS in a network, so applications use this name to direct requests to the local DB2 subsystem. Other systems use different terms for a location name. For example, DB2 Connect calls this the target database name. DB2 uses the DRDA term RDBNAM to refer to non-DB2 relational database names.

TCP/IP

Transmission Control Protocol/Internet Protocol (TCP/IP) is a standard communication protocol for network communications. Previous versions of DB2 supported TCP/IP requesters, although additional software and configuration was required. Native TCP/IP eliminates these requirements, allowing gateway-less connectivity to DB2 for systems running UNIX System Services.

The security aspects of TCP/IP are different from SNA. Unlike SNA, where it is possible to tighten security, TCP/IP is much easier to mimic the address you are coming from. As a result, not all features available to the SNA protocol have been implemented for TCP/IP. DDF can be configured in such a way that it does inbound user ID translation. If a specific user ID enters the system, then replace it with a new value. Several systems use this to map a user ID to a functional user ID, which is very often the owner of the objects used in the application. IBM has decided not to implement inbound user ID translation for TCP/IP clients. If you really need this functionality and you are sure your network is sufficiently secured so that you don't have any issues, then you would have to use the DB2 exits to perform the inbound user ID translation. You have to make sure you modify the proper exit, as TCP/IP clients do not use the sign-on exit. The module that should be adapted is the DSN3@ATH exit.

CDB

The DB2 catalog includes the communications database (CDB), which contains several tables that hold information about connections with remote systems. These tables include

  • SYSIBM.LOCATIONS

  • SYSIBM.LUNAMES

  • SYSIBM.IPNAMES

  • SYSIBM.MODESELECT

  • SYSIBM.USERNAMES

  • SYSIBM.LULIST

  • SYSIBM.LUMODES

Some of these tables must be populated before data can be requested from remote systems. If this DB2 system services only data requests, the CDB does not have to be populated; the default values can be used.

When sending a request, DB2 uses the LINKNAME column of the SYSIBM.LOCATIONS catalog table to determine which protocol to use.

  • To receive VTAM requests, an LU name must be selected in installation panel DSNTIPR.

  • To receive TCP/IP requests, a DRDA port and a resynchronization port must be selected in installation panel DSNTIP5. TCP/IP uses the server's port number to pass network requests to the correct DB2 subsystem. If the value in the LINKNAME column is found in the SYSIBM.IPNAMES table, TCP/IP is used for DRDA connections. If the value is found in SYSIBM.LUNAMES table, SNA is used.

  • If the same name is in both SYSIBM.LUNAMES and SYSIBM.IPNAMES,TCP/IP is used to connect to the location.

NOTE

A requester cannot connect to a given location using both SNA and TCP/IP protocols. For example, if the SYSIBM.LOCATIONS specifies a LINKNAME of LU1, and if LU1 is defined in both the SYSIBM.IPNAMES and SYSIBM.LUNAMES tables, TCP/IP is the only protocol used to connect to LU1 from this requester for DRDA connections. For private protocol connections, the SNA protocols are used. If private protocol connections are being used, the SYSIBM.LUNAMES table must be defined for the remote location's LU name.

Gathering Configuration Information

How do you obtain the information to fill in the CDB and set up the connection with the remote system? DB2 UWO has a piece of software called the client configuration assistant, which communicates with a component on the server called the DB2 Database Administrative Server. This DB2DAS provides the client with all the information required to define the target database. Today DB2 for OS/390 and Z/OS does not provide this DB2DAS, and the user has to find the required information manually. The DB2 command -DIS DDF lists all the information required to set up the connection to the DB2 (see for the following sample output). Without this command, you would have to print the content of the bootstrap dataset (BSDS), which contains other sensitive information you may not want exposed.

DSNL080I  -DBT5 DSNLTDDF DISPLAY DDF REPORT FOLLOWS:
DSNL081I STATUS=STARTD
DSNL082I LOCATION           LUNAME            GENERICLU
DSNL083I DBT5               TU0.BSYSDBT5      -NONE
DSNL084I IPADDR          TCPPORT RESPORT
DSNL085I 10.35.4.16      2590    2591
DSNL086I SQL    DOMAIN=t390.rpc.com
DSNL086I RESYNC DOMAIN=t390.rpc.com
DSNL090I DT=A  CONDBAT=     64 MDBAT=   64
DSNL092I ADBAT=    0 QUEDBAT=      0 IN1DBAT=      0 CONQUED=      0
DSNL093I DSCDBAT=      0 IN2CONS=      0
             DSNL099I DSNLTDDF DISPLAY DDF REPORT COMPLETE

Communicating with a Data Sharing Group

All the members of the DB2 data sharing group have the same location name, but each individual member has its own specific communication parameters. There is therefore no way to define at the application level which member of the data sharing group should be addressed. The mapping to the group or an individual member should be defined at the level of the configuration of the client. On OS/390 that would be the definitions in the CDB; when using DB2 Connect the target is defined in the node directory.

In fact, the purpose of the data sharing implementation is to make the entire group virtually one in order to increase the availability of the overall data sharing group. With every new release of DB2 Connect, we see further improvements to make the routing to the data sharing members more transparent and efficient.

At the networking level, we find solutions that allow you to "virtualize" the DB2 server. These include the use of SNA/APPC (Advanced Program to Program Communication) generic resources and techniques such as TCP/IP VIPA (Virtual IP Address). Both require a considerable investment from the networking side. Another alternative is the definition of dynamic APPC application definitions. In this case we make use of the concept of a model. The application used by DB2 is no longer defined in a static fashion but refers to a model that is active on all systems in the data sharing group.


086 - Coding Methods for Distributed Data

Chapter 10. Accessing Distributed Data

Coding Methods for Distributed Data

There are different ways of accessing distributed data and there are also considerations for preparing and binding programs that will be executing statements against this data. We will take a look at connect options, program preparation, and bind options, as well as additional considerations for coordinating updates.

Three-Part Names

You can use three-part table names to access data at a remote location through DRDA access or DB2 private protocol access. When you use three-part table names, the way you code your application is the same, regardless of the access method you choose. You determine the access method when you bind the SQL statements into a package or plan. If you use DRDA access, you must bind the DBRMs for the SQL statements to be executed at the server into packages that reside at that server. Because platforms other than DB2 for OS/390 might not support the three-part name syntax, you should not code applications with three-part names if you plan to port those applications to other platforms.

In a three-part table name, the first part denotes the location. The local DB2 makes and breaks an implicit connection to a remote server as needed. An application uses a location name to construct a three-part table name in an SQL statement. It then prepares the statement and executes it dynamically. If it is an INSERT, the values to be inserted are transmitted to the remote location and substituted for the parameter markers in the INSERT statement. The following overview shows how the application uses three-part names:

Read input values
Do for all locations
Read location name
Set up statement to prepare
Prepare statement
Execute statement
End loop
Commit

After the application obtains a location name, for example SAN_JOSE, it creates the following character string:

INSERT INTO SAN_JOSE.DSN8710.PROJ VA UES (?,?,?,?,?,?,?,?)

The application assigns the character string to the variable INSERTX and then executes these statements:

EXEC SQL
PREPARE STMT1 FROM :INSERTX;
EXEC SQL
EXECUTE STMT1 USING :PROJNO, :PROJNAME, :DEPTNO, :RESPEMP,
:PRSTAFF, :PRSTDATE, :PRENDATE, :MAJPROJ;

To keep the data consistent at all locations, the application commits the work only when the loop has executed for all locations. Either every location has committed the INSERT or, if a failure has prevented any location from inserting, all locations have rolled back the INSERT. (If a failure occurs during the commit process, the entire unit of work can be in doubt.)

NOTE

It might be more convenient to use aliases when creating character strings that become prepared statements, instead of using full three-part names.

Three-Part Names and Multiple Servers

If you use a three-part name or an alias that resolves to one in a statement executed at a remote server by DRDA access, and if the location name is not that of the server, then the method by which the remote server accesses data at the named location depends on the value of DBPROTOCOL. If the package at the first remote server is bound with DBPROTOCOL(PRIVATE), DB2 uses DB2 private protocol access to access the second remote server. If the package at the first remote server is bound with DBPROTOCOL(DRDA), DB2 uses DRDA access to access the second remote server. We recommend that you follow these steps so that access to the second remote server is by DRDA access:

  • Rebind the package at the first remote server with DBPROTOCOL(DRDA).

  • Bind the package that contains the three-part name at the second server.

Accessing Declared Temporary Tables

You can access a remote declared temporary table using a three-part name only if you use DRDA access. However, if you combine explicit CONNECT statements and three-part names in your application, a reference to a remote declared temporary table must be a forward reference. For example, you can perform the following series of actions, which includes a forward reference to a declared temporary table:

EXEC SQL CONNECT TO CHICAGO; /* Connect to the remote site */
EXEC SQL
DECLARE GLOBAL TEMPORARY TABLE TEMPPROD /*Define the temporary table*/
 (CHARCO CHAR(6) NOT NULL); /* at the remote site */
EXEC SQL CONNECT RESET; /* Connect back to local site */
EXEC SQL INSERT INTO CHICAGO.SESSION.T1
(VALUES 'ABCDEF'); /* Access the temporary table*/
/* at the remote site (forward reference) */

However, you cannot perform the following series of actions, which includes a backward reference to the declared temporary table:

EXEC SQL
DECLARE GLOBAL TEMPORARY TABLE TEMPPROD /*Define the temporary table*/
(CHARCO CHAR(6) NOT NULL ); /* at the local site (ATLANTA)*/
EXEC SQL CONNECT TO CHICAGO; /* Connect to the remote site */
EXEC SQL INSERT INTO ATLANTA.SESSION.T1
(VALUES 'ABCDEF'); /* Cannot access temp table */
/* from the remote site (backward reference)*/

Using Explicit CONNECT Statements

With this method the application program explicitly connects to each new server. You must bind the DBRMs for the SQL statements to be executed at the server to packages that reside at that server. An application executes CONNECT for each server, and in turn the server can execute statements such as INSERTs. In this case the tables to be updated each have the same name, though each is defined at a different server. The application executes the statements in a loop, with one iteration for each server.

The application connects to each new server by means of a host variable in the CONNECT statement. CONNECT changes the special register CURRENT SERVER to show the location of the new server. The values to insert in the table are transmitted to a location as input host variables. The following overview shows how the application uses explicit CONNECTs:

Read input values
Do for all locations
Read location name
Connect to location
Execute insert statement
End loop
Release all
Commit

The application inserts a new location name into the variable LOCATION_NAME, and executes the following statements:

EXEC SQL
CONNECT TO : LOCATION_NAME;
EXEC SQL
INSERT INTO DSN8710.PROJ VALUES
(:PROJNO, :PROJNAME, :DEPTNO,:RESPEMP,
:PRSTAFF, :PRSTDATE, :PRENDATE, :MAJPROJ);

To keep the data consistent at all locations, the application commits the work only when the loop has executed for all locations. Either every location has committed the INSERT or, if a failure has prevented any location from inserting, all other locations have rolled back the INSERT. (If a failure occurs during the commit process, the entire unit of work can be in doubt.)

Releasing Connections

When you connect to remote locations explicitly, you must also break those connections explicitly. You have considerable flexibility in determining how long connections remain open, so the RELEASE statement differs significantly from CONNECT.

Differences Between CONNECT and RELEASE

  • CONNECT makes an immediate connection to exactly one remote system.

  • CONNECT (Type 2) does not release any current connection.

  • RELEASE does not immediately break a connection. The RELEASE statement labels connections for release at the next commit point. A connection so labeled is in the release-pending state and can still be used before the next commit point.

  • RELEASE can specify a single connection or a set of connections for release at the next commit point.

Preparing Programs for DRDA Access

For the most part, binding a package to run at a remote location is like binding a package to run at your local DB2. Binding a plan to run the package is like binding any other plan.

Precompiler Options

The following precompiler options are relevant to preparing a package to be run using DRDA access:

  • CONNECT: Use CONNECT(2) explicitly or by default. CONNECT(1) causes your CONNECT statements to allow only the restricted function known as remote unit of work. Be particularly careful to avoid CONNECT(1) if your application updates more than one DBMS in a single unit of work.

  • SQL: Use SQL(ALL) explicitly for a package that runs on a server that is not DB2 for OS/390. The precompiler then accepts any statement that obeys DRDA rules. Use SQL(DB2) explicitly or by default if the server is DB2 for OS/390 only. The precompiler then rejects any statement that does not obey the rules of DB2 for OS/390.

BIND PACKAGE Options

The following options of BIND PACKAGE are relevant to binding a package to be run using DRDA access:

  • location-name: Name the location of the server at which the package runs. The privileges needed to run the package must be granted to the owner of the package at the server. If you are not the owner, you must also have SYSCTRL authority or the BINDAGENT privilege granted locally.

  • SQLERROR: Use SQLERROR(CONTINUE) if you used SQL(ALL) when precompiling. That creates a package even if the bind process finds SQL errors, such as statements that are valid on the remote server but that the precompiler did not recognize. Otherwise, use SQLERROR(NOPACKAGE) explicitly or by default.

  • CURRENTDATA: Use CURRENTDATA(NO) to force block fetch for ambiguous cursors.

  • OPTIONS: When you make a remote copy of a package using BIND PACKAGE with the COPY option, use this option to control the default bind options that DB2 uses. Specify COMPOSITE to cause DB2 to use any options you specify in the BIND PACKAGE command. For all other options, DB2 uses the options of the copied package. This is the default command to cause DB2 to use the options you specify in the BIND PACKAGE command. For all other options, DB2 uses the defaults for the server on which the package is bound. This helps ensure that the server supports the options with which the package is bound.

  • DBPROTOCOL: Use DBPROTOCOL(PRIVATE) if you want DB2 to use DB2 private protocol access for accessing remote data that is specified with three-part names. Use DBPROTOCOL(DRDA) if you want DB2 to use DRDA access to access remote data that is specified with three-part names. You must bind a package at all locations whose names are specified in three-part names. These values override the value of DATABASE PROTOCOL on installation panel DSNTIP5. Therefore, if the setting of DATABASE PROTOCOL at the requester site specifies the type of remote access you want to use for three-part names, you do not need to specify the DBPROTOCOL bind option.

BIND PLAN Options

The following options of BIND PLAN are particularly relevant to binding a plan that uses DRDA access:

  • DISCONNECT: For the most flexibility, use DISCONNECT(EXPLICIT) explicitly or by default. That requires you to use RELEASE statements in your program to explicitly end connections. But the other values of the option are also useful. DISCONNECT(AUTOMATIC) ends all remote connections during a commit operation without the need for RELEASE statements in your program. DISCONNECT(CONDITIONAL) ends remote connections during a commit operation except when an open cursor defined as WITH HOLD is associated with the connection.

  • SQLRULES: Use SQLRULES(DB2) explicitly or by default. SQLRULES(STD) applies the rules of the SQL standard to your CONNECT statements, so that CONNECT TO x is an error if you are already connected to x. Use STD only if you want that statement to return an error code. If your program selects LOB data from a remote location, and you bind the plan for the program with SQLRULES(DB2), the format in which you retrieve the LOB data with a cursor is restricted. After you open the cursor to retrieve the LOB data, you must retrieve all of the data using an LOB variable or retrieve all of the data using an LOB locator variable. If the value of SQLRULES is STD, this restriction does not exist. If you intend to switch between LOB variables and LOB locators to retrieve data from a cursor, execute the SET SQLRULES=STD statement before you connect to the remote location.

  • CURRENTDATA: Use CURRENTDATA(NO) to force block fetch for ambiguous cursors.

  • DBPROTOCOL: Use DBPROTOCOL(PRIVATE) if you want DB2 to use DB2 private protocol access for accessing remote data that is specified with three-part names. Use DBPROTOCOL(DRDA) if you want DB2 to use DRDA access to access remote data that is specified with three-part names. You must bind a package at all locations whose names are specified in three-part names. The package value for the DBPROTOCOL option overrides the plan option. For example, if you specify DBPROTOCOL(DRDA) for a remote package and DBPROTOCOL(PRIVATE) for the plan, DB2 uses DRDA access when it accesses data at that location using a three-part name. If you do not specify any value for DBPROTOCOL, DB2 uses the value of DATABASE PROTOCOL on installation panel DSNTIP5.

Coordinating Updates

Two or more updates are coordinated if they must all commit or all rollback in the same unit of work. Updates to two or more DBMSs can be coordinated automatically if both systems implement a method called two-phase commit.

DB2 and IMS, and DB2 and CICS, jointly implement a two-phase commit process. You can update an IMS database and a DB2 table in the same unit of work. If a system or communication failure occurs between committing the work on IMS and on DB2, then the two programs restore the two systems to a consistent point when activity resumes.

You cannot really have coordinated updates with a DBMS that does not implement two-phase commit. In the description that follows, we call such a DBMS a restricted system. DB2 prevents you from updating both a restricted system and any other system in the same unit of work. In this context, update includes the statements INSERT, DELETE, UPDATE, CREATE, ALTER, DROP, GRANT, REVOKE, and RENAME.

To achieve the effect of coordinated updates with a restricted system, you must first update one system and commit that work, and then update the second system and commit its work. If a failure occurs after the first update is committed and before the second is committed, there is no automatic provision for bringing the two systems back to a consistent point. Your program must assume that task.

CICS and IMS

You cannot update at servers that do not support two-phase commit.

TSO and batch

You can update if and only if

  • No other connections exist, or

  • All existing connections are to servers that are restricted to read-only operations.

If these conditions are not met, then you are restricted to read-only operations.

If the first connection in a logical unit of work is to a server that supports two-phase commit, and there are no existing connections or only read-only connections, then that server and all servers that support two-phase commit can update. However, if the first connection is to a server that does not support two-phase commit, only that server is allowed to update.

NOTE

Rely on DB2 to prevent updates to two systems in the same unit of work if either of them is a restricted system.

Without Two-Phase Commit

If you are accessing a mixture of systems, some of which might be restricted, you can

  • Read from any of the systems at any time.

  • Update any one system many times in one unit of work.

  • Update many systems, including CICS or IMS, in one unit of work, provided that none of them is a restricted system. If the first system you update in a unit of work is not restricted, any attempt to update a restricted system in that unit of work returns an error.

  • Update one restricted system in a unit of work, provided that you do not try to update any other system in the same unit of work. If the first system you update in a unit of work is restricted, any attempt to update any other system in that unit of work returns an error.


087 - Programming Considerations

Chapter 10. Accessing Distributed Data

Programming Considerations

When working with more than one location, we need to find a way to identify which DB2 holds the data we want to process. With application directed data, before executing the SQL, you identify to DB2 the location to which the SQL statement should be directed. This can be done either explicitly by coding a connect statement in the application or by relying on the CURRENT SERVER register. The value of the CURRENT SERVER register is initially determined by the BIND option CURRENT SERVER. If this was not specified, then CURRENT SERVER is set to blanks until you issue a CONNECT TO statement.

When a package is bound with DBPROTOCOL(DRDA) and you use a three part name, DB2 will issue the connect statement under the covers. The SQLRULES bind option will also determine how DB2 will handle connection management. When using SQLRULES(DB2), you can connect to a database location even if you were already connected. The previous connect will simply be put in the current state. However, when using SQLRULES(STD), the control is more strict. When you are already connected to a location, the SET CONNECTION should be used to switch between connections.

It is possible that your bind will get errors if your program contains SQL statements that use more than one DB2. Some of the tables may not be defined at all locations or could have different definitions. It is important to bind your package with SQLERROR(CONTINUE) to allow the bind to ignore these errors. The errors are not causing any problems as long as you execute the SQL against the proper DB2. The same comment applies to the precompiler the option: SQL(ALL) will make the precompiler flag the statements, but it will not prevent the creation of the DBRM.

Beware that when DRDA is used, the SQL statement will be processed by the remote location and will adhere to the syntax rules of the target database. When using a non-OS/390 target, you may find some differences. This can work to your advantage, as you can exploit the full capabilities of your target database.

Application Design Options

The DRDA protocol allows an application to perform any SQL statement as if the database is local to the application. In Figure 10-2 we see an example of a program connecting to a remote database and issuing several SQL statements. We notice that the application requester already performs some optimization, as not all fetches seem to access the remote database. The second fetch finds the data on the client without having to access the server. This concept is called block fetch. Block fetch sends a number of rows in one go when the context allows this to happen without creating data consistency problems.

Figure 10-2. Accessing a remote database.

Let's assume that the client program doesn't need any interaction between the start and end. What keeps us from running the entire program on the server, and not just the SQL statements? We just invented the concept of a stored procedure. The program logic and SQL statements are ported to the database server, and the client program only needs to connect to the database server and start the stored procedure (see Figure 10-3).

Figure 10-3. Stored procedure flow.

Stored Procedures

In the stored procedure programming model, the application logic is moved from the client program to the database server. It is the responsibility of the database server to invoke the stored procedure program and handle the parameters flowing to and from the stored procedure. The actual implementation of the environment where the program runs depends on the platform of deployment. On OS/390 you can either configure a stored procedure address space or you can use address spaces that are controlled by the Workload Manager. The second option is by far the best technique, as you have much more control over the resources that are used and not all procedures that are running will share the same address space. On UNIX, Windows, or OS/2 there is no need to define a separate runtime environment.

The DB2 stored procedure builder (see Figure 10-4) provides a crossplatform development environment, allowing you to code programs either in Java or as Persistent Stored Modules (PSM). PSM is the programming language defined in the SQL99 standard and is very similar to Basic. The PSM code is translated by DB2 into a C program, resulting in much better performance and the ability to run static SQL.

Figure 10-4. Stored procedure builder.

If you don't need the portability of the stored procedure, but need to exploit non-DB2 resources such as DL/I databases, sequential files, CICS transactions, or any other resource on OS/390, it is better to develop the stored procedure outside the scope of the stored procedure builder and use your existing application development environment (see Figure 10-5). IBM already has delivered integration with the MQ series, thereby enriching the capabilities of the stored procedures programming environment. Have a look at the MQ UDF wizard, which you will find in the stored procedure builder.

Figure 10-5. Non-DB2 resources.

    Team-Fly
    Top


088 - Remote Query Performance

Chapter 10. Accessing Distributed Data

Remote Query Performance

There are many ways to improve the performance of remote queries. We take a look at some of those options in the next sections.

OPTIMIZE FOR n ROWS

Use of the OPTIMIZE FOR n ROWS for distributed applications to limit the number of rows returned in a DRDA client query block so that only a portion of the answer set is fetched. It can also optimize cases when a large number of rows are fetched by allowing a client to request multiple query blocks from a DRDA requester in a single network transmission. This allows you to specify the number of query blocks to retrieve.

OPTIMIZE FOR n ROWS is supported for result sets returned by a SELECT statement or by a stored procedure. DRDA Level 3 is implemented to provide the client the ability to specify the number of extra query blocks it wants to receive (instead of the default of one at a time). Any value n will allow the DRDA server to send multiple query blocks in a single transmission.

DB2 will send n number of rows of the result set in each network transmission if the result set fits in a query block. If the rows do not fit in a query block, extra query blocks will be sent in the same transmission up to either the query block limit set for the server (DSNZPARM EXTRASRV) or the query block limit set by the client (DSNZPARM EXTRAREQ, which is also the value in DDM MAXBLKEXT on the DRDA requester). You want to be cautious of these parameters, since the default is 100 (query blocks per transmission) and this could negatively affect the performance of your applications depending on your workload mix.

You would want to take advantage of this clause when the value n is less than the total number of rows that will fit in a DRDA query block and the application is only going to process the same number of n rows. You can also significantly reduce elapsed time for large query result sets by using OPTIMIZE FOR n ROWS if n is greater than the number of rows that can fit in one DRDA query block, because this will allow the requester to get multiple query blocks with each network transmission.

If your DRDA application meets the following criteria you may want to use OPTIMIZE FOR n ROWS:

  • Read-only queries fetching a large number of rows.

  • SQL cursors rarely being closed before fetching entire result set.

  • When cursor is open, no statements other than FETCH are used.

  • Multiple cursors defined with OPTIMIZE FOR n ROWS not issuing FETCHes.

You do not want to set a large number of query blocks for cursors defined WITH HOLD, because if the requester application commits while several blocks are in the network, DB2 will buffer the blocks in memory.

Inactive Threads

Access threads that do not hold any cursors are known as inactive threads. Two types of inactive threads are supported: type 1 and type 2.

Type 2 Inactive Threads

Type 2 threads are available only for DRDA connections, use a pool of database threads (which can be switched as needed among connections), and use less storage than type 1. You want to use type 2 inactive threads when possible.

Distributed Application Tuning Guidelines

  • Use stored procedures to reduce network traffic.

  • Use COMMIT ON RETURN YES to issue an implicit commit for a stored procedure when there is a return from the CALL statement.

  • Commit frequently.

  • The fewer SQL statements, the better.

  • Use the SQL RELEASE statement to release the remote connection at commit time, and also use the DISCONNECT(EXPLICIT).

  • Use the CURRENT RULES of DB2 (not STD) special register so DB2 can send multiple blocks of data back to the program when requesting LOB data.

  • Use DRDA type connections instead of the DB2 private protocol.


089 - Summary

Chapter 10. Accessing Distributed Data

Summary

Access to DB2 from remote locations is a necessary part of most application environments. DB2 provides that capability through various means. Using the distributed data facility (DDF) of DB2 allows for access to data held by other DBMSs or makes your DB2 data accessible to other systems. A DB2 application program can use SQL to access data at DBMSs other than the DB2 at which the application's plan is bound.

We looked at the two methods that DB2 provides for accessing data at remote application servers: DRDA and DB2 private protocol access. We also looked at the use of three-part names and the DB2 CONNECT statement. Last, we covered some of the ways to improve performance of remote queries.


090 - Additional Distributed Resources

Chapter 10. Accessing Distributed Data

Additional Distributed Resources

IBM DB2 UDB for OS/390 Installation Guide GC26-9936

IBM DB2 UDB for OS/390 Administration Guide SC26-9931

IBM DB2 UDB for OS/390 SQL Guide and Reference SC26-9944

Open Group Technical Standard in DRDA Volume 1: Distributed Relational Database Architecture (DRDA) Document number C911

DRDA information: www.opengroup.com

SNA LU 6.2 Peer Protocols Reference SC31-6808


091 -

Part 4: Programming and Language Environments

    Chapter 11. ODBC/CLI Programming

    Chapter 12. DB2 Traditional Programming

    Chapter 13. Java Programming

    Chapter 14. Attachment Programming


092 - Chapter 11. ODBC/CLI Programming

Part 4. Programming and Language Environments

Chapter 11. ODBC/CLI Programming

  • Embedded Dynamic SQL Versus Call-Level Interface

  • The DB2 ODBC Environment

  • Handles

  • Database Connections

  • Transaction Control

  • Executing SQL Statements

  • Retrieving Results

  • ODBC Stored Procedures

  • Error Handling and Problem Determination

  • Sample Program

DB2 Open Database Connectivity (ODBC) is IBM's callable SQL interface for the DB2 family of products. It is a C and C++ application programming interface (API) for relational database access, and it uses function calls to pass dynamic SQL statements as function arguments. Other languages can use the ODBC API, but it is usually defined using the C language.

ODBC is an alternative to embedded dynamic SQL, but unlike embedded SQL, it does not require that a program be precompiled. DB2 ODBC is based on the Microsoft ODBC specification and the X/Open Call-Level Interface (CLI) specification. These specifications were chosen as the basis for the DB2 ODBC in an effort to follow industry standards and to provide a shorter learning curve for those application programmers already familiar with either of these data source interfaces. In addition, some DB2-specific extensions were added to help the DB2 application programmer specifically exploit DB2 features. DB2 ODBC is derived from the ISO Call-Level Interface Draft International Standard (ISO CLI DIS) and ODBC Versions 2.0 and 3.0. DB2 provides both ODBC and CLI drivers.

DB2 ODBC programs can execute on many different platforms. This chapter deals with programs that run on OS/390 and z/OS systems. Programs executing on other platforms follow the same coding conventions, but details of the interface may vary, and the corresponding DB2 Universal Database references should be reviewed.


093 - Embedded Dynamic Versus Call-Level Interface

Chapter 11. ODBC/CLI Programming

Embedded Dynamic Versus Call-Level Interface

Traditional DB2 access facilities like CAF, DSN (TSO), IMS, and CICS use embedded SQL in application programs. This embedded SQL is usually static, but may contain dynamic statements. Dynamic SQL is executed using the PREPARE, EXECUTE and EXECUTE IMMEDIATE statements. Like static statements, these dynamic statements require precompilation and binding to the database to form a package or plan. More information about embedded dynamic SQL is available in Chapter 6, "Binding an Application Program."

DB2 ODBC data access is always dynamic and does not require precompilation or binding for the application program. This facilitates the migration of programs across platforms, because they execute the same and use the same database interfaces. Programs that use the ODBC and CLI interfaces do not need any embedded SQL statements and are compiled the same way whether the data source is DB2 or another DBMS.

PREPARE and EXECUTE are normal SQL statements, and the only way to execute a statement is to create a DBRM using the preprocessor and bind them as a plan or package. The bind for PREPARE and EXECUTE will be extremely fast, because the optimizer cannot optimize anything for these statementsall the work is done at runtime.

Now, why is it that programs that use DB2 ODBC do not have to bind anything? This is because at runtime your program calls the functions of DB2 ODBC. These functions use statements that are part of a standard plan used by this interface. For OS/390, this plan is called DSNACLI.

A DB2 ODBC program can use embedded SQL as well as ODBC function calls. Mixed-mode programs like these require their own package, a plan that includes that package, and the DB2 ODBC packages as well.


094 - The DB2 ODBC Environment

Chapter 11. ODBC/CLI Programming

The DB2 ODBC Environment

DB2 for OS/390 and z/OS does not support an ODBC driver manager. All API calls are routed through the single ODBC driver that is loaded at runtime into the application address space. DB2 ODBC support is implemented as an IBM C/C++ dynamic load library (DLL). By providing DB2 ODBC support using a DLL, DB2 ODBC applications do not need to link-edit any DB2 ODBC driver code with the application load module. Instead, the linkage to the DB2 ODBC APIs is resolved dynamically at runtime by the IBM Language Environment (LE) runtime support. The DB2 ODBC driver can use either the call attachment facility (CAF) or the Recoverable Resource Manager Services attachment facility (RRSAF) to connect to the DB2 for OS/390 and z/OS address space.

  • If the DB2 ODBC application is not running as a stored procedure, the MVSATTACHTYPE keyword in the DB2 ODBC initialization file determines the attachment facility that DB2 ODBC uses.

  • If the DB2 ODBC application is running as a stored procedure, then DB2 ODBC uses the attachment facility that was specified for stored procedures.

When the DB2 ODBC application invokes the first ODBC function, SQLAllocHandle(), to allocate the environment handle, the DB2 ODBC driver DLL is loaded.

DB2 ODBC supports access to the local DB2 for OS/390 and z/OS subsystems and any remote data source that is accessible using DB2 for OS/390 and z/OS Version 7. These include

  • Remote DB2 subsystems using specification of an alias or three-part name

  • Remote DRDA-1 and DRDA-2 servers using LU 6.2 or TCP/IP

There are several DB2 ODBC packages that must be bound at each possible data source, including the local DB2 for OS/390 and z/OS subsystem and all remote DRDA application servers. This task must be completed before an ODBC program can successfully use a data source.

Initialization File

DB2 ODBC uses an optional initialization file to retrieve default settings for configuration options and attributes. For most applications, the use of this file may not be necessary. The initialization file is specified at runtime by a DSNAOINI DD statement in the JCL that executes the program. UNIX System Services programs specify the initialization file using the DSNAOINI environment variable.

The initialization file is divided into three sections. The common section contains parameters that are global to all data sources. The subsystem section contains parameters that are specific to a DB2 subsystem. The data source section contains parameters specific to a data source. Within each section are keyword and value pairs that set the option values. A possible example of an initialization file follows.

; This is a comment line...
; Common Section, set default subsystem
[COMMON]
MVSDEFAULTSSID=DSN1
; DSN1 subsystem settings
[DSN1]
MVSATTACHTYPE=CAF
PLANNAME=DSNACLI
; DB2CERT Data Source
[DB2CERT]
AUTOCOMMIT=0
CONNECTTYPE=2
SCHEMALIST="'DB2USER1'"

When the environment handle is allocated, the MVSDEFAULTSSID is used to connect to the DB2 for OS/390 and z/OS address space. This is the subsystem where the DB2 location names of the data sources must be known. Data sources correspond to DB2 location names as defined in the SYSIBM.LOCATIONS table in the communications database. The local database name is the name that was set during DB2 installation. If a null connection is made, the local subsystem will act as the data source, so using null connections and different initialization files is an easy way to point an ODBC program at a different subsystem. Each instance of a program executing DB2 ODBC could potentially have its own initialization file.


095 - Handles

Chapter 11. ODBC/CLI Programming

Handles

Handles provide a context between an application program and the ODBC service routines. Each handle is a variable that indirectly references an ODBC controlled data object. These data objects hold information stored as attributes along with internal information used by the DB2 ODBC driver code. Attributes define the behavior expected of the data objects and allow a program some control over that behavior.

Handle Allocation

There are three handle types. All three types of handles are allocated using the SQLAllocHandle() function.

SQLRETURN SQLAllocHandle (SQLSMALLINT HandleType,
                          SQLHANDLE   InputHandle,
                          SQLHANDLE  *OutputHandlePtr);

The function requires the type of handle to be allocated, an input handle to establish the context for the new handle, and returns the new handle into an integer buffer (OutputHandlePtr) supplied by the calling program. The SQLAllocHandle() function is part of the ODBC 3.0 specification and is the preferred method of allocating all handles.

Multiple connection and statement handles can be allocated by an application at the same time. DB2 ODBC 3.0 driver applications can use the same environment, connection, or statement handle on different threads. DB2 ODBC provides thread-safe access for all handles and function calls. Applications can have multiple connections to the same or different data sources at the same time and each connection maintains its own unit of recovery. The application itself might experience unpredictable behavior if the threads it creates do not coordinate their use of DB2 ODBC resources.

Environment Handle

The environment handle refers to an environment data object. This data object stores global information about the state of the application, including global attributes and connection settings. Allocation of the environment handle is the first step in an ODBC program and DB2 ODBC uses this opportunity to load the DLL support library and read the initialization file.

The environment handle is allocated by calling SQLAllocHandle() with HandleType set to SQL_HANDLE_ENV and InputHandle set to SQL_NULL_HANDLE. The application passes the *OutputHandlePtr value in all subsequent calls that require an environment handle argument. DB2 ODBC does not support multiple environments. An application program may allocate only one environment handle.

Connection Handle

Connection handles refer to connection data objects. There is a connection data object for each data source used by an application. ODBC data sources are essentially the equivalent of DB2 for OS/390 and z/OS subsystems. An environment handle must be allocated before a connection handle can be allocated. Allocation of the connection handle does not perform the actual connection to the data source, but merely establishes the data object that will store the connection settings including options, status, and diagnostic information. Transaction status is also stored in the connection data object.

The connection handle is allocated by calling SQLAllocHandle() with HandleType set to SQL_HANDLE_DBC and InputHandle set to the environment handle returned in the prior SQLAllocHandle() call. The application passes the *OutputHandlePtr value in all subsequent calls that require a connection handle argument.

By allocating additional connection handles, an application can connect to multiple data sources or establish multiple concurrent connections to the same data source. There may be a limit on the number of connection handles. This limit can be determined with the SQLGetInfo() function. Once a connection handle has been allocated, the SQLConnect() function can be used to connect to DB2 or another DRDA application server.

Statement Handle

Statement handles refer to statement data objects. Each statement data object contains information, attributes, and options about a particular SQL statement. A connection handle must be allocated before a statement handle can be allocated.

A statement handle is allocated by calling SQLAllocHandle() with HandleType set to SQL_HANDLE_STMT and InputHandle set to the appropriate connection handle. Since a connection handle is required, an application can only use this statement handle against a single data source. If you want to run a statement against multiple data sources, you must allocate a statement handle for each data source and make the same calls for each.

Handle Deallocation

Handles are deallocated using the SQLFreeHandle() function. Both the handle type and the handle must be supplied.

SQLRETURN SQLFreeHandle (SQLSMALLINT HandleType,
                         SQLHANDLE   Handle);

Statement handles should be deallocated when they are no longer needed. All statement handles for a connection should be freed before the connection handle. Disconnect from the database using SQLDisconnect() to terminate the database connection before freeing a connection handle. All connection handles should be freed before the environment handle. Finally, the environment handle should be deallocated prior to program termination.

Attributes

Each data object referenced by a handle has several attributes. Attributes are retrieved and manipulated using GET and SET functions. Each handle type has its own specific functions. Attributes are set and retrieved using keyword and value pairs. For environment handles, use

SQLRETURN SQLGetEnvAttr (SQLHENV     EnvironmentHandle,
                         SQLINTEGER  Attribute,
                         SQLPOINTER  ValuePtr,
                         SQLINTEGER  BufferLength,
                         SQLINTEGER *StringLengthPtr)
SQLRETURN SQLSetEnvAttr (SQLHENV     EnvironmentHandle,
                         SQLINTEGER  Attribute,
                         SQLPOINTER  ValuePtr,
                         SQLINTEGER  StringLength)

For connection handles, use

SQLRETURN SQLGetConnectAttr (SQLHDBC     ConnectionHandle,
                             SQLINTEGER  Attribute,
                             SQLPOINTER  ValuePtr,
                             SQLINTEGER  BufferLength,
                             SQLINTEGER *StringLengthPtr);
SQLRETURN SQLSetConnectAttr (SQLHDBC     ConnectionHandle,
                             SQLINTEGER  Attribute,
                             SQLPOINTER  ValuePtr,
                             SQLINTEGER  StringLength);

For statement handles, use

SQLRETURN SQLGetStmtAttr (SQLHSTMT    StatementHandle,
                          SQLINTEGER  Attribute,
                          SQLPOINTER  ValuePtr,
                          SQLINTEGER  BufferLength,
                          SQLINTEGER *StringLengthPtr);
SQLRETURN SQLSetStmtAttr (SQLHSTMT    StatementHandle,
                          SQLINTEGER  Attribute,
                          SQLPOINTER  ValuePtr,
                          SQLINTEGER  StringLength);

Access to an attribute requires a handle. Some environment attributes provide global default values for use across connections and may be overridden for a specific connection by setting the connection attribute. Default attributes are loaded from the initialization file.


096 - Database Connections

Chapter 11. ODBC/CLI Programming

Database Connections

Connections to DB2 ODBC data sources are controlled with connection handles. Prior to connecting, a connection handle must be allocated. The program must execute on a system with a running DB2 for OS/390 and z/OS subsystem, though that subsystem doesn't have to be the desired data source.

Connecting

ODBC programs can connect to local DB2 subsystems, remote DB2 subsystems, or remote DRDA application servers. Each connection requires a separate connection handle. Remote connections require that the server be defined in the communications database of the local DB2 subsystem.

The SQLConnect() or SQLDriverConnect() functions are used to establish the connection to DB2. Both functions require a connection handle and a connection string. The connection string defines the target data source (DB2 subsystem) for the connection. The connection string can specify a DataSourceName or omit it in order to establish a null connection (discussed below).

Some connection attributes must be set prior to SQLConnect() execution. An example of this is the connection type (SQL_ATTR_CONNECTTYPE), which controls whether this is a type 1 or type 2 connection.

SQLRETURN SQLConnect (SQLHDBC     ConnectionHandle,
                      SQLCHAR    *DataSourceName,
                      SQLSMALLINT DataSourceLength,
                      SQLCHAR    *Userid,
                      SQLSMALLINT UseridLength,
                      SQLCHAR    *Password,
                      SQLSMALLINT PasswordLength);

SQLConnect() issues a SQL CONNECT to the data source specified by DataSourceName. The Userid and Password fields are validated, but ignored. Data source attribute values are loaded from the ODBC initialization file if there is a section.

SQLRETURN SQLDriverConnect (SQLHDBC      ConnectionHandle,
                            SQLHWND      hwnd,
                            SQLCHAR     *ConnStringIn,
                            SQLSMALLINT  ConnStringInLength,
                            SQLCHAR     *ConnStringOut,
                            SQLSMALLINT  ConnStringOutMaxLen,
                            SQLSMALLINT *ConnStringOutActLen,
                            SQLUSMALLINT DriverCompletion);

SQLDriverConnect() takes a more complicated ConnectStringIn that contains keyword and value pairs. The data source name is specified with the DSN keywordfor example, DSN=DB01. On other platforms, SQLDriverConnect() has options that permit the ODBC drivers to prompt the user for additional information. This is often used to let the driver prompt the user for his or her user ID and password as part of the connection rather than the application writing its own prompt dialog box. DB2 for OS/390 and z/OS does not support these prompting options. The connection string passed into the SQLDriverConnect() function usually looks something like DSN=DBT1,UID=MYID,PWD=MYPASS. DB2 for OS/390 and z/OS ignores the UID and PWD keywords. Additional keywords can be specified to override the specification in the initialization file.

Null Connections

A null connection is established by issuing SQLConnect() with a null data source name pointer or a zero data source name length. An application would need a null connection when running as a stored procedure or when mixing embedded SQL with ODBC and the connection has already been established.

An application that wants to connect to the default data source should also use a null connection. DB2 will pull the default DB2 subsystem from the MVSDEFAULTSSID setting in the initialization file.

For a null SQLConnect(), the connection type defaults to the value of the CONNECTTYPE keyword specified in the common section of the initialization file. Before the null SQLConnect() is issued, the connection type can be overridden by specifying the SQL_ATTR_CONNECTTYPE attribute.

Remote Connections

In order to connect to a remote DRDA application server, that server must trust the user ID supplied by DB2 for OS/390 and z/OS. This is because DB2 for OS/390 and z/OS does not support the specification of user ID and password on the SQL CONNECT statement.

Disconnecting

After a program is done processing, it should call SQLDisconnect() to terminate the database connection.

SQLRETURN SQLDisconnect (SQLHDBC ConnectionHandle);

The connection should be terminated prior to releasing the connection handle. Once the connection is terminated, the program can, if desired, reuse the connection handle to open a new connection to the same or another data source.


097 - Transaction Control

Chapter 11. ODBC/CLI Programming

Transaction Control

ODBC programs often assume that each SQL statement is a logical unit of work. The setting that controls this is AUTOCOMMIT. For compatibility, the DB2 default setting is 1, which forces a commit (or rollback) for every ODBC function call. To execute multiple ODBC calls in a single logical unit of work (LUW), you must override the setting either in the initialization file or using the SQLSetConnectAttr() or SQLSetEnvAttr() functions.

The SQLEndTran() function is used to commit or rollback an LUW for one or more connections. SQLEndTran() takes a HandleType and Handle along with a CompletionType of SQL_COMMIT or SQL_ROLLBACK.

SQLRETURN SQLEndTran (SQLSMALLINT HandleType,
                      SQLHANDLE   Handle,
                      SQLSMALLINT CompletionType);

If the HandleType is SQL_HANDLE_ENV, DB2 will attempt to commit or roll back for each connection handle that was created for the environment handle. If the HandleType is SQL_HANDLE_DBC the commit or rollback will be done only for the specified connection.


098 - Executing SQL Statements

Chapter 11. ODBC/CLI Programming

Executing SQL Statements

There are two main functions in DB2 ODBC for executing SQL statements: SQLExecDirect() and SQLExecute(). The SQLExecDirect() function prepares and executes a SQL statement similar to the SQL EXECUTE IMMEDIATE embedded dynamic SQL statement.

SQLRETURN SQLExecDirect (SQLHSTMT     StatementHandle,
                         SQLCHAR     *Statement,
                         SQLINTEGER   StatementLength);

The SQLExecute() function requires that the statement be prepared using SQLPrepare() first. Once the statement has been prepared it can be executed many times, saving CPU resources.

SQLRETURN SQLPrepare    (SQLHSTMT     StatementHandle,
                         SQLCHAR     *Statement,
                         SQLINTEGER   StatementLength);
SQLRETURN SQLExecute    (SQLHSTMT     StatementHandle);

Because the statement is dynamic, a program can put literal values directly into the SQL statement prior to the SQLPrepare() or SQLExecDirect() call. For example,

char stmt[500];
char testcenter[7];
char newname[41];
strcpy(stmt,"UPDATE DB2USER1.TEST_CENTER ");
strcat(stmt,"SET NAME='");
strcat(stmt,newname);
strcat(stmt,"' ");
strcat(stmt,"WHERE TCID = '");
strcat(stmt,testcenter);
strcat(stmt,"' ;");
rc = SQLExecDirect(StmtHandle, stmt, strlen(stmt));

This works because the SQLExecDirect() function optimizes and executes the statement at runtime. This technique can also be used to supply literal values in predicates of SELECT statements. If this were to be done repetitively in a program, the optimization would be done every time and potentially waste resources. For repetitive statements, there are parameter markers.

Parameter Markers

Host variables in ODBC programs are inserted into SQL statements using parameter markers. Parameter markers are represented by a "?" (question mark) character in the statement. Parameter markers can be placed in any SQL statement where an embedded statement would include a host variable. To make the connection between the parameter marker and the variable, the SQLBindParameter() function is used.

SQLRETURN SQLBindParameter(SQLHSTMT     StatementHandle,
                           SQLUSMALLINT ParamMarkerNumber,
                           SQLSMALLINT  ParamType,
                           SQLSMALLINT  CDataType,
                           SQLSMALLINT  SqlDataType,
                           SQLUINTEGER  Precision,
                           SQLSMALLINT  Scale,
                           SQLPOINTER   Buffer,
                           SQLINTEGER   BufferMaxSize,
                           SQLINTEGER  *BufferDataSize);

The SQLBindParameter() call may be made prior to a call to SQLPrepare(), but must be made prior to the execution of the SQL statement via SQLExecute() or SQLExecDirect(). Each parameter marker used for a statement must be assigned a unique sequential ParamMarkerNumber by the application. They need not be defined in order, but there cannot be any gaps when the SQLExecute() call is made. The application needs to call SQLBindParameter() for every parameter marker included in the SQL statement.

ParamType specifies whether the parameter is input to the SQL statement (SQL_PARAM_INPUT), output from the SQL statement (SQL_PARAM_OUTPUT), or both (SQL_PARAM_INPUT_OUTPUT). Input parameter markers can be used in any SQL statement; output and input/output parameters may only be used for SQL CALL statements to stored procedures. Using the above program excerpt as a model, a parameterized program might look like the following.

char stmt[500] = "UPDATE DB2USER1.TEST_CENTER"
                 " SET NAME=? WHERE TCID=?;";
char testcenter[7];
char newname[41];
SQLBindParameter(StmtHandle, 1,
                         SQL_C_CHAR,
                         SQL_CHAR,
                         41, 0,
                         newname,
                         sizeof(newname),
                         SQL_NTS);
SQLBindParameter(StmtHandle, 2,
                         SQL_C_CHAR,
                         SQL_CHAR,
                         7, 0,
                         testcenter,
                         sizeof(testcenter),
                         SQL_NTS);
rc = SQLExecDirect(StmtHandle, stmt, strlen(stmt));
Input Parameters

When the statement is executed, the actual data value for the parameter is sent to the server. The buffer must contain valid input data values and the BufferDataSize must contain the corresponding length, SQL_NTS, or SQL_NULL_DATA.

Output Parameters

After the statement is executed, data for the output parameter is returned to the application buffer and BufferDataSize, unless both are null pointers, in which case the output data is discarded.

Input/Output Parameters

When the statement is executed, the actual data value for the parameter is sent to the server. The buffer must contain valid input data values and the BufferDataSize variable must contain the corresponding length, SQL_NTS, SQL_NULL_DATA.

After the statement is executed, data for the output parameter is returned to the application buffer and BufferDataSize, unless both are null pointers, in which case the output data is discarded.

Data at Execution

A bound parameter for which value is prompted at execution time instead of stored in memory before calling SQLExecute() or SQLExecDirect() is called a data-at-execute parameter. To indicate this, the application sets the BufferDataSize to the value SQL_DATA_AT_EXEC.

If there are any data-at-execute parameters when the application calls SQLExecDirect() or SQLExecute(), the call returns with SQL_NEED_DATA to prompt the application to supply values for these parameters. The application then

  • Calls SQLParamData() to conceptually advance to the first such parameter. SQLParamData() returns SQL_NEED_DATA and provides the contents of the input data pointer argument specified on the associated SQLBindParameter() call to help identify the information required.

  • Calls SQLPutData() to pass the actual data for the parameter. Long data can be sent in pieces by calling SQLPutData() repeatedly.

  • Calls SQLParamData() again after it has provided the entire data for this data-at-execute parameter. If more data-at-execute parameters exist, SQLParamData() again returns SQL_NEED_DATA and the application repeats steps 2 and 3 above.

When all data-at-execute parameters are assigned values, SQLParamData() completes execution of the SQL statement and produces a return value and diagnostics as the original SQLExecDirect() or SQLExecute() would have produced.

If there is more than one data-at-execute parameter, set each input data pointer argument to some value that the program can recognize to uniquely identify the field.

LOB Locators

The application variable can be a LOB Locator, rather than a data area. In this case, the LOB Locator is passed to or from the server rather than to or from the LOB itself. LOB Locators allow an application to manipulate LOB data without passing the entire object back and forth.

Data Types

The CDataType and SQLDataType parameters tell the DB2 ODBC interface what data types the host variable and database variable are, respectively. Data conversion will be done if necessary, within the limits of valid conversions. The DB2 ODBC header files provide many convenient constants for coding data types in your programs.

Along with the specification of data types and column buffers, the DB2 ODBC functions usually require a long integer field to hold the actual length of the buffer contents. For binary data types like INTEGER and SMALLINT, this is generally a fixed value. For character fields, this may contain SQL_NTS, which indicates that the character field is a null-terminated string. The field may also be used to indicate a null value when set to SQL_NULL_DATA.

Releasing Parameter Markers

Parameter markers remain bound to a statement handle until the statement handle is deallocated using SQLFreeHandle(), another SQLBindParameter() call is made for that ParamMarkerNumber, or SQLFreeStmt() is called with the SQL_RESET_PARAMS option. This is true even if the statement handle is reused for another different SQL statement.

Arrays of Values

Programs that insert, delete, or update many values repetitively can pass arrays of values to DB2 ODBC. This is done by allocating an array of each parameter that is passed to SQLBindParameter() and calling SQLParamOptions() to indicate the number of array elements.

SQLRETURN SQLParamOptions (SQLHSTMT      StatementHandle,
                           SQLUINTEGER   RowCount,
                           SQLUINTEGER  *FetchOffsetPtr);

The RowCount should be set to the number of entries in the array. The contents of FetchOffsetPtr have the following uses:

  • When the SQL statement succeeds, the value in FetchOffsetPtr is set to the input value in RowCount to indicate that all elements of the array have been processed successfully.

  • When the SQL statement returns an error, the application can access the value in FetchOffsetPtr to find out which element in the array failed.

  • When SQLParamData() returns SQL_NEED_DATA, the application can access the value in FetchOffsetPtr to determine which set of parameters is being assigned values.

The output argument FetchOffsetPtr indicates how many sets of parameters were successfully processed. If the statement processed is a query, FetchOffsetPtr indicates the array index associated with the current result set returned by SQLMoreResults() and is incremented each time SQLMoreResults() is called.

DB2 ODBC prepares the statement, and executes it repeatedly for the array of parameter markers. As a statement executes, FetchOffsetPtr is set to the index of the current array of parameter values. If an error occurs during execution for a particular element in the array, execution halts and SQLExecute(), SQLExecDirect(), or SQLParamData() returns SQL_ERROR.


099 - Retrieving Results

Chapter 11. ODBC/CLI Programming

Retrieving Results

Some SQL statements, like SELECT, can return a table of results that must be retrieved by the program. The IBM manuals refer to these as result tables. Stored procedures invoked by the SQL CALL statement may return multiple result tables, and each is referred to as a result set. In this chapter we'll use the term result set to refer to either a result table from a query or a result set from a stored procedure, because the way they are handled in application programs is indistinguishable.

In DB2 ODBC, as in embedded SQL, result sets are retrieved using cursors. Similar to SQLBindParameter() for parameter markers in the SQL statement, result set columns are associated with application variables. The SQLBindCol() function handles this for cursors.

SQLRETURN SQLBindCol (SQLHSTMT      StatementHandle,
                      SQLUSMALLINT  ColumnNumber,
                      SQLSMALLINT   CDataType,
                      SQLPOINTER    Buffer,
                      SQLINTEGER    BufferMaxSize,
                      SQLINTEGER   *BufferDataSize);

SQLBindCol() is called for every result set column the program wishes to retrieve. Unlike SQLBindParameter(), columns bound to result sets can have gaps. Any column that does not have a variable bound to it is not returned to the application, though it would be more efficient to omit the column from the result set in the first place.

There are fewer parameters on SQLBindCol() because DB2 already knows the SQL data type. The C data type must still be specified, and DB2 will perform any necessary data conversion.

After the row is fetched, BufferDataSize will contain the length of the data placed in the buffer for this column. If the column contains a null value, this field will be set to SQL_NULL_DATA.

The associations for bound columns remain in effect until the statement handle is deallocated or another SQLBindCol() call is made for the same ColumnNumber.

Once the columns have been bound to application variables, the result rows may be fetched using either SQLFetch() or SQLExtendedFetch(). These different fetch methods may not be intermixed. SQLExtendedFetch() has been deprecated in ODBC 3.0, so its use is not recommended.

SQLRETURN SQLFetch         (SQLHSTMT      StatementHandle);
SQLRETURN SQLExtendedFetch (SQLHSTMT      StatementHandle,
                            SQLUSMALLINT  FetchType,
                            SQLINTEGER    irow,
                            SQLUINTEGER  *pcrow,
                            SQLUSMALLINT *rgfRowStatus);

The SQLFetch() function retrieves a single row and places the column values in the host variables associated with them in the preceding SQLBindCol() calls.

SQLExtendedFetch() retrieves one or more rows from the result set (called a rowset) as an array for each bound column. The number of rows in the rowset is determined using the SQL_ROWSET_SIZE statement attribute, which can be set using the SQLSetStmtAttr() function.

FetchType should contain SQL_FETCH_NEXT to retrieve the next row or rowset. Other values available for FetchType are discussed later under the SQLFetchScroll() function when we discuss scrollable cursors.

Getting Column Metadata

If the SQL statement isn't known at the time the program is written, you can find out what the result set looks like at runtime. Use SQLNumResultCols() to find out how many columns were returned, then use SQLDescribeCol() and/or SQLColAttribute() to get the details about each column.

SQLRETURN SQLNumResultCols(SQLHSTMT       StatementHandle,
                           SQLSMALLINT   *pccol);
SQLRETURN SQLDescribeCol  (SQLHSTMT       StatementHandle,
                           SQLUSMALLINT   ColNumber,
                           SQLCHAR       *ColName,
                           SQLSMALLINT    ColNameMaxLen,
                           SQLSMALLINT   *ColNameLen,
                           SQLSMALLINT   *SqlDataType,
                           SQLUINTEGER   *ColLen,
                           SQLSMALLINT   *Scale,
                           SQLSMALLINT   *Nullable);
SQLRETURN SQLColAttribute (SQLHSTMT       StatementHandle,
                           SQLSMALLINT    ColumnNumber,
                           SQLSMALLINT    FieldId,
                           SQLPOINTER     CharAttrPtr,
                           SQLSMALLINT    BufferLength,
                           SQLSMALLINT   *StringLengthPtr,
                           SQLPOINTER     NumericAttributePtr);

Multiple Result Sets

There are times when an SQL statement may return multiple result sets. This may be from a stored procedure or a parameterized query with an array of input parameter values. When there are multiple result sets, they must be retrieved sequentially. To begin processing the next result set, use the SQLMoreResults() function.

SQLRETURN SQLMoreResults (SQLHSTMT StatementHandle);

If the SQLMoreResults() call is successful, the application can begin fetching rows for the new cursor. Don't forget to do SQLBindCol() calls if the result columns are different from the prior result set. When all the result sets have been processed, SQLMoreResults() returns SQL_NO_DATA_FOUND.

Scrollable Cursors

As of version 7, DB2 for OS/390 and z/OS does include support for scrollable cursors. The manuals do not include information on how to use scrollable cursors in ODBC applications, but we will discuss how to use them. Scrollable cursors let you move forward, backward, or randomly through a result set. Scrollable cursors cannot be used in applications that use DB2 private protocol access. Scrollable cursors are also discussed in more detail in Chapter 7, "Application Program Features." Programs use three new functions to use scrollable cursors.

Fetching from Scrollable Cursors

SQLFetchScroll() fetches the specified number of rows from the result set. The cursor can be moved to a relative or absolute position within the result set.

SQLRETURN SQLFetchScroll (SQLHSTMT     StatementHandle,
                          SQLUSMALLINT FetchType,
                          SQLINTEGER   FetchOffset);

The statement uses the FetchType and FetchOffset values to decide where the cursor is to be positioned within the result set. The function can return multiple rows from a single execution. The number of rows to return is set in the SQL_ATTR_ROW_ARRAY_SIZE statement attribute. Allowable FetchType values include the following:

  • SQL_FETCH_NEXT returns the next set of rows following the current cursor position.

  • SQL_FETCH_PRIOR returns the set number of rows starting at the row preceding the current cursor position.

  • SQL_FETCH_RELATIVE returns the set number of rows starting at FetchOffset from the current cursor position.

  • SQL_FETCH_ABSOLUTE returns the set number of rows starting at FetchOffset from the start of the result set.

  • SQL_FETCH_FIRST returns the set number of rows starting at the beginning of the result set.

  • SQL_FETCH_LAST returns the set number of rows before the last row in the result set.

  • SQL_FETCH_BOOKMARK returns the set number of rows from the position identified by the bookmark specified by the SQL_ATTR_FETCH_BOOKMARK_PTR statement attribute.

Positioning Scrollable Cursors

SQLSetPos() positions the cursor on a specific row of the result set. It can also be used to refresh, update, or to delete the entire row.

SQLRETURN SQLSetPos (SQLHSTMT     StatementHandle,
                     SQLUSMALLINT RowNumber,
                     SQLUSMALLINT Operation,
                     SQLSMALLINT  LockType);

The RowNumber value specifies the absolute position within the result set. Use 1 to position at the first row. If 0 is specified the Operation parameter is performed for the entire result set. The Operation parameter can have the following values:

  • SQL_POSITION for positioning the cursor at RowNumber without refreshing any data.

  • SQL_REFRESH for positioning the cursor at RowNumber and refreshing the data. The WHERE clause is not reapplied, so any modified rows in the result set may still show up.

  • SQL_UPDATE for positioning the cursor at RowNumber and updating the row with values from the buffer.

  • SQL_DELETE for positioning the cursor at RowNumber and deleting that row.

The only value that DB2 ODBC supports for the LockType parameter is SQL_LOCK_TYPE_CHANGE. This retains the locks taken prior to the SQLSetPos() call.

Bulk Operations on Scrollable Cursors

SQLBulkOperations() allows mass operations against the result set of a scrollable cursor query. New rows can be added. Mass updates or deletes can be performed on bookmarked rows.

SQLRETURN SQLBulkOperations (SQLHSTMT    StatementHandle,
                             SQLSMALLINT Operation);


100 - ODBC Stored Procedures

Chapter 11. ODBC/CLI Programming

ODBC Stored Procedures

Although embedded SQL stored procedures provide the most advantages, application developers who have existing DB2 ODBC applications might wish to move components of the application to run on the server. In order to minimize the required changes to the code and logic of the application, these components can be implemented by writing stored procedures using DB2 ODBC. Autocommit must be turned off and a null connection should be used.

The MVSATTACHTYPE keyword should be set to RRSAF if the stored procedure contains any LOB data types or distinct types in its parameter list. DB2 for OS/390 and z/OS requires that stored procedures containing any LOBs or distinct types must run in a WLM-established stored procedure address space.

Programming Stored Procedures to Return Result Sets

In a stored procedure, DB2 ODBC uses cursors declared WITH RETURN. Cursors that are closed before the stored procedure exit are local cursors. Cursors that remain open return result sets. In order for a DB2 ODBC stored procedure to return a result set, it must not close the cursor and it must not free the statement handle, the connection handle, or the environment handle.


101 - Error Handling and Problem Determination

Chapter 11. ODBC/CLI Programming

Error Handling and Problem Determination

DB2 ODBC functions return their status as an integer return code, indicated by the SQLRETURN data type. This return code can have several values, documented in Table 11-1.

Table 11-1. Status Return Codes of DB2 ODBC Functions

RETURN CODE

EXPLANATION

SQL_SUCCESS

The function completed successfully; no additional SQLSTATE information is available.

SQL_SUCCESS_WITH_INFO

The function completed successfully with a warning or other information. Call SQLGetDiagRec() to receive the SQLSTATE and any other informational messages or warnings.

SQL_NO_DATA_FOUND

The function returned successfully, but no relevant data was found. When this is returned after the execution of an SQL statement, additional information might be available, which can be obtained by calling SQLGetDiagRec().

SQL_NEED_DATA

The application tried to execute an SQL statement, but DB2 ODBC lacks parameter data that the application had indicated would be passed at execute time.

SQL_ERROR

The function failed. Call SQLGetDiagRec() to receive the SQLSTATE and any other error information.

SQL_INVALID_HANDLE

The function failed due to an invalid input handle (environment, connection, or statement handle). This is a programming error. No further information is available.

Retrieving Diagnostic Information

The SQLGetDiagRec() function is used to retrieve additional diagnostic information following an unsuccessful DB2 ODBC call or if the SQLRETURN value is SQL_SUCCESS_WITH_INFO. It may be called after any function call.

SQLRETURN  SQLGetDiagRec  (SQLSMALLINT  HandleType,
                           SQLHANDLE    Handle,
                           SQLSMALLINT  RecNumber,
                           SQLCHAR     *SQLState,
                           SQLINTEGER  *NativeErrorPtr,
                           SQLCHAR     *MessageText,
                           SQLSMALLINT  BufferLength,
                           SQLSMALLINT *TextLengthPtr);

This returns the current values of multiple fields of a diagnostic record that contains error, warning, and status information. Information returned includes the SQLSTATE, the native error code, and the error message text.

If the application calls any function other than SQLGetDiagRec(), diagnostic information from the previous calls is lost.

An application can scan all diagnostic records by looping, incrementing RecNumber, as long as SQLGetDiagRec() returns SQL_SUCCESS. Calls to SQLGetDiagRec() are nondestructive to the diagnostic record fields. The application can call SQLGetDiagRec() again at a later time to retrieve a field from a record as long as no other function except SQLGetDiagRec() has been called in the interim.

DB2 programmers are used to dealing with a diagnostic structure called the SQLCA. A DB2 extension to the ODBC and CLI specifications allows a DB2 ODBC program to retrieve this structure. SQLGetSQLCA() is used to return the SQLCA associated with preparing and executing a SQL statement, fetching data, or closing a cursor. The SQLCA can return information that supplements the information obtained by using SQLGetDiagRec().

SQLRETURN SQLGetSQLCA (SQLHENV       EnvironmentHandle,
                       SQLHDBC       ConnectionHandle,
                       SQLHSTMT      StatementHandle,
                       struct sqlca *pSqlca );

Application Trace

DB2 ODBC has two trace options, the diagnostic trace and the application trace. Traces are turned on by entries in the initialization file. The DB2 ODBC diagnostic trace captures information to use in DB2 ODBC problem determination. The trace is intended for use under the direction of the IBM Support Center.

The application trace is designed for diagnosis of application errors. When activated, every ODBC call is traced, and information about the call, including input parameters, is written to a trace file. In the following example, the trace is written to the file allocated to the APLTRACE DD statement.

[COMMON]
APPLTRACE=1
APPLTRACEFILENAME="DD:APLTRACE"


102 - Sample Program

Chapter 11. ODBC/CLI Programming

Sample Program

/* Standard C/C++ Headers */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* DB2 ODBC Header */
#include <sqlcli1.h>

/* DB2 SQLCA */
#include <sqlca.h>

/* Local Function Definitions */
int ErrorHandler(SQLRETURN rc,
                 char*     errstring,
                 SQLHENV   henv,
                 SQLHDBC   hdbc,
                 SQLHSTMT  hstmt);
/* Main Program */
int main(int argc, char** argv)
{
   /* Handles */
   SQLHENV  henv = SQL_NULL_HENV;
   SQLHDBC  hdbc = SQL_NULL_HDBC;
   SQLHSTMT hstmt= SQL_NULL_HSTMT;

   /* Local variables */
   SQLRETURN   rc;
   SQLCHAR     statement[32761];
   SQLINTEGER  totaltaken = 0;
   SQLINTEGER  totaltakenlen = sizeof(totaltaken);
   SQLCHAR     testout[7];
   SQLINTEGER  testoutlen = 0;
   SQLCHAR     nameout[51];
   SQLINTEGER  nameoutlen = 0;
   char*        errstring;
   errstring="Allocate Environment Handle";
   rc = SQLAllocHandle(SQL_HANDLE_ENV,
                       SQL_NULL_HANDLE,
                       &henv);
   if(rc != SQL_SUCCESS)
      ErrorHandler(rc, errstring, henv, hdbc, hstmt);

   errstring="Allocate Connection Handle";
   rc = SQLAllocHandle(SQL_HANDLE_DBC,
                       henv,
                       &hdbc);
   if(rc != SQL_SUCCESS)
      ErrorHandler(rc, errstring, henv, hdbc, hstmt);

   errstring="Null Connect";
   rc = SQLConnect(hdbc,
                   0, 0,
                   0, 0,
                   0, 0);
   if(rc != SQL_SUCCESS)
      ErrorHandler(rc, errstring, henv, hdbc, hstmt);

   errstring="Allocate Statement Handle";
   rc = SQLAllocHandle(SQL_HANDLE_STMT,
                       hdbc,
                       &hstmt);
   if(rc != SQL_SUCCESS)
      ErrorHandler(rc, errstring, henv, hdbc, hstmt);

   errstring="Insert some data";
   strcpy(statement,"INSERT INTO DB2USER1.TEST ");
   strcat(statement," (NUMBER, NAME, TYPE, LENGTH)");
   strcat(statement," VALUES('910','ODBC Test 1','B',90);");
   rc = SQLExecDirect(hstmt,
                      statement,
                      SQL_NTS);
   if(rc != SQL_SUCCESS)
      ErrorHandler(rc, errstring, henv, hdbc, hstmt);

   errstring="Insert more data";
   strcpy(statement,"INSERT INTO DB2USER1.TEST ");
   strcat(statement," (NUMBER, NAME, TYPE, LENGTH)");
   strcat(statement," VALUES('912','ODBC Test 2','B',90);");
   rc = SQLExecDirect(hstmt,
                      statement,
                      SQL_NTS);
   if(rc != SQL_SUCCESS)
      ErrorHandler(rc, errstring, henv, hdbc, hstmt);
   errstring="Set up for retrieval";
   strcpy(statement,"SELECT NUMBER, NAME");
   strcat(statement,"  FROM DB2USER1.TEST");
   strcat(statement," WHERE TOTALTAKEN = ?");
   strcat(statement," ORDER BY NUMBER;");

   rc = SQLPrepare(hstmt,
                   statement,
                   strlen(statement));
   if(rc != SQL_SUCCESS)
      ErrorHandler(rc, errstring, henv, hdbc, hstmt);

   errstring="Input Parameter for Where Clause";
   rc = SQLBindParameter(hstmt, 1,
                         SQL_PARAM_INPUT,
                         SQL_C_LONG,
                         SQL_INTEGER,
                         sizeof(totaltaken),
                         0,
                         &totaltaken,
                         sizeof(totaltaken),
                         &totaltakenlen
                         );
   if(rc != SQL_SUCCESS)
      ErrorHandler(rc, errstring, henv, hdbc, hstmt);

   /* Set Value for Where Clause */
   totaltaken = 0;

   errstring="Run the Statement";
   rc = SQLExecute(hstmt);
   if(rc != SQL_SUCCESS)
      ErrorHandler(rc, errstring, henv, hdbc, hstmt);

   errstring="Result Columns";
   rc = SQLBindCol(hstmt, 1,
                   SQL_C_CHAR,
                   testout,
                   sizeof(testout),
                   &testoutlen);
   if(rc != SQL_SUCCESS)
      ErrorHandler(rc, errstring, henv, hdbc, hstmt);
   rc = SQLBindCol(hstmt, 1,
                   SQL_C_CHAR,
                   nameout,
                   sizeof(nameout),
                   &nameoutlen);
   if(rc != SQL_SUCCESS)
      ErrorHandler(rc, errstring, henv, hdbc, hstmt);

   errstring="Fetch Results";
   while((rc = SQLFetch(hstmt)) == SQL_SUCCESS
         || rc == SQL_SUCCESS_WITH_INFO)
   {
     /* Print data */
     printf("Test %s: %s\n", testout, nameout);
   }

   if(rc != SQL_NO_DATA_FOUND)
      ErrorHandler(rc, errstring, henv, hdbc, hstmt);

   errstring="Close Cursor";
   rc = SQLCloseCursor(hstmt);
   if(rc != SQL_SUCCESS)
      ErrorHandler(rc, errstring, henv, hdbc, hstmt);

   errstring="Free Statement Resources";
   rc = SQLFreeStmt(hstmt, SQL_RESET_PARAMS);
   if(rc != SQL_SUCCESS)
      ErrorHandler(rc, errstring, henv, hdbc, hstmt);

   errstring="Free Statement Handle";
   rc = SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
   if(rc != SQL_SUCCESS)
      ErrorHandler(rc, errstring, henv, hdbc, hstmt);

   errstring="Disconnect";
   rc = SQLDisconnect(hdbc);
   if(rc != SQL_SUCCESS)
      ErrorHandler(rc, errstring, henv, hdbc, hstmt);

   errstring="Free Connection Handle";
   rc = SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
   if(rc != SQL_SUCCESS)
      ErrorHandler(rc, errstring, henv, hdbc, hstmt);

   errstring="Free Environment Handle";
   rc = SQLFreeHandle(SQL_HANDLE_ENV, henv);
   if(rc != SQL_SUCCESS)
      ErrorHandler(rc, errstring, henv, hdbc, hstmt);

   return 0;
}

/* ErrorHandler()      */
/* - Print Diagnostics */
int ErrorHandler(SQLRETURN rc,
                 char*     errstring,
                 SQLHENV   henv,
                 SQLHDBC   hdbc,
                 SQLHSTMT  hstmt)
{
   SQLCHAR     buffer[SQL_MAX_MESSAGE_LENGTH + 1];
   SQLCHAR     msqlstate[SQL_SQLSTATE_SIZE + 1];
   SQLINTEGER  msqlcode;
   SQLSMALLINT length, i;
   SQLRETURN   prc;
   struct sqlca sqlca;
   memset(&sqlca, '\0', sizeof(sqlca));

   printf("\nError: %s\n\n", errstring);
  /* Environment Messages */
  if(henv != SQL_NULL_HENV)
  {
     i = 1;
     while(SQLGetDiagRec(SQL_HANDLE_ENV,

                           henv,
                           i,
                           msqlstate,
                           &msqlcode,
                           buffer,
                           SQL_MAX_MESSAGE_LENGTH + 1,
                           &length ) == SQL_SUCCESS)
       {
          printf( "Env SQLSTATE: %s\n", msqlstate ) ;
          printf( "Env Native Error Code: %ld\n", msqlcode ) ;
          printf( "Env buffer: %s \n", buffer ) ;
          i++ ;
       }
    }

/* Connection Messages */
if(hdbc != SQL_NULL_HDBC)
{
   i = 1;
      while(SQLGetDiagRec(SQL_HANDLE_DBC,
                           hdbc,
                           i,
                           msqlstate,
                           &msqlcode,
                           buffer,
                           SQL_MAX_MESSAGE_LENGTH + 1,
                           &length ) == SQL_SUCCESS)
       {
          printf( "Dbc SQLSTATE: %s\n", msqlstate ) ;
          printf( "Dbc Native Error Code: %ld\n", msqlcode ) ;
          printf( "Dbc buffer: %s \n", buffer ) ;
          i++ ;
       }
    }

/* Statement Messages */
if(hstmt != SQL_NULL_HSTMT)
{
   i = 1;
      while(SQLGetDiagRec(SQL_HANDLE_STMT,
                           hstmt,
                           i,
                           msqlstate,
                           &msqlcode,
                           buffer,
                           SQL_MAX_MESSAGE_LENGTH + 1,
                           &length ) == SQL_SUCCESS)
       {
          printf( "Stmt SQLSTATE: %s\n", msqlstate ) ;
          printf( "Stmt Native Error Code: %ld\n", msqlcode ) ;
          printf( "Stmt buffer: %s \n", buffer ) ;
          i++ ;
       }
    }

    if(SQLGetSQLCA(henv, hdbc, hstmt, &sqlca) == SQL_SUCCESS)
    {
        printf("SQLCA SQLCODE = %d\n", SQLCODE);
    }

   if(rc != SQL_SUCCESS_WITH_INFO)
   {
      abort();
   }

   return 0;
}


103 - Summary

Chapter 11. ODBC/CLI Programming

Summary

There are many ODBC functions available, and this chapter has only touched the surface of what can be done. The specification allows application programs to inquire into the supported and unsupported features of the drivers, find out what tables and stored procedures are available, dynamically determine the columns in a result set, and much more.


104 - Additional Resources

Chapter 11. ODBC/CLI Programming

Additional Resources

DB2 Universal Database for OS/390 and z/OS ODBC Guide and Reference SC26-9941

A Complete Guide to DB2 Universal Database by Don Chamberlain. 1998 Morgan Kaufmann Publishers, Inc. ISBN 1-55860-482-0


105 - Chapter 12. DB2 Traditional Programming

Part 4. Programming and Language Environments

Chapter 12. DB2 Traditional Programming

  • COBOL

  • C and C++

  • REXX

There are several languages that can be used to code application programs that can communicate with DB2. We will take a look at how to use some of the more popular languages.


106 - COBOL

Chapter 12. DB2 Traditional Programming

COBOL

COBOL is a traditional and very common mainframe programming language that is utilized for a variety of business applications. COBOL programs can be online or batch programs. COBOL programs can run in any OS/390 address space, can execute under a variety of transaction managers such as CICS, and can be used for DB2 stored procedures and user-defined functions. COBOL is one of the most common programming languages, and there are many billions of lines of COBOL code in use today.

COBOL API

DB2 provides a COBOL API that allows you to embed static or dynamic SQL into a COBOL program. You can code SQL statements in the COBOL program sections, which are listed in Table 12-1.

Table 12-1. COBOL Program Sections for SQL Statements

SQL Statement

Program Section

BEGIN DECLARE SECTION

Working-storage section or linkage section

END DECLARE SECTION

Working-storage section or linkage section

INCLUDE SQLCA

Working-storage section or linkage section

INCLUDE text-file-name

Data division or procedure division

DECLARE TABLE

Data division or procedure division

DECLARE CURSOR

Data division or procedure division

Other

Procedure division

NOTE

When including host variable declarations in an included text file, the INCLUDE statement must be in the working-storage section or linkage section.

Embedding SQL in a COBOL Program

Each SQL statement in a COBOL program must begin with EXEC SQL and end with END-EXEC. If the SQL statement is embedded between two COBOL statements, the period at the end of the END-EXEC is optional and might not be appropriate. If the SQL statement is embedded in a COBOL IF...ELSE expression, the period should be left off the end of the SQL statement in order to avoid inadvertently terminating the IF...ELSE expression. The EXEC and SQL keywords must appear on the same line of the program, after which the rest of a statement can appear on any number of lines. Here is an example of an embedded SQL statement in a COBOL program:

EXEC SQL
INSERT INTO YLA.TABLE1 VALUES(:VAR1, :VAR2, DEFAULT)
END-EXEC.

A COBOL program that contains SQL statements must include either a SQLCODE or SQLSTATE host variable, or both. The program can either define these variables, or you can use an INCLUDE SQLCA statement to include the SQL communications area (SQLCA) within the program. The SQLCA structure contains both the SQLSTATE and SQLCODE variables.

The COBOL program should include the statement DECLARE TABLE to describe each table and view the program accesses. You can use the DB2 declarations generator (DCLGEN) to generate DECLARE TABLE statements. You should include the DCLGEN members in the data division. Refer to Chapter 5, "Using SQL in an Application Program," to create the DCLGEN. The INCLUDE statement can be used to include table declarations, host variable declarations, and SQL statements from members of a partitioned dataset at precompile time.

Dynamic SQL statements can be coded into COBOL programs. COBOL programs can handle dynamic SQL statements if the data types and the number of fields returned are fixed. If you need to use variable-list SELECT statements in your COBOL program, then you must use a SQL descriptor area (SQLDA) within your program.

Host Variable Declarations

You must explicitly declare all host variables used in SQL statements in the working-storage section or linkage section of your program's data division. You must explicitly declare each host variable before it is first used in any SQL statement. You can precede the COBOL statements that define the host variables with the statement BEGIN DECLARE SECTION and follow the statements with the statement END DECLARE SECTION. A colon (:) must precede all host variable references in a SQL statement. There are numerous mappings between SQL data types and the equivalent COBOL variable declarations. Table 12-2 lists only the most typical data type mappings:

Table 12-2. SQL and COBOL Data Type Mappings

SQL Data Type

COBOL Data Type

SMALLINT

S9(4) COMP-4

INTEGER

S9(9) COMP-4

DECIMAL(p,s) or NUMERIC(p,s)

S9(p-s)V9(s) COMP-3

CHAR(n)

X(n)

VARCHAR(n)

01 VAR-NAME.

49 VAR-LEN PIC S9(4) USAGE BINARY.

49 VAR-TXT PIC X(n)

DATE

X(10)

TIMESTAMP

X(26)

In addition to these and many other basic data type mappings, there are several special-purpose COBOL data types, including result set locators used for processing result sets returned from stored procedures, table locators used for accessing transition tables created by a trigger and passed to a user-defined function or a stored procedure, LOB data types, LOB locators used to avoid the materialization of LOBs in an application program, and the ROWID data type.

Indicator Variables

Indicator variables are used in a COBOL program to indicate a null value for an optional DB2 table column. Your COBOL program will have to interpret or set the indicator variable in order to deal with optional columns. The indicator variable is typically set to 0 to indicate the presence of a value and 1 to indicate the null value. You declare indicator variables just as you would a SMALLINT variable in your program. You reference the indicator in your SQL statements immediately following the variable for the optional column to which they relate. For example,

EXEC SQL
   FETCH CURSOR1 INTO :VAR1 :VAR1-IND
END EXEC.

The above statement fetches a column from a DB2 cursor into the COBOL variable VAR1, and since the column in this case is optional, the indicator variable is placed in the COBOL variable VAR1-IND. The indicator variable can then be tested in program logic or referenced in further SQL statements to determine whether or not the value of VAR1 is null.

Error Handling

The SQLCODE or SQLSTATE variables should be tested after each SQL statement called. The DSNTIAR program can be used to help interpret SQL errors when detected. The DSNTIAR program is called from your COBOL program with the SQLCA as an input parameter. DSNTIAR then places an English message in an output parameter. This message can then be used as part of a display of the error in the program.

COBOL Program Example

The following simple COBOL program processes a single DB2 cursor, and displays the result:

IDENTIFICATION DIVISION.
PROGRAM-ID. YLAPROG1.
AUTHOR.
REMARKS.
***********************************************************
*                                                         *
* THIS PROGRAM USES COBOL TO READ THE                     *
* DB2 SYSDUMMY1 CATALOG TABLE, AND DISPLAY THE RESULT.    *
*                                                         *
***********************************************************

ENVIRONMENT DIVISION.

DATA DIVISION.

WORKING-STORAGE SECTION.

***********************************************************
* SQLCA                                                   *
***********************************************************
EXEC SQL
   INCLUDE SQLCA
END-EXEC.

***********************************************************
* DECLARATION OF SYSDUMMY1 TABLE                          *
***********************************************************
EXEC SQL DECLARE SYSIBM.SYSDUMMY1 TABLE
   (IBMREQD     CHAR(1) NOT NULL)
END-EXEC.

***********************************************************
* HOST VARIABLE DECLARATIONS                              *
***********************************************************
01 SYSDUMMY1-TBL.
   05 IBMREQD-CDE      PIC X(1).

***********************************************************
* DB2 CURSOR DECLARATION                                  *
***********************************************************
EXEC SQL DECLARE CURS1 CURSOR FOR
   SELECT IBMREQD
   FROM   SYSIBM.SYSDUMMY1
END-EXEC.

***********************************************************
* BEGIN THE PROGRAM                                       *
***********************************************************
PROCEDURE DIVISION.
PERFORM A100-OPEN.
PERFORM A200-FETCH
   UNTIL SQLCODE IS NOT EQUAL TO ZERO.
PERFORM A300-CLOSE.

PROGRAM-END.
   GOBACK.

A100-OPEN.
   EXEC SQL
      OPEN CURS1
   END-EXEC.
   IF SQLCODE IS NOT EQUAL TO ZERO
      DISPLAY 'SQLCODE FROM OPEN IS ' SQLCODE
      GOTO PROGRAM-END
      END-IF.

A200-FETCH.
   EXEC SQL
      FETCH CURS1 INTO :IBMREQD-CDE
   END-EXEC.
   IF SQLCODE IS EQUAL TO ZERO
      DISPLAY 'IBMREQD CODE IS ' IBMREQD-CDE
   ELSE
      DISPLAY 'SQLCODE FROM FETCH IS ' SQLCODE
      GOTO PROGRAM-END
      END-IF.

A300-CLOSE.
   EXEC SQL
      CLOSE CURS1
   END-EXEC.


107 - C and C++

Chapter 12. DB2 Traditional Programming

C and C++

C is an extremely flexible and very common mainframe programming language that is currently utilized for a variety of business and scientific applications. C can be used in either online or batch programs. C programs can run in any OS/390 address space, can execute under a variety of transaction managers such as CICS, and can be used as DB2 stored procedures or external user-defined functions.

C API

DB2 provides a C API that allows you to embed static or dynamic SQL into a C program. You can code SQL statements in a C program anywhere in which you can code an executable statement.

Embedding SQL in a C Program

Each SQL statement in a C program must begin with EXEC SQL and end with a semicolon (;). The EXEC and SQL keywords must appear on the same line of the program, after which the rest of a statement can appear on any number of lines. In general, because C is case-sensitive, use uppercase letters to enter SQL words. You must keep the case of host variable names consistent throughout the program. For example, if a host variable name is in lowercase in its declaration, then it must be in lowercase in all SQL statements. Here is an example of an embedded SQL statement in a C program:

EXEC SQL
   INSERT INTO YLA.TABLE1 VALUES( :var1, :var2, DEFAULT);

A C program that contains SQL statements must include either a SQLCODE or SQLSTATE host variable, or both. The program can either define these variables or you can use an INCLUDE SQLCA statement to include the SQLCA within the program. The SQLCA structure contains both the SQLSTATE and SQLCODE variables.

The C program should include the statement DECLARE TABLE to describe each table and view the program accesses. You can use the DB2 DCLGEN to generate DECLARE TABLE statements. Refer to Chapter 5 to create the DCLGEN. The INCLUDE SQL statement can be used to include table declarations, host variable declarations, and SQL statements from members of a partitioned dataset at precompile time. You should not use the C++ INCLUDE statement to include SQL statements containing C host variable declarations.

Dynamic SQL statements can be coded into C programs. C programs can handle dynamic SQL statements if the data types and the number of fields returned are fixed. If you need to use variable-list SELECT statements in your C program, then you must use a SQLDA within your program.

Host Variable Declarations

You must explicitly declare each host variable before its first use in a SQL statement. You must precede the C statements that define the host variables with the statement BEGIN DECLARE SECTION and follow the statements with the statement END DECLARE SECTION. You can have more than one host variable declaration section in your program. A colon (:) must precede all host variable references in a SQL statement. There are numerous mappings between SQL data types and the equivalent C variable declarations. Table 12-3 lists only the most typical data type mappings.

NOTE

There is no native decimal C data type. IBM does provide a decimal.h header file to provide compatibility for C programs. This header file does not work for C++ programs. C programmers also typically write their own conversion routines to deal with the decimal data type. However, another common technique is to use the REAL or DOUBLE SQL data types in place of DECIMAL.

NOTE

You should always allow for an extra byte of storage for all string host variables greater than a single character to allow for the null-termination. DB2 will insert characters from variable or fixed-length character fields that are less than the length of the host variable, and then append the null-terminator.

Table 12-3. SQL and C Data Type Mappings

SQL Data Type

C Data Type

SMALLINT

short int

INTEGER

long int

DECIMAL(p,s)

decimal

NUMERIC(p,s)

decimal

CHAR(1)

single-character form char

CHAR(n)

no exact equivalent; if n > 1 use a null-terminated character array of length n + 1: char[n + 1]

VARCHAR(n)

null-terminated character array length n + 1 or

Struct {short len;

char data[n];

} var1;

DATE

null-terminated character array of length 11: char[11]

TIMESTAMP

null-terminated character array of length 26: char[26]

REAL

float

DOUBLE PRECISION

double

In addition to these and many other basic data type mappings, there are several special-purpose C data types, including result set locators used for processing result sets returned from stored procedures, table locators used for accessing transition tables created by a trigger and passed to a user-defined function or a stored procedure, LOB data types, LOB locators used to avoid the materialization of LOBs in an application program, and the ROWID data type.

Indicator Variables

C and SQL differ in the way they use the word null. The C language has a null character (NUL), a null pointer (NULL), and a null statement (just a semicolon). The C NUL character is a single character, which compares equal to 0. DB2 will append the NUL on the end of any character array host variable, including those of length 0. The DB2 NULL indicates the absence of a value for a table column. Indicator variables are used in a C program to indicate a null value for an optional DB2 table column. Your C program will have to interpret or set the indicator variable in order to deal with optional columns. The indicator variable is typically set to 0 to indicate the presence of a value and onset to 1 to indicate the null value. You declare indicator variables just as you would a SMALLINT variable in your program. You reference the indicator in your SQL statements immediately following the variable for the optional column to which it relates. For example,

EXEC SQL
   FETCH CURSOR1 INTO :var1 :var1-ind;

The above statement fetches a column from a DB2 cursor into the C variable var1, and since the column in this case is optional, the indicator variable is placed in the C variable var1-ind, which is a short integer. The indicator variable can then be tested in program logic or referenced in further SQL statements to determine whether or not the value of var1 is null. Remember, this is a test of the DB2 null value.

Error Handling

The SQLCODE or SQLSTATE variables should be tested after each SQL statement called. The DSNTIAR program can be used to help interpret SQL errors when detected. The DSNTIAR program is called from your C program with the SQLCA as an input parameter. DSNTIAR then places an English message in an output parameter. This message can then be used as part of a printf of the error in the program.

C Program Example

The following simple C program processes a single DB2 cursor and displays the result:

/********************************************************/
/* This simple c program reads the SYSIBM.SYSDUMMY1 DB2 */
/* catalog table, and displays the results. It also     */
/* gets the current date to demonstrate the use of a    */
/* null-terminated character array                      */
/********************************************************/

#include "stdio.h"
#include "stdefs.h"

void main(void) {

EXEC SQL INCLUDE SQLCA;

/* Include the host variables */
EXEC SQL BEGIN DECLARE SECTION;

char ibmreqd;
char cdate[11];

EXEC SQL END DECLARE SECTION;

/* Declare the SYSDUMMY1 table */
EXEC SQL DECLARE SYSIBM.SYSDUMMY1 TABLE
   (IBMREQD     CHAR(1) NOT NULL);

/* Declare the cursor */
EXEC SQL DECLARE CURS1 CURSOR FOR
   SELECT IBMREQD, CURRENT DATE
   FROM   SYSIBM.SYSDUMMY1;

/* Begin the execution */
EXEC SQL
   OPEN CURS1;
if (SQLCODE != 0) {
   printf("SQLCODE is %d\n",SQLCODE);
   return;
   }

while (SQLCODE != 0) {
   EXEC SQL FETCH CURS1 INTO :ibmreqd, :cdate;
   if (SQLCODE == 0) {
      printf("ibmreqd is %c\n",ibmreqd);
      printf("cdate is %c\n",cdate);
      }
   if (SQLCODE != 0 and SQLCODE != 100) {
      printf("SQLCODE is %d\n",SQLCODE);
      }
   }

EXEC SQL
   CLOSE CURS1;

return;
}


108 - REXX

Chapter 12. DB2 Traditional Programming

REXX

The OS/390 REXX language offers an interface to DB2 so that REXX programs can use SQL DML and execute IFI commands. Even though REXX is an interpreted language, DB2 provides the same capabilities as other languages in that a REXX program can run in any OS/390 address space, and REXX programs can run as stored procedures. In fact, a stored procedure written in REXX was delivered with this feature, as it is one of the many components of the SQL procedures implementation.

You can write SQL application programs in the REXX programming language, and dynamic SQL is issued from REXX with no precompiles or link edit. REXX is an interpreted language and has been around for a long time. It is SYSPROG and "techie-loved," and you can build quick and easy scripts in REXX. The REXX language can be used for DB2 stored procedures and is supported across the DB2 family.

REXX stored procedures are written in the interpreted language of REXX with no precompiler, compiler, or linker. They can contain SQL, and the SQLCA is automatically included. All parameters are passed as strings, and integers are passed as numeric strings. There is only one OUT parameter allowed. This is basically simple syntax to identify to REXX a SQL string, allowing retrieval, storing, and processing of DB2 data.

Prior to the REXX/DB2 API, we needed freeware or vendor utilities to execute REXX. REXX is an interpretive string-based language. This allows for dynamic SQL execution via REXX. We can put programs and queries for DBA functions (such as REORGs) into a REXX stored procedure and have the ability to execute it remotely. The ability to quickly and easily write applications in REXX makes it a powerful scripting language to generate reports or commands from DB2 objects, such as the system catalog. Scripting languages have been used extensively on Windows and UNIX platforms to aid DBAs and developers with the development of simple tools to produce reports, generate SQL or commands, debug SQL statements, emulate table access sequences, and create simple applications. The REXX API allows this same sort of functionality on the OS/390 or z/OS platforms.

NOTE

REXX is not for performance as much as it is for function. This is an interpretive language using dynamic SQL, and the interpretive nature of REXX is suited for ease of use and power, not for high performance.

REXX API

The DB2 REXX language support includes the following application programming interfaces:

The CONNECT API, which provides the connection to the appropriate subsystem using the user ID assigned to the address space from which the REXX application is executing:

ADDRESS DSNREXX 'CONNECT' '<subsystem id or REXX variable'

The EXECSQL API, which executes SQL statements in the REXX procedure:

ADDRESS DSNREXX 'EXECSQL' '<SQL statement or REXX variable>'

The DISCONNECT API, which releases all acquired DB2 resources and disconnects from the subsystem:

ADRESS DSNREXX 'DISCONNECT'

Error Handling

DB2 automatically provides a SQLCA to a REXX procedure in either a separate set of variables or a REXX compound variable, depending upon the manner in which the connection is performed. The SQLCODE or SQLSTATE variables can be tested after each SQL statement execution, as can the REXX RC return code variable, which is set according to Table 12-4.

Table 12-4. REXX RC Return Codes

Return code

Meaning

0

No SQL warning or error occurred

1

A SQL warning occurred

1

A SQL error occurred

Embedding SQL in a REXX Program

You can code SQL statements in your REXX program anywhere you can issue REXX commands. The SQL statements must be directed to the DSNREXX external environment either by preceding each SQL statement with the ADDRESS DSNREXX command or by issuing the ADDRESS DSNREXX command, without any SQL command following it, to inform REXX that external commands will be going the DSNREXX environment. DB2 REXX Language Support allows all SQL statements that DB2 for OS/390 or z/OS supports, except the following:

BEGIN DECLARE SECTION
END DECLARE SECTION
DECLARE STATEMENT
INCLUDE
SELECT INTO
WHENEVER

Each SQL statement must begin with EXECSQL and either be enclosed in single or double quotes, or be a REXX variable reference. For example,

EXECSQL "COMMIT"
EXECSQL 'COMMIT'

SQLSTMT="COMMIT"
EXECSQL SQLSTMT

These are all valid executions of a COMMIT statement. In addition, SQL statements can begin or end anywhere on a line and can be continued by utilizing commas or concatenation operators and commas:

EXECSQL,
"SET :TSTAMP = ", ||
"CURRENT TIMESTAMP"

"EXECSQL " ||,
" SET :TSTAMP = " ||,
" CURRENT TIMESTAMP"

REXX DB2 Application Support provides specific names for cursors and prepared statements that must be used within your DB2 REXX program.

C1 to C100: Cursor names for DECLARE CURSOR, OPEN, CLOSE, and FETCH statements. By default, C1 to C50 are defined with the WITH RETURN clause, and C51 to C100 are defined with the WITH HOLD clause. You can use the ATTRIBUTES clause of the PREPARE statement to override these attributes to make your cursor scrollable.

C101 to C200: Cursor names for ALLOCATE, DESCRIBE, FETCH, and CLOSE statements that are used to retrieve result sets in a program that calls a stored procedure.

S1 to S100: Prepared statement names for DECLARE STATEMENT, PREPARE, DESCRIBE, and EXECUTE statements.

You can use only the predefined names, and when you associate a cursor name with a statement name in a DECLARE CURSOR statement, the cursor name and the statement must have the same number. For example,

EXECSQL 'DECLARE C1 CURSOR FOR S1'

REXX Programming Examples

Cursor Processing

The following simple example establishes a connection to DB2 and then opens and fetches from a simple cursor:

/*REXX*/
/* CHECK TO SEE IF THE REXX/DB2 COMMAND ENVIRONMENT IS AVAILABLE */
/* IF IT IS NOT, THEN ESTABLISH IT.                              */
/* THEN CONNECT TO THE APPROPRIATE DATABASE (SUBSYSTEM)          */
/*                                                               */
/* TRACE ?I   */
'SUBCOM DSNREXX'
IF RC THEN
   S_RC = RXSUBCOM('ADD','DSNREXX','DSNREXX')
ADDRESS DSNREXX "CONNECT" "DSN1"
IF SQLCODE \= "0" THEN
   DO
    SAY "FAILURE TO CONNECT TO DATABASE"
    EXIT 8
   END

/* SET A VARIABLE EQUAL TO THE DESIRED SQL STATMENT.             */
/*                                                               */
SQLSTMT="SELECT 'HELLO' FROM SYSIBM.SYSDUMMY1"

/* PREPARE THE STATEMENT FOR EXECUTION BY DECLARING THE CURSOR,  */
/* DOING A PREPARE OF THE STATEMENT, AND OPENING THE CURSOR.     */
/*                                                               */
ADDRESS DSNREXX
"EXECSQL DECLARE C1 CURSOR FOR S1"
IF SQLCODE \= "0" THEN
   DO
    SAY "DECLARE CURSOR FAILED WITH SQLCODE = " SQLCODE
    EXIT 8
   END
"EXECSQL PREPARE S1 FROM :SQLSTMT"
IF SQLCODE \= "0" THEN
   DO
    SAY "PREPARE FAILED WITH SQLCODE = " SQLCODE
    EXIT 8
   END
"EXECSQL OPEN C1"
IF SQLCODE \= "0" THEN
   DO
    SAY "OPEN FAILED WITH SQLCODE = " SQLCODE
    EXIT 8
   END

/*                                                               */
/* FETCH LOOP. FOR EACH ROW RETURNED SHOW THE RESULT             */
/*                                                               */
JOBCNT = 0
DO UNTIL SQLCODE \= "0"
   "EXECSQL FETCH C1 INTO :TESTMSG"   IF SQLCODE = "0" THEN
      DO
       SAY TESTMSG
       END
   END

/* HERE THE FETCH LOOP HAS ENDED (SQLCODE <> 0), WHY?            */
/*                                                               */
SELECT
     WHEN SQLCODE = 0 THEN DO
       END
     WHEN SQLCODE = 100 THEN DO
       END
     OTHERWISE
       SAY "FETCH FAILED WITH SQLCODE = " SQLCODE
       SAY SQLERRM
   END

/* ALL IS WELL, SO THE CURSOR IS CLOSED.                         */
/*                                                               */
"EXECSQL CLOSE C1"
IF SQLCODE \= "0" THEN
   DO
    SAY "CLOSE FAILED WITH SQLCODE = " SQLCODE
   END

/* CLEANUP.                                                      */
/* DISCONNECT FROM THE DATABASE, AND RELEASE ALLOCATIONS.        */
/*                                                               */
ADDRESS DSNREXX "DISCONNECT"
S_RC = RXSUBCOM('ADD','DSNREXX','DSNREXX')
EXIT 0
Processing a Result Set Returned from a Stored Procedure

The next example demonstrates a call to a stored procedure with the processing of a result set:

/*REXX*/

/* **************************************************************/
/* TRACE ?I */

/* CLEAN UP PREVIOUS VERSIONS OF OUTPUT                         */
/*                                                              */

/* CHECK TO SEE IF THE REXX/DB2 COMMAND ENVIRONMENT IS AVAILABLE*/
/* IF IT IS NOT, THEN ESTABLISH IT.                             */
/* THEN CONNECT TO THE APPROPRIATE DATABASE (SUBSYSTEM)         */
/*                                                              */
/* 'SUBCOM DSNREXX' */
/* IF RC THEN */
   S_RC = RXSUBCOM('ADD','DSNREXX','DSNREXX')
ADDRESS DSNREXX "CONNECT" "DSN1"
IF SQLCODE \= "0" THEN
   DO
    SAY "FAILURE TO CONNECT TO DATABASE"
    EXIT 8
   END

/*                                                              */
CREATOR="YLA"
ADDRESS DSNREXX
EXECSQL "CALL SPRSLT (:CREATOR)"
SAY "SQL CODE IS " SQLCODE
IF SQLCODE \= "466" THEN
   DO
    SAY "CALL FAILED WITH SQLCODE = " SQLCODE
    SAY "SQLERRM IS " SQLERRMC
    SAY "SQLSTATE IS" SQLSTATE
    SAY SQLWARN.0
    SAY "SQLERRD IS " SQLERRD.1 "," SQLERRD.2 "," SQLERRD.3,
        "," SQLERRD.4 "," SQLERRD.5 "," SQLERRD.6
    EXIT 8
   END
"EXECSQL ASSOCIATE LOCATOR (:LOC1) WITH PROCEDURE CDBSP004"
IF SQLCODE \= "0" THEN
   DO
    SAY "ASSOC FAILED WITH SQLCODE = " SQLCODE
    SAY "SQLERRM IS " SQLERRMC
    SAY "SQLSTATE IS" SQLSTATE
    SAY SQLWARN.0
    SAY "SQLERRD IS " SQLERRD.1 "," SQLERRD.2 "," SQLERRD.3,
        "," SQLERRD.4 "," SQLERRD.5 "," SQLERRD.6
    EXIT 8
   END
"EXECSQL ALLOCATE C101 CURSOR FOR RESULT SET :LOC1"
IF SQLCODE \= "0" THEN
   DO
    SAY "ALLOC FAILED WITH SQLCODE = " SQLCODE
    SAY "SQLERRM IS " SQLERRMC
    SAY "SQLSTATE IS" SQLSTATE
    SAY SQLWARN.0
    SAY "SQLERRD IS " SQLERRD.1 "," SQLERRD.2 "," SQLERRD.3,
        "," SQLERRD.4 "," SQLERRD.5 "," SQLERRD.6
    EXIT 8
   END
"EXECSQL FETCH C101 INTO :ACTID, :CUSTID"
IF SQLCODE \= "0" THEN
   DO
    SAY "FETCH FAILED WITH SQLCODE = " SQLCODE
    SAY "SQLERRM IS " SQLERRMC
    SAY "SQLSTATE IS" SQLSTATE
    SAY SQLWARN.0
    SAY "SQLERRD IS " SQLERRD.1 "," SQLERRD.2 "," SQLERRD.3,
        "," SQLERRD.4 "," SQLERRD.5 "," SQLERRD.6
    EXIT 8
   END
SAY "CUSTOMER ID IS:" CUSTID ", AND ACCOUT ID IS:" ACTID
"EXECSQL CLOSE C101"
ADDRESS DSNREXX "DISCONNECT"
EXIT 0

Host Variables in an REXX Program

It is important to note that you do not need to declare host variables in an REXX program. When you need a new variable, you simply reference it in a REXX command. A colon always precedes host variable references in SQL statements. All REXX data is string data, and when REXX variables are referenced within an SQL statement, DB2 performs the appropriate data type conversion. You can also use the SQLDA to identify the appropriate data type conversion to DB2. For the most part, DB2 does a good job of converting the strings into the appropriate data types. However, if you need a string of numbers, you should use quotes to force the appropriate data type conversion. This variable will be converted into an integer:

VAR1 = "1234"

This variable will be converted into a character string (either CHAR or VARCHAR):

VAR2 = "'"1234" '"

When executing your REXX program, you have a choice of isolation levels by using one of four REXX packages, listed in Table 12-5.

Table 12-5. Isolation Levels in REXX Packages

Package Name

Isolation Level

DSNREXRR

Repeatable read (RR)

DSNREXRS

Read stability (RS)

DSNREXCS

Cursor stability (CS)

DSNREXUR

Uncommitted read (UR)

You can utilize the SET CURRENT PACKAGESET command to change the package that the REXX DB2 interface uses and subsequently change the isolation level.


109 - Summary

Chapter 12. DB2 Traditional Programming

Summary

In this chapter we have looked at some traditional programming languages used to write programs to access DB2 data. Every organization has its preferences on which language to use. Each system should be developed in a language that will not inhibit the flexibility and performance of the application programs. In the Chapter 13, "Java Programming," we take a look at a relatively new language that supports DB2: Java.


110 - Additional Resources

Chapter 12. DB2 Traditional Programming

Additional Resources

IBM DB2 Application Programming and SQL Guide C26-9933


111 - Chapter 13. Java Programming

Part 4. Programming and Language Environments

Chapter 13. Java Programming

  • DB2 and Java

  • JDBC Programming

  • SQLJ Programming

  • Guidelines for Java Applications

  • Java Stored Procedures and UDFs


112 - DB2 and Java

Chapter 13. Java Programming

DB2 and Java

DB2 for OS/390 and z/OS provides Java applications two options for accessing relational databases: SQLJ and JDBC. In general, Java applications use SQLJ for static SQL and JDBC for dynamic SQL. However, there are features of JDBC that cannot be used yet in SQLJ, as the standard for SQLJ is still maturing.


113 - JDBC

Chapter 13. Java Programming

JDBC

JDBC is an API that provides a uniform SQL interface to a large selection of relational databases and a common base on which higher level interfaces and tools can be developed. DB2 for OS/390's support for JDBC enables you to write Java applications that access local DB2 data or remote relational data on a server that supports Distributed Relational Database Architecture (DRDA).

To understand JDBC, knowing about its purpose and background is helpful. Sun Microsystems developed the specifications for a set of APIs that allow Java applications to access relational data. The purpose of the APIs is to provide a generic interface for writing platform-independent applications that can access any SQL database. The APIs are defined within several classes and interfaces that support basic SQL functionality for connecting to a database, executing SQL statements, and processing results. On the server side, JDBC supports both fenced and unfenced UDFs and stored procedures in Java. Of course, on OS/390, all stored procedures are fenced to protect the environment.

On the client side, JDBC is very similar to DB2 ODBC and has the same features as DB2 ODBC, with a few more advantages. First, by using JDBC you can code Java applets to be executed by a Java-enabled browser, allowing your data to be accessed from the Web without additional client software. Second, you can access relational databases by using an object-oriented interface, because JDBC is integrated into the Java language.

A JDBC applet is a program written in Java that can be invoked by any Java-enabled Web browser when a page is displayed. By using the facilities of JDBC, the applet can connect to the database and retrieve and display data. Use of JDBC applets allows computers that can access the Internet to access your data on DB2.

Advantages of DB2 JDBC

DB2 JDBC offers a number of advantages for accessing DB2 data:

  • JDBC combines the benefit of running your applications in an OS/390 environment with the portability and ease of writing Java applications. Using the Java language, you can write an application on any platform and execute it on any platform to which the Java Development Kit (JDK) is ported.

  • The ability to develop an application once and execute it anywhere offers the potential benefits of reduced development, maintenance, and systems management costs, and flexibility in supporting diverse hardware and software configurations.

  • The JDBC interface offers the ability to change between drivers and access a variety of databases without recoding your Java program.

  • JDBC applications do not require precompiles.

DB2 for OS/390 SQLJ/JDBC Driver

The Sun JDBC specification provides for 4 types of drivers, two of which are used by application writers, and two that are used by driver writers.

Type 1: ODBC drivers. ODBC binary codeand in many cases, database client codemust be loaded on each client machine that uses a JDBC-ODBC Bridge. Sun provides a JDBC-ODBC Bridge driver, which is appropriate for experimental use and for situations in which no other driver is available.

Type 2: A native-API partly Java technology-enabled driver: This type of driver converts JDBC calls into calls on the client API for Oracle, Sybase, Informix, DB2, or other DBMS. Note that, like the bridge driver, this style of driver requires that some binary code be loaded on each client machine.

Type 3: Pure Java Driver for Database Middleware: This style of driver translates JDBC calls into the middleware vendor's protocol, which is then translated to a DBMS protocol by a middleware server. The middleware provides connectivity to many different databases.

Type 4: Direct-to-Database Pure Java Driver: This style of driver converts JDBC calls into the network protocol used directly by DBMSs, allowing a direct call from the client machine to the DBMS server and providing a practical solution for intranet access.

The DB2 for OS/390 SQLJ/JDBC driver is implemented as a type 2 driver. The type 2 driver translates JDBC calls into calls to a DB2 language interface module. The driver complies with the JDBC 1.2 specification and some of the JDBC 2.0 specification.

Several packages are included with the DB2 for OS/390 SQLJ/JDBC driver. These packages represent the DB2 for OS/390 implementation of the java.sql JDBC API. The driver packages include all of the JDBC classes, interfaces, and exceptions that comply with the JDBC specification.

The DB2 for OS/390 SQLJ/JDBC driver is available under two different Java class names. The preferred driver name is COM.ibm.db2os390.sqlj.jdbc.DB2SQLJDriver class. However, to maintain compatibility with existing DB2 for OS/390 JDBC applications, the following driver name is also supported: ibm.sql.DB2Driver. The ibm.sql.DB2Driver class will automatically forward all driver API calls to the COM.ibm.db2os390.sqlj.jdbc.DB2SQLJDriver.

DB2's JDBC Implementation

DB2 for OS/390 provides two implementations of JDBC.

  1. The first is an SQLJ/JDBC driver, which is fully compliant with SUN's JDBC 1.2 and SQLJ Part 0 specifications. To use this driver, DB2 for OS/390 requires an OS/390 Java Runtime Environment (JRE) version 1.1.6 or higher.

  2. The second is an SQLJ/JDBC driver, which is fully compliant SUN's JDBC 1.2 and SQLJ Part 0 specification and includes most of the functions of the JDBC 2.0 specification. To use this driver DB2 for OS/390 requires an OS/390 Java Runtime Environment (JRE) Version 1.3 or higher. You will need to use this JDBC driver if you use any of the following functions:

    - The JDBC 2.0 DataSource function

    - Global transactions that run under WebSphere Application Server Version 4.0 and above

You select a version of the JDBC driver by specifying the associated file name in your CLASSPATH environment variable.

NOTE

You can download the specification for the JDBC drivers from the JDBC Web site: http://java.sun.com/products/jdbc.

NOTE

The JDK includes a Java compiler, Java Virtual Machine (JVM), and Java Debugger. You can learn more about the JDK from the Java for OS/390 Web site: http://www.ibm.com/s390/java.

A Java application executes under the JVM. The Java application first loads the JDBC driver (by invoking the Class.forName()method), in this case the DB2 for OS/390 SQLJ/JDBC driver, and subsequently connects to the local DB2 subsystem or a remote DRDA application server (by invoking the DriverManager.getConnection method.

Target Data Source Identification

The Java application identifies the target data source it wants to connect to by passing a database Uniform Resource Locator (URL) to the DriverManager. The basic structure for the URL is

jdbc:<subprotocol>:<subname>

Specify either of the following URL values for a DB2 for OS/390 data source:

jdbc:db2os390:<location-name>
jdbc:db2os390sqlj:<location-name>

Each format results in the same behavior. Both subprotocols are provided for compatibility with existing DB2 for OS/390 JDBC applications. If location-name is not the local site, location-name must be defined in the SYSIBM.LOCATIONS catalog table. If location-name is the local site, location-name must have been specified in field DB2 LOCATION NAME of the Distributed Data Facility panel during DB2 installation.

In addition to the URL values shown above for a DB2 for OS/390 data source, there are two URL values that have special meaning for the DB2 for OS/390 SQLJ/JDBC driver.

  • If a URL value does not specify a location name, for example, jdbc:db2os390:, you will be connected to the local DB2 site. This format of the URL value is a DB2 for OS/390 defined extension. By using this URL value, a DB2 for OS/390 JDBC application does not need to know the location name of the local DB2 subsystem that the driver is using.

  • The SQLJ specification defines the following URL: jdbc:default:connection. When you use this URL value, your application is connected to the local DB2 site.

Connecting to a Data Source

There are two ways to connect to a data source. One method is available when you use the JDBC 1.2 driver or later. The other method is available only when you use the JDBC 2.0 driver or later.

When using the JDBC 1.2 driver the application attempts a connection to a data source, by requesting a java.sql.Connection implementation from the DriverManager (part of the java.sql package). The DriverManager searches all of the registered java.sql.Driver implementations for a driver that is capable of accepting the database URL. It then invokes the first JDBC driver that supports the subprotocol that is specified in the URL (and is registered with the DriverManager).

In this case, the DB2 for OS/390 SQLJ/JDBC driver (which is registered with the DriverManager) accepts the URL and returns a java.sql.Connection implementation that represents the database connection.

When using the JDBC 2.0 driver to connect to a data source, your application can reference a data source using a logical name, rather than an explicit driver class name and URL. In addition, you can define or modify the data source attributes without changing the JDBC application program.

JDBC 2.0 data source support is a complete replacement for the previous JDBC driver manager support. You can use both types of support in the same application, but it is recommended that you use data source support to obtain connections, regardless of whether you use connection pooling or distributed transactions.

The application uses JNDI to associate a logical name with a specific data source implementation. This data source object contains all of the information that is necessary to determine the correct JDBC driver and return a java.sql.Connection object to the specified data source.

Creating a DB2DataSource Instance

A DataSource object is the Java representation of a data source. The DataSource interface provides methods for connecting to the data source.

A DataSource object works with a JNDI naming service. A JNDI naming service provides a way for an application to access remote services over a network. Before you can use a DataSource object, the object needs to be created and registered with JNDI. In general, creating and managing DataSource objects is not done by the applications that use those objects.

If you use an application server, such as WebSphere, to write your JDBC applications, the application server creates and registers DataSource objects for you. This section contains information that you need if you create the DataSource objects yourself.

Two DB2 for OS/390 JDBC classes implement the javax.sql.DataSource interface:

  1. com.ibm.db2.jcc.DB2DataSource includes the methods that are necessary for a JDBC application to establish a connection to a data source using JDBC 2.0 support. This class also contains support for connection pooling.

  2. com.ibm.db2.jcc.DB2SimpleDataSource includes the same methods and properties as com.ibm.db2.jcc.DB2DataSource, but this class does not contain support for connection pooling. Because CICS does not support connection pooling, you need to use this class for CICS applications.

A DB2DataSource or DB2SimpleDataSource class provides a set of properties that define how the connection to a particular data source should be made. Those properties are usually set when a DataSource object is created and deployed. Those properties are:

databaseName

Specifies the location name to be used when establishing connections using the data source object. If the location name is not the local site the location name must be defined in SYSIBM.LOCATIONS. If the location name is the local site, the location name must have been specified in field DB2 LOCATION NAME of the DISTRIBUTED DATA FACILITY panel during the DB2 installation. If you do not set the database property, connections that are established using this data source object are to the local site. This property has data type String. The default value is null. The methods to get and set the value of this property are:

getDatabaseName

Returns the location name of the data source.

java.lang.String getDatabaseName()
setDatabaseName

Sets the location name of the data source.

voidsetDatabaseName(java.lang.String dbname)
description

Describes the data source object. This property has data type String. The default value is null. The methods to get and set the value of this property are:

getDescription

Returns a description of the data source.

java.lang.String getDescription()
setDescription

Sets the description of the data source.

voidsetDescription(java.lang.String description)
user

Specifies the OS/390 user ID to be used when using the DataSource object to establish a connection to the data source. DB2 validates the user ID and password. You can override this property by calling the DataSource.getConnection method with the user parameter. If you set the user property, or specify user parameter in the DataSource.getConnection method call, you must also set the password property, or specify the password parameter in the DataSource.getConnection method call. This property has data type String. The default value is null. The methods to get and set the value of this property are:

getUser

Returns the user ID to be used when connecting to the data source.

java.lang.String getUser()
setUser

Sets the user ID that is to be used for connecting to the data source.

voidsetUser(java.lang.String user)
password

Specifies a corresponding password for the user property. You can override this property by calling the DataSource.getConnection method with the password parameter. This property has data type String. The default value is null. The method to set the value of this property is:

setPassword

Sets the password that is to be used for connecting to the data source.

void setPassword(java.lang.String password)
planName

Specifies the name of the plan that DB2 allocates for connections that are established using the data source object. This property has data type String. The default value is DSNJDBC. The methods to get and set the value of this property are:

getPlanName

Gets the name of the plan that DB2 allocates for connections that are established using the data source object.

java.lang.String getPlanName()
setPlanName

Sets the name of the plan that DB2 allocates for connections that are established using the data source object.

voidsetPlanName(java.lang.String planName)
loginTimeout

Specifies the maximum time in seconds to wait for the DataSource object to connect to a data source. A value of 0 means that the timeout value is the default system timeout value, which is specified by the db2.connpool.connect.create.timeout property in the db2sqljjdbc.properties file. This property has a data type of int. The default value is 0. The methods to get and set the value of this property are:

getLoginTimeout

Gets the maximum time in seconds to wait for a connection.

int getLoginTimeout()
setLoginTimeout

Sets the maximum time in seconds to wait for a connection.

voidsetLoginTimeout(int seconds)

JDBC API

The JDBC API consists of the abstract Java interfaces that an application program uses to access databases, execute SQL statements, and process the results. Like ODBC, JDBC is a dynamic SQL interface. Writing a JDBC application is similar to writing a C application using ODBC to access a database. Four main interfaces perform these functions:

  • The DriverManager and DB2DataSource classes create database connections. DB2DataSource is available in JDCB 2.0 and above. DriverManager is available in JDBC 1.2 and above.

  • The Connection interface supports the connection to a specific database.

  • The Statement interface supports all SQL statement execution. This interface has two underlying interfaces:

    - The PreparedStatement interface supports any SQL statement containing input parameter markers.

    - The CallableStatement interface supports the invocation of a stored procedure and allows the application to retrieve output parameters.

  • The ResultSet interface provides access to the results that a query generates. The ResultSet interface is similar to the cursor that is used in SQL applications in other languages.

Running a JDBC Application

When you create a Java application that uses the JDBC interfaces, you import the java.sql package and invoke methods according to the JDBC specification. After coding your program, compile it as you would any other Java program. No precompile or bind steps are required to run a Java program.


114 - SQLJ

Chapter 13. Java Programming

SQLJ

SQLJ is an implementation of static SQL to be used with the Java programming language. It was designed by IBM, Oracle, and Sun to eliminate the weaknesses of JDBC. It allows most of the normal SQL language in a Java module, as shown below.

#sql iterator Honors ( String, float);
Honors honor;
#sql (recs) honor =
    { SELECT STUDENT, SCORE FROM GRADE_REPORTS
    WHERE SCORE >= :limit
    AND ATTENDED >= :days
    AND DEMERITS <= :offences
    ORDER BY SCORE DESCENDING };
while (true) {
    #sql {FETCH :honor INTO :name, :grade };
    if (honor.endFetch()) break;
    System.out.println( name + " has grade " + grade );
    }

The static SQL syntax for Java is easier than JDBC, and the performance is much better than JDBC. It provides popular language support for binary portability of static SQL across DBMS vendors. With SQLJ, Java stored procedures can be developed that can be ported across platforms.

SQLJ supports

  • INSERT

  • UPDATE

  • DELETE

  • Singleton SELECT

  • Cursor SELECT

  • Calling stored procedures, including result sets

  • COMMIT and ROLLBACK

  • Methods for CONNECT and DISCONNECT

Dynamic SQL is supported only through JDBC. When using both SQLJ and JDBC in a single process, you must share the connection handles and connect state.

With SQLJ you have Java applications with SQLJ clauses that are translated by a Java precompiler and produce modified Java code and a profile. This code and profile are platform-independent descriptions of the SQLJ clauses. The profile is then customized and produces a DB2 for OS/390-dependent DBRM that is bound into a package or plan. The application is executed via OS/390 JVM. The profiles are portable across platforms. See Figure 13-1.

Figure 13-1. Compiling Java

A profile generated on Oracle, compiled on Windows NT against Oracle8, can be moved to DB2 on the OS/390 and can be customized and bound into a DB2 package or plan without modification of any source code. SQLJ applications have all the benefits of JDBC as well as the advantages of the static model SQLJ compilation.

Writing SQLJ Programs

In general, Java applications use JDBC for dynamic SQL and SQLJ for static SQL. However, because SQLJ includes JDBC 1.2 or JDBC 2.0, an application program can create a JDBC connection and then use that connection to execute dynamic SQL statements through JDBC and embedded static SQL statements through SQLJ.

The SQLJ specification consists of three parts:

  • Database Languages, SQL, Part 10: Object Language Bindings (SQL/OLB) is also known as SQLJ Part 0. It was approved by ANSI in 1998, and it specifies the SQLJ language syntax and semantics for embedded SQL statements in a Java application.

  • Database Languages, SQLJ, Part 1: SQL Routines Using the Java Programming Language was approved by ANSI in 1999, and it specifies extensions that define

    - installation of Java classes in an SQL database.

    - invocation of static methods as stored procedures.

  • Database Languages, SQLJ, Part 2: SQL Types Using the Java Programming Language specifies extensions for accessing Java classes as SQL user-defined types.

The DB2 for OS/390 implementation of SQLJ includes support for the following portions of the specification:

  • Part 0

  • The ability to invoke a Java static method as a stored procedure, which is in Part 1

SQL and JDBC Differences

Some of the major differences between SQLJ and JDBC include the following:

  • SQLJ follows the static SQL model, and JDBC follows the dynamic SQL model.

  • SQLJ source programs are smaller than equivalent JDBC programs, because certain code that the programmer must include in JDBC programs is generated automatically by SQLJ.

  • SQLJ can do data type checking during the program preparation process to determine whether table columns are compatible with Java host expressions. JDBC passes values to and from SQL tables without compile-time data type checking.

  • In SQLJ programs, you can embed Java host expressions in SQL statements. JDBC requires a separate call statement for each bind variable and specifies the binding by position number.

  • SQLJ provides the advantages of static SQL authorization checking. With SQLJ, the authorization ID under which SQL statements execute is the plan or package owner. DB2 checks table privileges at bind time. Because JDBC uses dynamic SQL, the authorization ID under which SQL statements execute is not known until runtime, so no authorization checking of table privileges can occur until runtime.

Including SQL Statements

In an SQLJ program, all statements that are used for database access are in SQLJ clauses. SQLJ clauses that contain SQL statements are called executable clauses. An executable clause begins with the characters #sql and contains an SQL statement that is enclosed in curly brackets. The SQL statement itself has no terminating character. Following is an example of an executable clause:

#sql {DELETE FROM EMP};

An executable clause can appear anywhere in a program that a Java statement can appear.

Host Expressions

To pass data between a Java application program and DB2, use host expressions. A Java host expression is a Java simple identifier or complex expression, preceded by a colon. The result of a complex expression must be a single value. An array element is considered to be a complex expression. A complex expression must be surrounded by parentheses. When you use a host expression as a parameter in a stored procedure call, you can follow the colon with the IN, OUT, or INOUT parameter, which indicates whether the host expression is intended for input, output, or both. The IN, OUT, or INOUT value must agree with the value you specify in the stored procedure definition in catalog table SYSIBM.SYSPROCEDURES.

The following SQLJ clause uses a host expression that is a simple Java variable named empname:

#sql {SELECT LASTNAME INTO :empname FROM EMP WHERE EMPNO='000010'};

The following SQLJ clause calls stored procedure A and uses a simple Java variable named EMPNO as an input or output parameter:

#sql {CALL A (:INOUT EMPNO)};

SQLJ evaluates host expressions from left to right before DB2 processes the SQL statements that contain them. For example, suppose that the value of i is 1 before the following SQL clause is executed:

#sql {SET :(z[i++]) = :(x[i++]) + :(y[i++])};

The array index that determines the location in array z is 1. The array index that determines the location in array x is 2. The array index that determines the location in array y is 3. The value of i in the Java space is now 4. The statement is then executed. After statement execution, the output value is assigned to z[1]. In an executable clause, host expressions, which are Java tokens, are case-sensitive.

Including Comments

To include comments in an SQLJ program, use either Java comments or SQL comments.

  • Java comments are denoted by /* */ (block) or // (line). You can include Java comments outside SQLJ clauses, wherever the Java language permits them. Within an SQLJ clause, use Java comments in host expressions.

  • SQL comments are denoted by * at the beginning of a line oranywhere on a line in an SQL statement. You can use SQL comments in executable clauses, anywhere except in host expressions.

Handling SQL Errors and Warnings

SQLJ clauses use the JDBC class java.sql.SQLException for error handling. SQLJ generates an SQLException when either an SQL statement returns a negative SQLCODE or when a SELECT INTO SQL statement returns a +100 SQLCODE. You can use the getErrorCode method to retrieve SQLCODEs and the getSQLState method to retrieve SQLSTATEs. To handle SQL errors in your SQLJ application, import the java.sql.SQLException class, and use the Java error handling try/catch blocks to modify program flow when an SQL error occurs. For example,

import java.sql.SQLException
.
.
.
try {
#sql {SELECT LASTNAME INTO :empname
   FROM EMP WHERE EMPNO='000010'};
}
catch(SQLException e) {
System.out.println("SQLCODE returned: " + e.getErrorCode());
}

DB2 warnings do not throw SQLExceptions. To handle DB2 warnings, you need to import the java.sql.SQLWarning class. To check for a DB2 warning, invoke the getWarnings method after you execute an SQL clause. getWarnings returns the first warning code that an SQL statement generates. Subsequent SQL warning codes are chained to the first SQL warning code.

Before you can execute getWarnings for an SQL clause, you need to set up an execution context for that SQL clause. The following example demonstrates how to retrieve a SQL warning code for an SQL clause with execution context ExecCtx:

SQLWarning SQLWarn;
#sql [ExecCtx] {SELECT LASTNAME INTO :empname
FROM EMP WHERE EMPNO='000010'};
if (SQLWarn = ExecCtx.getWarnings() != null) then
System.out.println("SQLWarning " + SQLWarn);

If your SQLJ or JDBC application runs only on DB2 for OS/390 and z/OS, you can retrieve the contents of the SQLCA when an SQL statement generates an SQLWarning or SQLException. To retrieve the SQLCA, import the com.ibm.db2.jcc.DB2Diagnosable and db2.jcc.DB2Sqlca classes. Then, in the catch block for an SQLException or after the getWarnings call for an SQLWarning, call the DB2Diagnosable.getSQLCA method to retrieve the SQLCA and the DB2Sqlca methods to retrieve the fields in the SQLCA. For example:

import com.ibm.db2.jcc.DB2Diagnosable;
import com.ibm.db2.jcc.DB2Sqlca;
.
.
.
try {
#sql {SELECT LASTNAME INTO :empname
   FROM EMP WHERE EMPNO='000010'};
}
catch(SQLException e){
System.out.println("SQLCODE returned:"+e.getErrorCode());
if (e instanceof DB2Diagnosable){ //If SQLException object has
//DB2-only diagnostics
  DB2Sqlca sqlca =((DB2Diagnosable)e).getSqlca();  //Get the SQLCA
if (sqlca !=null){
     int sqlCode =sqlca.getSqlCode();//Get the SQLCA fields .
.
.
    }
  }
}

Code for SQLJ Support

Before you can execute any SQLJ clauses in your application program, you must include code to accomplish these tasks:

  • Import the Java packages for SQLJ runtime support and the JDBC interfaces that are used by SQLJ.

  • Load the DB2 for OS/390 SQLJ/JDBC driver, which is the SQLJ implementation of JDBC 1.2 function.

To import the Java packages for SQLJ and JDBC, include these lines in your application program:

import sqlj.runtime.*;   // SQLJ runtime support
import java.sql.*;       // JDBC interfaces

/* To load the DB2 for OS/390 SQLJ/JDBC driver and register it with the DriverManager,
invoke method Class.forName with an argument of
COM.ibm.db2os390.sqlj.jdbc.DB2SQLJDriver. For example: */

try {
Class.forName("COM.ibm.db2os390.sqlj.jdbc.DB2SQLJDriver");
}
catch (ClassNotFoundException e) {
e.printStackTrace();
}

Connecting to a Data Source

In an SQLJ application, as in any other DB2 application, you must be connected to a data source before you can execute SQL statements. A data source in DB2 for OS/390 is a DB2 location name. To execute an SQL statement at a data source, use one of the following methods:

  • Use an explicit connection. Specify a connection context, enclosed in square brackets, at the beginning of the execution clause that contains the SQL statement. For example, the following SQL clause executes an UPDATE statement at the data source that is associated with connection context myconn:

    #sql [myconn] {UPDATE DEPT SET MGRNO=:hvmgr WHERE DEPTNO=:hvdeptno};

  • Use a default connection. When you specify an execution clause without a connection context, SQLJ uses the default context to access a data source. If you create a connection context object for accessing a remote data source, you can use the setDefaultContext method to install that connection context object as the default connection. If you do not use setDefaultContext to override, the default connection is to the local DB2 subsystem. A connection context is an instance of a connection context class. To define the connection context class and set up the connection context, use one of the following methods before you specify the connection context in any SQL statements:

Connection Method 1

  1. Execute a type of SQLJ clause called a connection declaration clause to generate a connection context class.

  2. Invoke the constructor for the connection context class with the following arguments:

    - A string that specifies the location name that is associated with the data source. That argument has the form jdbc:db2os390sqlj:location-name. If the location name is not the local site, location-name must be defined in the SYSIBM.LOCATIONS DB2 catalog table. If the location name is the local site, location-name must have been specified in field DB2 LOCATION NAME of the Distributed Data Facility panel during DB2 installation.

    - A boolean that specifies whether autoCommit is on or off for the connection. For example, suppose that you want to use the first method to set up connection context myconn to access data at a data source that is associated with location NEWYORK. For this connection, you want autoCommit to be off. First, execute a connection declaration clause to generate a connection context class:

    #sql context Ctx;

    Then invoke the constructor for generated class Ctx with arguments jdbc:db2os390sqlj:NEWYORK and false:

    Ctx myconn=new Ctx("jdbc:db2os390sqlj:NEWYORK",false);
Connection Method 2

  1. Execute a connection declaration clause to generate a connection context class.

  2. Invoke the JDBC java.sql.DriverManager.getConnection method. The argument for java.sql.DriverManager.getConnection is a string that specifies the location name that is associated with the data source. That argument has the form jdbc:db2os390sqlj:location-name. If the location name is not the local site, location-name must be defined in SYSIBM.LOCATIONS. If the location name is the local site, location-name must have been specified in field DB2 LOCATION NAME of the Distributed Data Facility panel during DB2 installation. The invocation returns an instance of class Connection, which represents a JDBC connection to the data source.

  3. For environments other than the CICS environment, the default state of autoCommit for a JDBC connection is on. To disable autoCommit, invoke the setAutoCommit method with an argument of false.

  4. Invoke the constructor for the connection context class. For the argument of the constructor, use the JDBC connection that results from invoking java.sql.DriverManager.getConnection.

To use the second method to set up connection context myconn to access data at the data source associated with location NEWYORK with autoCommit off, first execute a connection declaration clause to generate a connection context class:

#sql context Ctx;

Then invoke java.sql.Driver.getConnection with the argument jdbc:db2os390sqlj:NEWYORK:

Connection
jdbccon=DriverManager.getConnection("jdbc:db2os390sqlj:NEWYORK");

Next, to set autoCommit off for the connection, invoke setAutoCommit with an argument false:

jdbccon.setAutoCommit(false);

Finally, invoke the constructor for class Ctx using the JDBC connection as the argument:

Ctx myconn=new Ctx(jdbccon);

SQLJ uses the JDBC java.sql.Connection class to connect to data sources. Your application can invoke any method in the java.sql.Connection class.

Connection Method 3

  1. Execute a connection declaration clause to generate a connection context class.

  2. Invoke the JNDI javax.naming.InitialContext method to create a context for use by JNDI.

  3. Invoke the JNDI javax.naming.lookup method to get the DataSource object that is associated with a logical name. The DataSource object is created separately by an application server such as WebSphere.

  4. Invoke the JDBC java.sql.DataSource.getConnection method to connect the DataSource object to the data source.

  5. If necessary, invoke the setAutoCommit method to enable or disable AutoCommit. For environments other than the CICS environment, the default state of autoCommit for a JDBC connection is on. To disable autoCommit, invoke the setAutoCommit method with an argument of false.

  6. Invoke the constructor for the connection context class. For the argument of the constructor, use the JDBC connection that results from invoking java.sql.DataSource.getConnection.

For example, suppose you want to use the second method to set up connection context myconn to access data at the data source with logical name dbc/sampledb. First, execute a connection declaration clause to generate a connection context class:

#sql context Ctx;

Next, establish a JNDI context and find the DataSource object that is associated with the logical data source name:

Context ctx=new InitialContext();
DataSource ds=(DataSource)ctx.lookup("jdbc/sampledb");

Then establish a connection for the DataSource object:

Connection jdbccon=ds.getConnection();

Next, set autoCommit off for the connection:

jdbccon.setAutoCommit(false);

Finally, invoke the constructor for class Ctx using the JDBC connection as the argument:

Ctx myconn=new Ctx(jdbccon);

Result Set Iterators

In DB2 application programs that are written in traditional host languages, you use a cursor to retrieve individual rows from the result table that is generated by a SELECT statement. The SQLJ equivalent of a cursor is a result set iterator. A result set iterator is a Java object that you use to retrieve rows from a result table. Unlike a cursor, a result set iterator can be passed as a parameter to a method.

You define a result set iterator using an iterator declaration clause. The iterator declaration clause specifies the following information:

  • A list of Java data types.

  • Information for a Java class declaration, such as whether the iterator is public or static.

  • A set of attributes, such as whether the iterator is holdable or whether its columns can be updated.

The data type declarations represent columns in the result table and are referred to as columns of the result set iterator. The code example later in this chapter under "Design Guidelines for Applications" shows each Java data type that you can specify in a result set iterator declaration and the equivalent SQL data type.

If you declare an iterator without the public modifier, you can declare and use the iterator in the same file. If you declare the iterator as public, you can declare and use the iterator in one of the following ways:

  • Declare the iterator in one file and use it in a different file. The name of the file in which you declare the iterator must match the iterator name.

  • Declare and use the iterator in the same file. If you do this, you need to declare the iterator with the public and static modifiers and declare the iterator in the class that uses it.

Examples in this section that use a public iterator declare the iterator in a different file from the file in which it is used. An iterator must have a public modifier when the iterator has a with clause, such as with UpdateColumns.

The two types of results set iterators are positioned iterators and named iterators. The type of result set iterator that you choose depends on the way that you plan to use that result set iterator. The following sections explain how to use each type of iterator.

Positioned Iterators

For a positioned iterator, the columns of the result set iterator correspond to the columns of the result table in left-to-right order. For example, if an iterator declaration clause has two data type declarations, the first data type declaration corresponds to the first column in the result table, and the second data type declaration corresponds to the second column in the result table. You declare positioned iterators to execute FETCH statements. For example, the following iterator declaration clause defines a positioned iterator named ByPos with two columns. The first column is of type String, and the second column is of type Date.

#sql iterator ByPos(String,Date);

When SQLJ encounters an iterator declaration clause for a positioned iterator, it generates a positioned iterator class with the name that you specify in the iterator declaration clause. You can then declare an object of the positioned iterator class to retrieve rows from a result table.

For example, suppose that you want to retrieve rows from a result table that contains the values of the LASTNAME and HIREDATE columns from the DB2 sample employee table. The example below shows how you can declare an iterator named ByPos and use an object of the generated class ByPos to retrieve those rows.

{
#sql iterator ByPos(String,Date);
// Declare positioned iterator class ByPos
ByPos positer; // Declare object of ByPos class
String name = null;
Date hrdate;
#sql positer = { SELECT LASTNAME, HIREDATE FROM EMP };
#sql { FETCH :positer INTO :name, :hrdate };
// Retrieve the first row
while ( !positer.endFetch() )
{ System.out.println(name + " was hired in " +
hrdate);
#sql { FETCH :positer INTO :name, :hrdate };
// Retrieve the rest of the rows
}
}
Named Iterators

Using named iterators is an alternative way to select rows from a result table. When you declare a named iterator for a query, you specify names for each of the iterator columns. Those names must match the names of columns in the result table for the query. An iterator column name and a result table column name that differ only in case are considered to be matching names.

When SQLJ encounters a named iterator declaration, it generates a named iterator class with the same name that you use in the iterator declaration clause. In the named iterator class, SQLJ generates an access or method for each column name in the iterator declaration clause. The accessor method name is the same name as the column name in the iterator declaration clause. The data type that is returned by the accessor method is the same as the data type of the corresponding column in the iterator declaration clause.

When you execute an SQL clause that has a named iterator, SQLJ matches the name of each iterator column to the name of a column in the result table.

The following iterator declaration clause defines the named iterator ByName, which has two columns. The first column of the iterator is named LastName and is of type String. The second column is named HireDate and is of type Date.

#sql iterator ByName(String LastName, Date HireDate);

To use a named iterator, you use an SQLJ assignment clause to assign the result table from a SELECT statement to an instance of a named iterator class. Then you use the accessor methods to retrieve the data from the iterator.

The below code shows how you can use a named iterator to retrieve rows from a result table that contains the values of the LASTNAME and HIREDATE columns of the employee table.

{
#sql iterator ByName(String LastName, Date HireDate);
ByName nameiter; // Declare object of ByName class
#sql nameiter={SELECT LASTNAME, HIREDATE FROM EMP};
while (nameiter.next())
{
System.out.println( nameiter.LastName() + " was hired on "
+ nameiter.HireDate());
}
}

The column names for named iterators must be valid Java identifiers. The column names must also match the column names in the result table from which the iterator retrieves rows. If a SELECT statement that uses a named iterator selects data from columns with names that are not valid Java identifiers, you need to use SQL AS clauses in the SELECT statement to give the columns of the result table acceptable names. For example, suppose you want to use a named iterator to retrieve the rows that are specified by this SELECT statement:

SELECT PUBLIC FROM GOODTABLE

The iterator column name must match the column name of the result table, but you cannot specify an iterator column name of PUBLIC because PUBLIC is a reserved Java keyword. You must therefore use an AS clause to rename PUBLIC to a valid Java identifier in the result table. For example,

SELECT PUBLIC AS IS_PUBLIC FROM GOODTABLE

You can then declare a named iterator with a column name that is a valid Java identifier and matches the column name of the result table:

#sql iterator ByName(String IS_PUBLIC);
ByName nameiter;
#sql nameiter={SELECT PUBLIC AS IS_PUBLIC FROM GOODTABLE};
Using Iterators for Positioned UPDATE and DELETE Operations

When you declare an iterator for a positioned UPDATE or DELETE statement, you must use an SQLJ implements clause to implement the sqlj.runtime.ForUpdate interface.

You must also declare the iterator as public. For example, suppose that you declare the iterator ByPos for use in a positioned DELETE statement. The declaration looks like this:

#sql public iterator ByPos(String) implements sqlj.runtime.ForUpdate
with(UpdateColumns="EmpNo");

Because you declare the iterator as public but not static, you need to use the iterator in a different source file. To use the iterator,

  1. Import the generated iterator class.

  2. Declare an instance of the generated iterator class.

  3. Assign the SELECT statement for the positioned UPDATE or DELETE to the iterator instance.

  4. Execute positioned UPDATE or DELETE statements using the iterator.

After the iterator is created, any SQLJ source file that has addressibility to the iterator and imports the generated class can retrieve data and execute positioned UPDATE or DELETE statements using the iterator. The authorization ID under which a positioned UPDATE or DELETE statement executes is the authorization ID under which the DB2 package that contains the UPDATE or DELETE executes. For example, suppose that you declare iterator UpdByName like this in UpdByName.sqlj:

#sql public iterator UpdByName(String EMPNO, BigDecimal SALARY)
implements sqlj.runtime.ForUpdate
with(updateColumns="SALARY");

To use UpdByName for a positioned UPDATE in another file, execute statements like the following:

import UpdByName;
{
UpdByName upditer;//Declare object of UpdByName class
String enum;
2 #sql upditer ={SELECT EMPNO,SALARY FROM EMP
WHERE WORKDEPT='D11'};
3 while (upditer.next())
{
enum =upditer.EmpNo();//Get value from result table
4 #sql {UPDATE EMP SET SALARY=SALARY*1.05 WHERE CURRENT OF :upditer };
//Update row where cursor is positioned
System.out.println("Updating row for "+enum);
}
#sql {COMMIT};//Commit the changes
}

Controlling the Execution of SQL Statements

You can use selected methods of the SQLJ ExecutionContext class to query and modify the characteristics of SQL statements during execution. To execute ExecutionContext methods for an SQL statement, you must create an execution context and associate that execution context with the SQL statement. To create an execution context, invoke the constructor for ExecutionContext and assign the result to a variable of type ExecutionContext. For example,

ExecutionContext ExecCtx=new ExecutionContext();

To associate an execution context with an SQL statement, specify the name of the execution context, enclosed in square brackets, at the beginning of the execution clause that contains the SQL statement. For example,

#sql [ExecCtx] {DELETE FROM EMP WHERE SALARY > 10000};

You can associate a different execution context with each SQL statement. If you also use an explicit connection context for an SQL statement, specify the connection context followed by the execution context in the execution clause for the SQL statement. For example,

#sql [ConnCtx, ExecCtx] {DELETE FROM EMP WHERE SALARY > 10000};

If you do not specify an execution context for an execution clause, SQLJ uses the execution context that is associated with the connection context for the execution clause. After you associate an execution context with an SQL statement, you can execute ExecutionContext methods for that SQL statement. For example, you can use method getUpdateCount to count the number of rows that are deleted by a DELETE statement:

#sql [ConnCtx, ExecCtx] {DELETE FROM EMP WHERE SALARY > 10000};
System.out.println("Deleted " + ExecCtx.getUpdateCount() + " rows");
Isolation Levels

To set the isolation level for a unit of work within a SQLJ program, use the SET TRANSACTION ISOLATION LEVEL clause. You can set the isolation level only at the beginning of a transaction. Table 13-1 shows the values that you can specify in the SET TRANSACTION ISOLATION LEVEL clause and their DB2 for OS/390 equivalents.

Table 13-1. Isolation Levels

SET TRANSACTION ISOLATION LEVEL Values

DB2 for OS/390 Equivalent

READ COMMITTED

Cursor stability

READ UNCOMMITTED

Uncommitted read

REPEATABLE READ

Read stability

SERIALIZABLE

Repeatable read

Read-Only Mode

To set the read-only mode for a unit of work within an SQLJ program, use the SET TRANSACTION READ ONLY or SET TRANSACTION READ WRITE clause. SET TRANSACTION READ ONLY puts a connection into read-only mode so that DB2 can optimize execution of SQL statements for read-only access. If you execute SET TRANSACTION READ WRITE, DB2 does not optimize for read-only access. You can set the read-only mode only at the beginning of a transaction.

JDBC and SQLJ Authorization Establishment

The method that DB2 uses to establish an authorization ID for a process depends on the level of the JDBC driver.

Determining an Authorization ID with the JDBC 1.2 Driver

With the JDBC 1.2 driver, the security environment created by an external security product, such as OS/390 Security Server (RACF ACEE), determines the DB2 authorization ID that is used for a thread. A user ID and password is not specified for an SQLJ connection context or a JDBC connection. DB2 does not create the security environment. The application or server that provides the point of entry into the OS/390 system, such as a TSO logon, Telnet logon, or WebServer, typically creates the security environment.

Determining an Authorization ID with the JDBC 2.0 Driver

With the JDBC 2.0 driver, the method that DB2 uses to determine the SQL Authorization ID to use for a connection depends on whether you provide user ID and password values for the connection. If you provide a user ID and password, the JDBC driver passes these values to DB2 for validation and uses these values for the connection. If you do not provide a user ID and password, the JDBC driver uses the external security environment that is associated with the thread to establish the DB authorization ID.

Running SQLJ Programs

After you have set the environmental variables and prepared your program for execution, your program is ready to run. To ensure that the program can find all the files that it needs,

  • Put the serialized profiles for the program in the same directory as the class files for the program.

  • Include class files that are used by the program in the CLASSPATH. To run your SQLJ program, execute the java command from the OS/390 UNIX System Services command line java program-name.

Diagnosing SQLJ Problems

SQLJ programs can generate two types of errors:

  • Recoverable errors: SQLJ reports recoverable SQL errors through the JDBC java.sql.SQLException class. You can use methods getErrorCode and getSQLState to retrieve SQLCODEs and SQLSTATEs.

  • Nonrecoverable errors: These errors do not throw an SQLException, or the application cannot catch the exception. To diagnose recoverable errors that generate SQLSTATE FFFFF or repeatable, nonrecoverable errors, you can collect trace data and run three utilities that generate additional diagnostic information.

Formatting Trace Data

Before you can format SQLJ trace data, you must set several environmental variables. You must also set several parameters in the runtime properties file that you name in environmental variable DB2SQLJPROPERTIES. When you set the parameter DB2SQLJ_TRACE_FILENAME in the runtime properties file, you enable SQLJ/JDBC tracing. The SQLJ/JDBC driver generates two trace files:

  • One trace file has a proprietary, binary format and must be formatted using the db2sqljtrace command. The name of that trace file is trace-file, where trace-file is the value to which you set DB2SQLJ_TRACE_FILENAME.

  • The other trace file contains readable text, which requires no additional formatting. The name of that trace file is trace-file.JTRACE.

The db2sqljtrace command writes the formatted trace data to stdout. The format of db2sqljtrace is

db2sqljtrace fmt/flw input-file-name
fmt

Specifies that the output trace file is to contain a record of each time a function is entered or exited before the failure occurs.

flw

Specifies that the output trace file is to contain the function flow before the failure occurs.

input-file-name

Specifies the name of the file from which db2sqljtrace is to read the unformatted trace data. This name is the name you specified for environmental variable DB2SQLJ_TRACE_FILENAME.

Diagnostic Utilities

If an SQLJ application program receives a recoverable, internal error (SQLSTATE FFFFF) or a repeatable, nonrecoverable error, run diagnosis utilities profp, profdb, and db2profp, which are provided with SQLJ, to obtain additional information about the error.

The profp utility captures information about each SQLJ clause in a serialized profile. The format of the profdb utility is:

profp serialized-profile-name

Run the profp utility on the serialized profile for the connection in which the error occurs. If an exception is thrown, a Java stack trace is generated. You can determine which serialized profile was in use when the exception was thrown from the stack trace.

The db2profp utility captures information about each SQLJ clause in a customized serialized profile. A customized serialized profile is a serialized profile on which the DB2 for OS/390 SQLJ customizer has been run. The format of the db2profp utility is:

db2profp customized-serialized-profile-name

Run the db2profp utility on the customized serialized profile for the connection in which the error occurs.

The profdb utility customizes serialized profiles so that SQLJ captures extra information about runtime calls. The syntax of the profdb utility is:

profdb _ serialized-profile-name

Run the profdb utility on every serialized profile that is associated with the SQLJ application program that received the internal error. After you run profdb, rerun the application program to gather the diagnostic information.


115 - Design Guidelines for Applications

Chapter 13. Java Programming

Design Guidelines for Applications

There are recommendations for designing applications for best performance when using JDBC/SQLJ. Some of them have been described in the IBM Redpaper "DB2 for z/OS and OS/390 V7 Selected Performance Topics"REDP0162 and are summarized below.

Data Types

There are a few performance gains that can be realized when developing Java applications in regards to data types. While this is also a database design issue, it is important to recognize these options.

Mapping

Java data types need to be mapped to the SQL column data types to achieve best performance. This can help with ensuring the predicates are Stage 1 and indexable and so that the cost of conversion can be minimized. See Table13-2.

Table 13-2. DB2 and Java Data Type Comparision

DB2 Data Type

Java Data Type

SMALLINT

short, Boolean

INTEGER

int

REAL

float

DOUBLE, FLOAT

double

DECIMAL (p,s) or NUMERIC (p,s)

java.math.BigDecimal

CHAR, VARCHAR, GRAPHIC, VARGRAPHIC

String

CHAR, VARCHAR, FOR BIT DATA

Byte[ ]

DATE

java.sql.Date

TIME

java.sql.Time

TIMESTAMP

java.sql.Timestamp

Use of INTEGER and SMALLINT

Storing numbers as INT or SMALLINT when applicable will save on conversion overhead between EBCDIC/ASCII and Unicode. Java runs Unicode and requires that character(CHAR, VARCHAR) data be converted. Numbers do not have to be converted, as they are not dependent on an encoding scheme.

Use of CHAR and VARCHAR

Java does not pad, and this means that trailing blanks are considered as characters. This can be a problem with string columns in DB2 because they are padded with blanks and therefore may not match the Java at predicate evaluation time.

This possibility of a mismatch forces the programmer to address it. There are three options available to address this issue:

  • Use a Java trim() method to get rid of the trailing blanks so the columns will match. This can make for complex programming and can increase the Java CPU costs. Define the columns as VARCHARs. This will of course incur the DB2 overhead associated with using them, but does eliminate the complex Java code.

  • Use the RTRIM option on SQL when retrieving the columns. This options reduces the complex Java code without incurring the DB2 overhead associated with VARCHARs.

Programming Guidelines

There are some general guidelines for best practices for developing Java programs. Most of these guidelines center around the performance aspects of using Java.

Autocommit

Autocommit is the default, but it is recommended to execute commits as necessary and turn autocommit off. With autocommit on, a lot of cost is added to the program execution because a commit is taken after each SQL statement. This will occur even in a read-only environment due to the releasing of locks and registrations. Autocommit can be turned off by calling the setAutoCommit method of the Connection object.

Connection connection = dataSource.getConnection("", "");
connection.setAutoCommit(false);

NOTE

Autocommit can also be turned off when the connection is established; refer to the previous section, "Connecting to a Data Source."

Conservative Selection

The recommendation for selection of DB2 data has always been to only select what data is actually required by the application. Java programming is no exception and actually has a more critical performance impact. Every column retrieved is returned as a Java object.

Explicit Connection Context Objects

A default connection context object is used when the connection context object is not specified. The use of a default connection context is not thread-safe and cannot be used in a multicontext environment such as WebSphere Application Server. The use of the default connect context can also cause application execution bottlenecks. You can also specify the constant KEEP_CONNECTION to indicate that the underlying database connection should be retained when the context is closed.

JDBC and SQLJ Connection Pooling

Connection pooling is part of JDBC 2.0 data source support. Connection pooling is a framework for caching physical data source connections, which are equivalent to DB2 threads. When JDBC reuses physical data source connections, the expensive operations that are required for the creation and subsequent closing of java.sql.Connection objects are minimized. Connection pooling is a built-in part of JDBC 2.0 data source support. Connection pooling support is completely transparent to the JDBC application.

Without connection pooling, each java.sql.Connection object represents a physical connection to the database. When the application establishes a connection to a data source, DB2 creates a new physical connection to the data source. When the application calls the java.sql.Connection.close method, DB2 terminates the physical connection to the data source. In contrast, with connection pooling, a java.sql.Connection object is a temporary, logical representation of the physical data source connection.

The JDBC 2.0 connection pooling framework lets a single physical data source connection be serially reused by logical java.sql.Connection instances. The application can use the logical java.sql.Connection object in exactly the same manner as it uses a java.sql.Connection object when there is no connection pooling support.

With connection pooling, when a JDBC application invokes the DataSource.getConnection method, the data source determines whether an appropriate physical connection exists. If an appropriate physical connection exists, the data source returns a java.sql.Connection instance to the application. When the JDBC application invokes the java.sql.Connection.close method, JDBC does not close the physical data source connection. Instead, JDBC closes only JDBC resources, such as Statement or ResultSet objects. The data source returns the physical connection to the connection pool for reuse.

Connection Pooling within CICS and WebSphere

Currently CICS does not support connection pooling. It is highly recommended when programming for WebSphere that DataSource connection pooling be used. When a user makes a request to the application server that requires interaction with the database, a connection to the database must be made. Connection pooling can reduce the overhead of creating a new connection to the database, because the DataSource might determine it has a free connection in its pool that it can give to the request. When the connection is no longer needed for the request, the database connection will be closed. This signals to the datasource that it can return the connection to its pool for reuse. This also has the benefit of reducing the cost of releasing the connection.

WebSphere connection pooling also has the advantage of caching prepared statements. The application server maintains a cache of previously prepared statements that it makes available to a connection. When a prepared statement is requested, the cached prepared statement is returned. If the statement is not already in the cache, it will be added. The number of statements to cache is a configurable setting. This type of caching reduces the cost of creating prepared statements, which in turn improves response times. Below is an example of using connection pooling with a prepared statement. Note that the context factory for WebSphere 3.5 is com.ibm.ejs.ns.jndi.CNInitialContextFactory and for 4.0 is com.ibm.websphere.naming.WsnInitialContextFactory. Also, the JNDI lookup string is "jdbc/MyDB" for 3.5 and "java:comp/env/jdbc/MyDB" for 4.0. Both lookups will work under version 4.0, but the 4.0 syntax is J2EE 1.2-compliant.

// Lookup the DataSource
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,
        "com.ibm.ejs.ns.jndi.CNInitialContextFactory");

// Create the Initial Naming Context.
Context ctx = new InitialContext(env);

// Use the naming service to retrieve the DataSource
DataSource ds = (DataSource) ctx.lookup("jdbc/MyDB");

// Obtain a connection from the DataSource
Connection conn = ds.getConnection("", "");

// Prepare a callable statement
CallableStatement cState =
            conn.prepareCall("{call myStoredProcedure(?)}");
cState.registerOutParameter(1, java.sql.Types.INTEGER);

// Execute the callable statement
cState.execute();

// Retrieve the results
int newId = cState.getInt(1);

// Close the callable statement
cState.close();
cState = null;

// Close the database connection
conn.close();
conn = null;
ds = null;

Sometimes the connections in the pool can become stale and need to be refreshed. Connections can become stale for the following reasons:

  • The application server starts before the database.

  • The database goes down while the application server is running.

  • The application closes the connection and then tries to perform a task on the closed connection.

  • The connection has been orphaned because it was not used by the application within the orphan timeout period.

WebSphere provides an application with the ability to recover from a stale connection with the StaleConnectionException class. Version 3.5 of WebSphere uses the class com.ibm.ejs.cm.portability.StaleConnectionException and Version 4.0 uses com.ibm.websphere.ce.cm.StaleConnectionException.

It is not required of an application to catch the StaleConnectionException, because this class extends SQLException, which is required to be caught or thrown by applications. Catching this exception allows an application to recover from a stale connection by retrying to retrieve enough connections to refresh the pool. There should be a limit set on how many times an application tries to retrieve a connection, because there is CPU cost involved with this type of approach.

Resource Release

Resource links are maintained by the JDBC driver and released only when the connection is lost or the resource is closed. Table 13-3 lists objects that should be explicitly released by an application rather than waiting for the Java garbage collector to release them.

Table 13-3. Objects to be Released by an Application

Object

Description

Connection

A database connection object.

CallableStatement

Object used to execute stored procedures.

PreparedStatement

Object used to execute precompiled SQL.

ResultSet

Object used to represent a database result set.

Statement

Object used for executing static SQL.

To reduce resource costs, the following guidelines should be followed:

  • Never close connection in a finalize() method. A connection closed in the finalize() method will not be released until the object is garbage collected. This can result in the application running out of database connections.

  • Do not declare Connection objects as servlet instance variables, because all instances of the servlet will use the same Connection object. This is an issue, since a servlet is multithreaded and can be used to handle multiple client requests.

  • The data source should be obtained in the init() method of a servlet, because JNDI context lookups are expensive and the data source is nothing more than a factory of connections that does not change.

Db2profc

Java has no concept of length for string data types such as CHAR and VARCHAR. In order to use index matching for the SQL predicates, the definition in the DBRM for SQLJ must match the definition (length and data type) in the DB2 catalog. To do this, the SQLJ serialized profile must be customized using db2proc with the online checker option. It needs to be run on the same platform where the code will be executed.

Db2proc ... -online=<db2_location_name ...


116 - Java Stored Procedures and UDFs

Chapter 13. Java Programming

Java Stored Procedures and UDFs

Stored procedures and user-defined functions (UDFs) are programs that can contain SQL statements. You invoke a stored procedure from a client program by executing the SQL CALL statement. You invoke a UDF by specifying the UDF name, followed by its arguments, in an SQL statement. For more information on stored procedures, refer to Chapter 8, "Stored Procedures," and for more information on UDFs, refer to Chapter 15, "Object Relational Programming."

The word routine refers to either a stored procedure or a UDF. The term compiled Java stored procedure refers to a stored procedure that runs under VisualAge for Java. The term interpreted Java stored routine refers to a stored procedure or a user-defined function that runs in a JVM.

Defining a Java Routine to DB2

Defining a Java routine to DB2 involves one or two steps, depending on how you prepare the routine for execution:

  • First, for interpreted Java routines that you store in JAR files, you need to define the JAR files to DB2. Refer to the section "Defining a JAR File for a Java Routine to DB2" later in this chapter.

  • Second, for all types of Java routines, you need to define the routine to DB2. If you prepare the Java routine for execution without IBM DB2 Stored Procedure Builder, execute the CREATE PROCEDURE or CREATE FUNCTION statement to define the routine to DB2. To alter the routine definition, use the ALTER PROCEDURE or ALTER FUNCTION statement.

NOTE

If you use the IBM DB2 Stored Procedure Builder to prepare your Java routine for execution, the IBM DB2 Stored Procedure Builder defines the Java routine and the JAR file to DB2 for you.

The definition for a Java routine is much like the definition for a routine in any other language. However, the following parameters have different meanings for Java routines.

  • LANGUAGE: Specifies the application programming language in which the routine is written. There are two possible values for a Java stored procedure. If the stored procedure runs in a JVM, specify LANGUAGE JAVA. If the stored procedure runs under VisualAge for Java, specify LANGUAGE COMPJAVA. For a Java UDF, which must run in a JVM, specify LANGUAGE JAVA.

  • EXTERNAL NAME: Specifies the program that runs when the procedure name is specified in a CALL statement or the UDF name is specified in an SQL statement. For Java routines, the argument of EXTERNAL NAME is a string that is enclosed in single quotation marks. The value in that string depends on the value of LANGUAGE.

Whether you include JAR-name depends on the way that you prepare your stored procedure for execution. If you create a JAR file from the routine class, you need to include JAR-name. You must create the JAR file, define the JAR file to DB2, and grant the USAGE privilege on the JAR before you execute the CREATE PROCEDURE or CREATE FUNCTION statement.

If you use a JAR file, that JAR file must be self-contained. That is, if a class within the JAR file references another class, the referenced class must also be in the JAR file. The exception to this rule is that classes that are part of the Java environment, such as java.lang package or the SQLJ/JDBC driver classes do not need to be in the JAR file.

Whether you include a method signature depends on the following factors:

  • The way that you define the parameters in your routine method. Each SQL data type has a corresponding default Java data type. If your routine method uses data types other than the default types, you need to include a method signature in the EXTERNAL NAME clause. A method signature is a comma-separated list of data types.

  • Whether you overload a Java routine. If you have several Java programs with the same name and different parameter types, you need to specify the method signature to indicate which version of the program is associated with the Java routine.

If your stored procedure returns result sets, you also need to include a parameter in the method signature for each result set. The parameter can be in one of the following forms:

  • java.sql.ResultSet[]

  • An array of a class that is declared as an SQLJ iterator

Example: EXTERNAL NAME clause for a Java user-defined function. Suppose that you write a Java UDF as method getSals in class S1Sal and package s1. You put S1Sal in a JAR file named sal_JAR and install that JAR in DB2. The EXTERNAL NAME parameter is

EXTERNAL NAME 'sal_JAR:s1.S1Sal.getSals'

Example: EXTERNAL NAME clause for a Java stored procedure. Suppose that you write a Java stored procedure as method getSals in class S1Sal. You put S1Sal in a JAR file named sal_JAR and install that JAR in DB2. The stored procedure has one input parameter of type INTEGER and returns one result set.

The Java method for the stored procedure receives one parameter of type java.lang.Integer, but the default Java data type for an SQL type of INTEGER is int, so the EXTERNAL NAME clause requires a signature clause. The EXTERNAL NAME parameter is

EXTERNAL NAME
'sal_JAR:S1Sal.getSals(java.lang.Integer,java.sql.ResultSet [])'

  • PARAMETER STYLE: Identifies the linkage convention that is used to pass parameters to the routine. For a Java routine, the only value that is valid is PARAMETER STYLE JAVA. You cannot specify PARAMETER STYLE JAVA for a user-defined table function.

  • WLM ENVIRONMENT: Identifies the MVS workload manager (WLM) environment in which the routine is to run when the DB2 stored procedure address space is WLM-established.

    - A Java routine must run in a WLM-established address space, so this parameter must be specified.

  • PROGRAM TYPE: Specifies whether Language Environment runs the routine as a main routine or a subroutine. This parameter value must be PROGRAM TYPE SUB. However, you can write a Java routine as a Java main method.

  • RUN OPTIONS: Specifies the Language Environment runtime options to be used for the routine. This parameter has no meaning for a Java routine. If you specify this parameter with LANGUAGE JAVA or LANGUAGE COMPJAVA, DB2 issues an error.

  • SCRATCHPAD: Specifies that when the user-defined function is invoked for the first time, DB2 allocates memory for a scratchpad. You cannot use a scratchpad in a Java user-defined function. Do not specify SCRATCHPAD when you call a Java user-defined function.

  • FINAL CALL: Specifies that a final call is made to the user-defined function, which the function can use to free any system resources that it has acquired. You cannot perform a final call when you call a Java user-defined function. Do not specify FINAL CALL when you call a Java user-defined function.

  • DBINFO: Specifies that when the routine is invoked, an additional argument is passed that contains environmental information. You cannot pass the additional argument when you call a Java routine. Do not specify DBINFO when you call a Java routine.

  • SECURITY: Specifies how the routine interacts with an external security product, such as RACF, to control access to non-SQL resources. The values of the SECURITY parameter are the same for a Java routine as for any other routine. However, the value of the SECURITY parameter determines the authorization ID that must have authority to access OS/390 UNIX System Services. The values of SECURITY and the IDs that must have access to OS/390 UNIX System Services are:

    - DB2: The user ID that is defined for the stored procedure address space in the RACF started-procedure table.

    - EXTERNAL: The invoker of the routine.

    - DEFINER: The definer of the routine.

Defining a Java Stored Procedure

Suppose that you have written and prepared a stored procedure that runs under VisualAge for Java and has these characteristics:

  • Fully-qualified procedure name: SYSPROC.S1SAL

  • Parameters: DECIMAL(10,2) INOUT

  • Language: Java

  • Runtime environment: VisualAge for Java

  • Collection ID for the stored procedure package: DSNJDBC

  • Java executable name: s1.S1Sal.getSals

  • Type of SQL statements in the program: Statements that modify DB2 tables

  • WLM environment name: WLMENV1

  • Maximum number of result sets returned: 1

This CREATE PROCEDURE statement defines the stored procedure to DB2:

CREATE PROCEDURE SYSPROC.S1SAL
(DECIMAL(10,2)INOUT)
FENCED
MODIFIES SQL DATA
COLLID DSNJDBC
LANGUAGE COMPJAVA
EXTERNAL NAME 's1.S1Sal.getSals'
WLM ENVIRONMENT WLMENV1
DYNAMIC RESULT SETS 1
PROGRAM TYPE SUB
PARAMETER STYLE JAVA;

Defining a Java UDF

Suppose that you have written and prepared a user-defined function that has these characteristics:

  • Fully-qualified function name: MYSCHEMA.S2SAL

  • Input parameter: INTEGER

  • Output parameter: VARCHAR(20)

  • Language: Java

  • Runtime environment: JVM

  • Collection ID for the function package: DSNJDBC

  • Package, class, and method name: s2.S2Sal.getSals

  • Java data type of the method input parameter: java.lang.Integer

  • JAR file that contains the function class: sal_JAR

  • Type of SQL statements in the program: Statements that modify DB2 tables

  • Function is called when input parameter is null? Yes

  • WLM environment name: WLMENV1

This CREATE FUNCTION statement defines the UDF to DB2:

CREATE FUNCTION MYSCHEMA.S2SAL(INTEGER)
RETURNS VARCHAR(20)
FENCED
MODIFIES SQL DATA
COLLID DSNJDBC
LANGUAGE JAVA
EXTERNAL NAME 'sal_JAR:s2.S2Sal.getSals(java.lang.Integer)'
WLM ENVIRONMENT WLMENV1
CALLED ON NULL INPUT
PROGRAM TYPE SUB
PARAMETER STYLE JAVA;

In this function definition, you need to specify a method signature in the EXTERNAL NAME clause because the data type of the method input parameter is different from the default Java data type for a SQL type of INTEGER.

Defining a JAR File for a Java Routine to DB2

One way to organize the classes for a Java routine is to collect those classes into a JAR file. If you do this, you need to install the JAR file into the DB2 catalog. DB2 provides three built-in stored procedures that perform the following functions for the JAR file:

  • SQLJ.INSTALL_JAR installs a JAR file into the DB2 catalog.

  • SQLJ.REPLACE_JAR replaces an existing JAR file in the DB2 catalog.

  • SQLJ.REMOVE_JAR deletes a JAR file from the DB2 catalog.

You can use the IBM DB2 Stored Procedure Builder to install JAR files into the DB2 catalog, or you can write a client program that executes SQL CALL statements to invoke the SQLJ.INSTALL_JAR, SQLJ.REPLACE_JAR, and SQLJ.REMOVE_JAR stored procedures. The following sections explain how to call the stored procedures.

Calling SQLJ.INSTALL_JAR

Use SQLJ.INSTALL_JAR to create a new definition of a JAR file in the DB2 catalog. The syntax for the statement is

CALL SQLJ.INSTALL_JAR (url ,jar-name ,deploy )

The meanings of the parameters are

  • url: a VARCHAR(128) input parameter that identifies the hierarchical file system (HFS) full path name for the JAR file that is to be installed in the DB2 catalog. The format is file://path-name.

  • jar-name: a VARCHAR(27) input parameter that contains the DB2 name of the JAR, in the form schema.jar-id or jar-id. This is the name that you use when you refer to the JAR in SQL statements. If you omit schema, DB2 uses the default schema name

  • deploy: an INTEGER input parameter that indicates whether additional actions should be performed after the JAR file is installed. Additional actions are not supported, so this value should always be 0.

Calling SQLJ.REPLACE_JAR

Use SQLJ.REPLACE_JAR to replace an existing JAR file in the DB2 catalog. The syntax for the statement is

CALL SQLJ.REPLACE_JAR (url ,jar-name )

The meanings of the parameters are

  • url: a VARCHAR(128) input parameter that identifies the HFS full path name for the JAR file that replaces the existing JAR file in the DB2 catalog. The format is file://path-name.

  • jar-name: a VARCHAR(27) input parameter that contains the DB2 name of the JAR, in the form schema.jar-id or jar-id. This is the name that you use when you refer to the JAR in SQL statements. If you omit schema, DB2 uses the default schema name.

Calling SQLJ.REMOVE_JAR

Use SQLJ.REMOVE_JAR to delete a JAR file from the DB2 catalog. The syntax for the statement is

CALL SQLJ.REMOVE_JAR (jar-name ,undeploy )

The meanings of the parameters are

  • jar-name: a VARCHAR(27) input parameter that contains the DB2 name of the JAR that is to be removed from the catalog in the form.

  • schema.jar-id or jar-id: This is the name that you use when you refer to the JAR in SQL statements. If you omit schema, DB2 uses the default schema name.

  • undeploy: an INTEGER input parameter that indicates whether additional actions should be performed after the JAR file is removed. Additional actions are not supported, so this value should always be 0.

Writing a Java Routine

A Java routine is a JDBC or SQLJ application program that runs in a stored procedure address space. A Java routine is much like any other Java program and follows the same rules as routines in other languages. It receives input parameters, executes Java statements, optionally executes SQLJ clauses, JDBC methods, or a combination of both, and returns output parameters.

Differences Between Java Routines and Standalone Java Programs

A Java routine differs from a standalone Java program in the following ways:

  • A Java routine does not establish its own connection to the local data source. Instead, the routine uses the default recoverable resource management services (RRS) connection to the data source that processes the CALL statement or the statement that contains the UDF invocation. If you want to execute SQLJ clauses or JDBC methods at another location, use the same methods to connect to those locations as you do in SQLJ or JDBC application programs.

  • A Java routine must be declared as static and public.

  • As in routines in other languages, the SQL statements that you can execute in the routine depend on whether you specify a SQL access level of NO SQL, CONTAINS SQL, READS SQL DATA, or MODIFIES SQL DATA.

Differences Between Java Routines and Other Routines

A Java routine differs from stored procedures that are written in other languages in the following ways:

  • A Java routine must be defined with PARAMETER STYLE JAVA. PARAMETER STYLE JAVA specifies that the routine uses a parameter-passing convention that conforms to the Java language and SQLJ specifications. DB2 passes INOUT and OUT parameters as single-entry arrays.

  • Java main programs must have a signature of String[]. If your Java routine is a main method, it must be possible to map all the parameters to Java variables of type java.lang.String.

  • You cannot make instrumentation facility interface (IFI) calls in Java routines.

  • As in other Java programs, you cannot include the following statements in a Java routine:

    - CONNECT

    - RELEASE

    - SET CONNECTION

  • The mappings between data types for routine parameters and host data types follow the rules for mappings between SQL and SQLJ data types.

  • The technique for returning result sets from Java stored procedures is different from the technique for returning result sets in other stored procedures.

Writing a Java Stored Procedure to Return Result Sets

Your stored procedure can return multiple query result sets to a DRDA client if the following conditions are satisfied:

  • The client supports the DRDA code points that are used to return query result sets.

  • The value of RESULT_SETS in the stored procedure definition is greater than 0.

For each result set you want to be returned, your Java stored procedure must perform the following actions

  • For each result set, include an object of type java.sql.ResultSet[] or an array of a class that is declared as a SQLJ iterator in the parameter list for the stored procedure method. If the stored procedure definition includes a method signature, then for each result set, include java.sql.ResultSet[] or the fully qualified name of an array of a class that is declared as a SQLJ iterator in the method signature. Do not include a java.sql.ResultSet array or an iterator array in the SQL parameter list of the stored procedure definition.

  • Execute a SELECT statement to obtain the contents of the result set.

  • Retrieve any rows that you do not want to return to the client.

  • Assign the contents of the result set to the java.sql.ResultSet[] object that is in the parameter list.

  • Do not close the ResultSet, the statement that generated the ResultSet, or the connection that is associated with the statement that generated the ResultSet. DB2 does not return result sets for ResultSets that are closed before the stored procedure terminates.

The code below shows an example of a Java stored procedure that uses an SQLJ iterator to retrieve a result set.

package s1;
import sqlj.runtime.*;
import java.sql.*;
import java.math.*;
1 #sql iterator NameSal(String LastName,BigDecimal Salary);
public class S1Sal
{
2 public static void getSals(BigDecimal []AvgSalParm,java.sql.ResultSet []rs)
throws SQLException
{
NameSal iter1;
try
{
3 #sql iter1 ={SELECT LASTNAME,SALARY FROM EMP
WHERE SALARY>0 ORDER BY SALARY DESC};
4 #sql {SELECT AVG(SALARY)INTO :(AvgSalParm [0 ])FROM EMP};
}
catch (SQLException e)
{
System.out.println("SQLCODE returned:"+e.getErrorCode());
throw(e);
}
5rs [0 ]=iter1.getResultSet();
}
}
Code Notes

  1. This SQLJ clause declares the iterator named NameSal, which is used to retrieve the rows that will be returned to the stored procedure caller in a result set.

  2. The declaration for the stored procedure method contains declarations for a single passed parameter, followed by the declaration for the result set object.

  3. This SQLJ clause executes the SELECT to obtain the rows for the result set, constructs an iterator object that contains those rows, and assigns the iterator object to variable iter1.

  4. This SQLJ clause retrieves a value into the parameter that is returned to the stored procedure caller.

  5. This statement uses the GetResultSet method to assign the contents of the iterator to the result set that is returned to the caller.
Running a Java Routine

Like other routines, Java routines run under Language Environment and in a stored procedure address space. A Java routine always runs as a subprogram.

The Stored Procedure Address Space for Java Routines

A Java routine must run in a WLM-established stored procedure address space. The startup procedure for Java routines requires extra DD statements that other routines do not need. The code below shows an example of a startup procedure for an address space in which Java routines can run.

//DSNWLM PROC RGN=0K,APPLENV=WLMCJAV,DB2SSN=DSN,NUMTCB=1
//IEFPROC EXEC PGM=DSNX9WLM,REGION=&RGN,TIME=NOLIMIT,
//PARM='&DB2SSN,&NUMTCB,&APPLENV'
//STEPLIB DD DISP=SHR,DSN=DSN710.RUNLIB.LOAD
1//DD DISP=SHR,DSN=HPJSP.PDSE1
 //DD DISP=SHR,DSN=CEE.SCEERUN
 //DD DISP=SHR,DSN=DSN710.SDSNEXIT
 //DD DISP=SHR,DSN=DSN710.SDSNLOAD
2 //DD DISP=SHR,DSN=HPJ.SQLJ,DISP=SHR
3 //DD DISP=SHR,DSN=HPJ.SHPJMOD
  //DD DISP=SHR,DSN=HPJ.SHPOMOD
  //DD DISP=SHR,DSN=VAJAVA.V2R0M0.SHPOMOD
4 //JAVAENV DD DISP=SHR,DSN=WLMCJAV.JSPENV
5 //JSPDEBUG DD SYSOUT=A
  //CEEDUMP DD SYSOUT=A
  //SYSPRINT DD SYSOUT=A
Code Notes

  1. This DD statement specifies the PDSE that contains the Java program objects for compiled Java stored procedures.

  2. This DD statement specifies the PDSE that contains Java program objects for Java classes that are referenced by the stored procedure.

  3. This DD statement and the following DD statement specify the PDSEs that contain the VisualAge for Java compiler and runtime library.

  4. JAVAENV specifies a dataset that contains environmental variables that specify system properties for the ET/390 Java execution environment.

  5. JSPDEBUG specifies a dataset into which DB2 puts information that you can use to debug your stored procedure.

If you specify SYSOUT=A in the JSPDEBUG DD statement, the debug information is written to your SYSOUT dataset. If you specify a dataset name, you also need to specify the MSGFILE(ddname) runtime option in your JAVAENV dataset. Specify JSPDEBUG for ddname to direct all diagnostic output to the JSPDEBUG dataset. If you do not redirect standard output, println statements in your stored procedure program write text to the JSPDEBUG dataset.

Setting Environmental Variables for Java Routines

For Java routines, the startup procedure for the stored procedure address space contains a JAVAENV DD statement. This statement specifies a dataset that contains environmental variables for the VisualAge for Java execution environment. You need to set the following environmental variables in the JAVAENV data set:

  • CLASSPATH: Modify CLASSPATH to include the following HFS directories: (1) the directories that contain the external links to the routines that run in the WLM-established stored procedure address space, and (2) the directory in which the VisualAge for Java links are defined ($IBMHPJ_HOME/lib). For example,

    CLASSPATH=.:/u/sysadm/links:/usr/lpp/hpj/lib

  • LIBPATH and LD_LIBRARY_PATH: Modify LIBPATH and LD_LIBRARY_PATH to include the following HFS directories: (1) the path for the ET/390 code ($IBMHPJ_HOME/lib), and (2) the path for the SQLJ/JDBC driver code, if the stored procedures contain SQL. For example,

    LIBPATH=/u/sysadm/links:/usr/lpp/hpj/lib:/u/hpjsp/lib
LD_LIBRARY_PATH=/u/sysadm/links:/usr/lpp/hpj/lib:/u/hpjsp/lib

  • JAVA_HOME: For an interpreted Java routine, used to determine Java.home. DB2 uses this environment variable to determine whether the WLM environment is for a compiled Java stored procedure or an interpreted Java routine. Therefore, if the startup procedure is for a WLM environment for interpreted Java routines, you need to include this environment variable. For example:

    JAVA_HOME=/usr/local/Java

  • LANG: Modify LANG to change the locale to use for the locale categories when neither the LC_ALL environment variable nor the individual locale environment variables specify locale information. For example:

    LANG="En_US.IBM-037"

  • LC_ALL: Modify LC_ALL to change the locale to be used to override any values for locale categories specified by the settings of the LANG environment variable or any individual locale environmental variables. For example,

    LC_ALL="S370"

  • LC_CTYPE: Modify LC_CTYPE to change the locale for character classification, case conversion, and other character attributes. This value should match the DB2 for OS/390 and z/OS installation default. For example,

    LC_CTYPE="En_US.IBM-037"

  • WORK_DIR: Specify WORK_DIR to direct diagnostic output to an HFS directory. When you specify the JSPDEBUG DD statement in your WLM address space startup procedure, DB2 creates three data sets in this directory for diagnostic information. Those data sets are server_stdin.txt, server_stdout.txt, and server_stderr.txt.

  • TZ: Modify TZ to change the local time zone. The default is GMT. For example,

    TZ="PST08"

The following example shows the contents of a JAVAENV dataset.

ENVAR("CLASSPATH=.:/u/sysadm/links:/usr/lpp/hpj/lib",
"TZ=PST08",
"LIBPATH=/u/sysadm/links:/usr/lpp/hpj/lib:/u/hpjsp/lib",
"LD_LIBRARY_PATH=/u/sysadm/links:/usr/lpp/hpj/lib:/u/hpjsp/lib"),
MSGFILE(JSPDEBUG)

Testing a Java Routine

Before you invoke your Java routines from SQL applications, it is a good idea to run the routines as standalone programs, which are easier to debug. When you are ready to invoke your programs as Java routines, include a JSPDEBUGDD statement in your startup procedure for the stored procedure address space. This DD statement specifies a dataset to which DB2 writes debug information as the Java routines execute.


117 - Summary

Chapter 13. Java Programming

Summary

Java is becoming widely accepted as the next universally used language, and to interact with DB2, there is both dynamic SQL via the JDBC API and static SQL using the SQLJ. SQLJ lets the application programming use normal SQL without having to learn the complexity of JDBC.

One of the most important features for rapid application development and control is the Stored Procedure Builder tool, which can easily create and maintain stored procedures written in either the SQL procedure language or Java.


118 - Additional Resources

Chapter 13. Java Programming

Additional Resources

IBM Java Programming Guide for OS390 SG2456-19-00

IBM Experiences Moving a Java Application to OS390 SG2456-20-00

IBM VisualAge Generator WebSphere SG245636

IBM VisualAge Java Persistence, SG245636

IBM Web Enabling S390 Apps using WS OS390 Java MQ REDP0027

IBM Enterprise Java Beans and CICS Trans Server v2-1 SG246284

IBM Application Programming Guide for Java SES1-2157

IBM DB2 Selected Performance Topics Version 7 REDP0162


119 - Chapter 14. Attachment Programming

Part 4. Programming and Language Environments

Chapter 14. Attachment Programming

  • Attachments

  • TSO

  • CICS

  • MS

  • CAF

  • RRSAF

The attachment facilities are the parts of DB2 that allow programs to connect to DB2, process SQL statements, and issue commands. Some of the attachment facilities allow programs to use the DB2 instrumentation facility interface (IFI) calls as well as SQL statements. All DB2 programs that run on z/OS and OS/390 systems use one of the attachment facilities.

The DB2 ODBC and CLI interfaces are not covered in this section because they don't have their own attachment. Instead, the DB2 ODBC driver modules use either Call Attach Facility (CAF) or Recoverable Resource Manager Services Attachment Facility (RRSAF) behind the scenes to communicate with the DB2 address spaces and process requests.


120 - Attachments

Chapter 14. Attachment Programming

Attachments

There are five different attachment facilities that can be used depending on the environment where the program will execute. Only one attachment can be active within a program at any given time. The attachments are

  • TSO

  • CICS

  • IMS

  • CAF

  • RRSAF

Each program runs in an address space called the allied address space. The DB2 attachment facility modules are called by the program, execute within the allied address space, and establish communication with the DB2 address spaces. When initialized the attachment modules make the link to DB2 and agent control blocks are created in the DSNMSTR address space to control the program's DB2 processing.

When a program issues a SQL statement, the attachment modules are given control. The attachment programs prepare the request for DB2 and pass it over to the DB2 address space. Results are passed back to the attachment programs and any results are copied into the application storage areas.

Execution Environments

There are several environments in which an application program can execute. The attachment that can be used by a particular program depends on the environment that the program runs in. Table 14-1 shows the attachment facilities that are available for each multiple virtual system (MVS) environment.

Table 14-1. Attachment Facilities for MVS Environments

Environment

TSO

CICS

IMS

CAF

RRSAF

TSO

Y

Y

Y

CICS

Y

IMS

Y

Y

DL/I Batch

Y

Y

UNIX System Services

Y

Batch

Y

Y

Started Task

Y

Y

Stored Procedure

Y

Y

As you can see, some environments, like TSO, allow for a variety of available attachments, where CICS supports only a single attachment. Knowing where your program will execute is important in organizing a project that consists of several modules, as only one type of attachment can be active at a time.

Program Preparation

Programs using embedded SQL must be precompiled to translate the EXEC SQL statements into code that the language compilers understand. When a program is processed, the precompiler replaces SQL statements with appropriate conditioning source code and a call to the DB2 high-level interface modules, usually DSNHLI or DSNHLI2. Each attachment has a load module that supplies these entry points. This load module must be linked into the application's load module or loaded dynamically at execution time by the application. The attachment interface load modules are listed in Table 14-2.

Table 14-2. Attachment Interface Load Modules

Attachment

Module

TSO

DSNELI

CICS

DSNCLI

IMS

DFSLI000

CAF

DSNALI

RRSAF

DSNRLI

Fortran uses module DSNHFT instead of DSNELI for the TSO attachment. The CICS interface module, DSNCLI, is supplied in the CICS product libraries.

Security

DB2 and RACF provide the capability to control which attachments are available to a given user. The RACF DSNR resource class protects the attachments. When a program attaches to DB2 and transfers control to the DB2 address space, DB2 checks with RACF to verify that the user executing the program is authorized to use the attachment type.

For some attachments, the programmer can control access to a program's package or plan by specifying the ENABLE or DISABLE options on the BIND command. With some of the ENABLE or DISABLE options, a specific connection name can also be listed.


121 - TSO

Chapter 14. Attachment Programming

TSO

The TSO attachment facility is the default and most frequently used interface. This interface is used in both foreground and background modes and all programs that use the TSO attachment must run under TSO. The reverse, however, is not true, as programs running under TSO may use the TSO attachment facility, CAF, or RRSAF.

Capabilities

The TSO attachment facility provides the main interface to DB2 for developers and administrators. Running in the TSO foreground environment, programs can be invoked by ISPF panels or use the Dialog Manager interfaces. Programs can be tested interactively using the TSO TEST command or the IBM Debug Tool.

Many of the DSN subcommands, like BIND, are necessary for implementation of application programs. The DB2I panels provided by IBM supply an administrative interface that uses the TSO attachment.

Restrictions

The TSO user or batch job must execute on the same MVS image as the DB2 subsystem.

Requirements

In order to use the TSO attachment, the DB2 load libraries must be in the link list or steplib concatenation of the TSO user or batch job.

Execution

The DSN command processor is used to execute programs that use the TSO attachment facility. The DSN command can be used in interactive mode or background mode. In either mode, the RUN subcommand is used to invoke the application program, as in the following example:

//MYJOB  JOB
//BKGRND EXEC PGM=IKJEFT01
//SYSPRINT DD  SYSOUT=*
//SYSOUT   DD  SYSOUT=*
//SYSTSPRT DD  SYSOUT=*
//SYSTSIN  DD  *
  DSN SYSTEM(DSN1)
      RUN PROGRAM(MYPGM) PLAN(MYPGM) -
          LIBRARY(MY.LOADLIB)
  END
/*
//

This differs from non-DB2 program execution where the application program name would normally be specified on the EXEC card in the Job Control Language (JCL). Instead, one of the TSO background programs is used. TSO background jobs read the SYSTSIN DD statement as if it were a terminal and send their output to the SYSTSPRT DD statement.

The DSN command processor establishes a connection to the specified (or default) DB2 subsystem. The TSO input stream is then read for subcommands, which are processed sequentially.

The RUN subcommand tells the DSN command processor to invoke a program specified by the PROGRAM parameter. The BIND parameter specifies the plan name that will be used for DB2 database access. The LIBRARY parameter specifies the load library where the program resides. If the LIBRARY parameter is omitted, the program will be loaded from the standard STEPLIB or link list libraries.

Units of Work

Because TSO is not a transaction manager, DB2 controls the logical unit of work (UOW) for programs using this attachment. There is no two-phase commit processing for programs running with the TSO interface. A UOW starts when the first DB2 object updates occur. It ends when one of the following conditions occur:

  • The program issues a COMMIT statement.

  • The program issues a ROLLBACK statement.

  • The program terminates and returns to the DSN command processor, which returns to the TSO Terminal Monitor Program (TMP).

A commit point occurs when you issue a COMMIT statement or your program terminates normally. Before you can connect to another DBMS, you must issue a COMMIT statement. If the system fails at this point, DB2 cannot know that your transaction is complete. In this case, as in the case of a failure during a one-phase commit operation for a single subsystem, you must make your own provision for maintaining data integrity. If your program abends or the system fails, DB2 backs out uncommitted data changes. Changed data returns to its original condition without interfering with other system activities.

Program Characteristics

There are some specific characteristics for coding programs to use the TSO attachment facility.

Initialization

Programs using the TSO attachment do not require any special code. The DB2 high-level interface module (DSNELI) takes care of the work. We're running under the DSN command processor, so the connection to DB2 has already been established.

Application programs running under the TSO attachment facility do not need to code CONNECT statements when using the local DB2 subsystem. They can issue CONNECT statements to connect to remote databases defined in the local communications database.

SQL Processing

Programs use embedded SQL statements. The DB2 precompiler translates the statements into the appropriate language calls to the high-level interface module.

Error Checking

Programs running under the TSO attachment should check the SQLCODE or SQLSTATE returned by DB2 to determine the status of each SQL statement. Programs may call the IBM-supplied routine DSNTIAR to generate error messages for most failure codes.

Termination

Normal termination is achieved by returning control to the caller, which in this case is the DSN command processor. DB2 will commit any work in progress, clean up, and finish the RUN subcommand. Abnormal program termination due to system abends or application-invoked abort processing will result in DB2 rolling back the UOW.

DB2 Abend

If DB2 abends while an application is running, the application is rolled back to the last commit point. If DB2 terminates while processing a commit request, DB2 either commits or rolls back any changes at the next restart. The action taken depends on the state of the commit request when DB2 terminates.


122 - CICS

Chapter 14. Attachment Programming

CICS

All CICS programs that access DB2 use the CICS attachment facility. CICS provides components that establish the connection to DB2. Many connections, called threads, can be established between a single CICS region and a DB2 subsystem. Each CICS region can attach to only one DB2 subsystem at a time. CICS/DB2 programs using embedded SQL can be written in COBOL, PL/I, C, C++, or Assembler.

CICS programs can also be written in Java using JDBC or SQLJ to access DB2. JDBC does not allow connections to be shared, so non-Java programs that call a Java program should commit or rollback their UOW prior to that call. Unlike SQLJ and JDBC applications that use other attachment facilities, SQLJ and JDBC applications that use the CICS attachment facility can create only one JDBC java.sql.Connection object within a UOW. Multithreading is supported, but Java child threads may not issue JDBC or SQLJ statements.

Capabilities

CICS regions provide a high-performance multithreaded execution environment for application programs. Programs running under CICS share resources like files and access these resources using the CICS command-level interface. CICS/DB2 programs also share database resources. When CICS is started, the CICS attachment facility modules allocate subtask task control blocks (TCBs) that are shared among the programs that execute SQL statements. These TCBs can be preconnected to DB2, and the CICS attachment facility includes a transaction (DSNC) that can be used to issue DB2 commands.

Restrictions

The CICS regions that connect to DB2 must run on the same MVS system as the DB2 subsystem. This restriction does not apply to other CICS regions, like terminal-owning regions that may execute on other MVS systems. Programs may use the IBM-supplied routine DSNTIAC instead of DSNTIAR to generate error messages under CICS.

Requirements

There are some requirements unique to executing in a CICS environment.

Resource Control Table (RCT)

The CICS attachment is controlled by the RCT. In current levels of CICS, the DB2 interface modules are shipped as part of CICS and take advantage of its online resource definition capabilities. The RCT definitions are very flexible allowing the specification of

  • Plan names

  • Authorization checking options

  • Thread limits and pooling options

  • Error processing options

The RCT has three sets of components that must be defined. The DB2CONN object defines global attributes for the CICS DB2 interface, including pool thread and command thread attributes. There is only one DB2CONN entry for a CICS region. Command threads are used by the attachment interface when issuing commands. Pool threads are a group of threads that may be used by any transaction if no dedicated, or entry, threads are defined for that transaction. Pool threads are not reusable.

The DB2ENTRY objects contain attributes for DB2 threads that may be used by a group of transactions. These define the entry, or dedicated, threads that are available for a transaction. The transaction ID can include wildcards to simplify definition. Entry threads are reusable.

The DB2TRAN objects define additional transaction IDs that may be associated with a DB2ENTRY object.

Coordinating DB2 and CICS Security

CICS manages end-user authentication with the system-supplied security system. The CICS attachment has several options for passing authorization IDs to DB2. The authorization ID that is passed to DB2 is controlled by the RCT entry for the transaction and can be

  • The CICS region's sign-on user ID

  • The terminal operator's authorization ID

  • The terminal name

  • The transaction ID

  • The terminal operator's group ID

  • A fixed string defined in the RCT

DB2 Commands

The CICS interface to DB2 has a transaction, DSNC, which can be used to

  • Start the interface

  • Stop the interface

  • Display thread statistics

  • Execute DB2 commands

To start the CICS DB2 interface to subsystem DSN1, the command is

DSNC STRT DSN1

The subsystem doesn't need to be specified on the command unless you want to override the subsystem defined in the DB2CONN object in the RCT.

Stopping the attachment between CICS and DB2 is simply

DSNC STOP QUIESCE

The QUIESCE option will allow work to complete before terminating the attachment. There is also a FORCE option.

The DSNC DISPLAY command allows you to monitor the CICS attachment to DB2 and collect statistical information about the threads that have been used. The following command will display a report showing the number of calls, high watermarks, and commits:

DSNC DISPLAY STATISTICS
Preparing CICS Applications for DB2

The following tasks must be performed for CICS applications accessing DB2 resources:

  1. Precompile the application using the DB2 precompiler.

  2. Translate the application using the CICS command translator.

  3. Compile or assemble the application.

  4. Link-edit the application, including the CICS-supplied SQL language interface module DSNCLI and the appropriate CICS command-level interface module. If the application also accesses DL/I, the corresponding IMS language interface must also be included.

  5. Bind the application to its application plan.

The CICS command translation can be done before the DB2 precompilation, but the CICS translator will issue a warning message for each EXEC SQL statement.

Execution

CICS programs may execute only in CICS address spaces. Load libraries containing programs to run under CICS must be specified in the concatenation of libraries in the DFHRPL DD statement for the CICS region in which the program executes.

CICS programs run under a transaction ID that may require one or more CICS address spaces. A common configuration separates different kinds of work into task-specific regions. Configurations often include Terminal Owning Regions (TOR), Application Owning Regions (AOR), and File Owning Regions (FOR). In this case, the AOR address spaces run the CICS/DB2 attachment code and the application programs. The application load library needs to be present only in the JCL for these AORs.

Units of Work

CICS is a transaction manager and controls the UOW for all programs. The SQL COMMIT and SQL ROLLBACK statements must not be used in DB2/CICS programs. Instead, code the appropriate CICS command-level statements.

EXEC SQL UPDATE MYTABLE
            SET COL2 = 'Y'
          WHERE COL1 = 'A'
            AND COL2 = 'N'

if(SQLCODE == 0)
{

  /* Commit work */
  EXEC CICS SYNCPOINT
}
else
if(SQLCODE < 0)
{
  /* Rollback work */
  EXEC CICS SYNCPOINT ROLLBACK
}

CICS controls the synchronization point processing using either one-phase or two-phase commits as appropriate. Each UOW is marked as complete by a synchronization point, defined as follows:

  • Implicitly at the end of a transaction when the program issues a CICS RETURN command from the initial program.

  • Explicitly by CICS SYNCPOINT commands.

  • Implicitly through a DL/I PSB termination (TERM) call or command.

  • Implicitly when a batch DL/I program issues a DL/I checkpoint call.

If the system fails, DB2 backs out uncommitted changes to data. Changed data returns to its original condition without interfering with other system activities. Sometimes, DB2 data does not return to a consistent state immediately. DB2 does not process in-doubt data (data that is neither uncommitted nor committed) until the CICS attachment facility is also restarted. To ensure that DB2 and CICS are synchronized, both DB2 and the CICS attachment facility must be restarted.

For JDBC applications under CICS, the autocommit setting is turned off by default. You can use native JDBC and SQLJ commit and rollback processing, because the SQLJ/JDBC driver translates commit and rollback statements to CICS syncpoint calls.

Program Characteristics

There are some characteristics specific to developing programs to run under CICS.

Initialization

Application programs running under CICS use the attachment facilities supplied by CICS. There is no need for the application code to load the interface modules. The high-level interface module for the CICS attachment facility is DSNCLI, and all DB2/CICS programs must include it in the link-edit step.

In CICS version 4 and higher, you can tell the attachment to wait for DB2 to start and make itself available at that time. You can also specify that the interface return a SQLCODE of 923 with a reason code that indicates that the attachment facility is not available. In prior releases of CICS, an AEY9 abend was received when an attempt was made to execute a SQL statement before the attachment was available. You can check to see if the DB2 interface is active in the CICS region by using

EXEC CICS INQUIRE EXITPROGRAM

If the command returns an invalid exit request (INVEXITREQ), then the attachment facility is not available. A NORMAL return, however, does not guarantee that the attachment facility is available. The CONNECTST parameter should be used to test whether the attachment facility is ready to process SQL statements, as in

EXEC CICS INQUIRE EXITPROGRAM CONNECTST

The shared resources are called threads. In many cases, the CICS/DB2 interface can take steps to reuse these threads for multiple transactions. This saves significant time in establishing the connection to DB2.

In general, you want transactions to reuse threads whenever possible, because there is a high processor cost associated with thread creation. An existing thread can be reused by a new transaction with the same plan and on the same RCT entry. Nonterminal transactions release their threads at the end of a task. Terminal-driven transactions may release their threads at SYNCPOINT if the following conditions are true.

  • The following special registers must be in their initial state:

    - CURRENT APPLICATION ENCODING SCHEME

    - CURRENT PACKAGESET

    - CURRENT PRECISION

    - CURRENT RULES

    - CURRENT SERVER

    - CURRENT SQLID

  • The CURRENT DEGREE special register must not have been modified during the life of the thread.

  • Declared temporary tables that were defined with ON COMMIT PRESERVE ROWS must have been explicitly dropped.

  • All cursors declared WITH HOLD must be closed.

The most important step in maximizing thread reuse is closing all cursors declared WITH HOLD. A thread for an application that contains an open cursor cannot be reused. A recommended programming practice is to close cursors immediately after you finish using them.

Programs do not need to code CONNECT statements, since the DB2 subsystem specification is controlled by the RCT. They can issue CONNECT statements to connect to remote databases defined in the local communications database.

SQL Processing

Programs use embedded SQL statements. The DB2 precompiler translates the statements into the appropriate language calls to the high-level interface module.

Error Checking

As with the TSO attachment, programs should check the SQLCODE or SQLSTATE returned in the SQLCA after every SQL statement to determine its status. Rather than using DSNTIAR to format error messages, programs running under CICS must use the routine DSNTIAC.

Termination

Normal termination for CICS/DB2 programs consists of closing cursors, if any, and returning to the caller via

EXEC CICS RETURN

During transaction termination, CICS will process an implicit synchronization point and tell DB2 to commit the UOW.

In a CICS SQLJ or JDBC application, you need to explicitly close the java.sql.Connection before the program ends to ensure that work is committed and make the java.sql.Connection object available for reuse. If a CICS program aborts, CICS controls the termination and backout processing. During abort processing, CICS tells the DB2 attachment to back out the UOW.

DB2 Abend

If DB2 abends while an application is running, the application is rolled back to the last commit point. If DB2 terminates while processing a commit request, DB2 either commits or rolls back any changes at the next restart of both DB2 and the CICS attachment facility. Coordinating the cleanup of threads that were "in commit" is the responsibility of CICS.


123 - IMS

Chapter 14. Attachment Programming

IMS

IMS programs access DB2 using the IMS attach facility. It is also possible, but not recommended, to use the CAF.

Capabilities

IMS provides a high-performance execution environment for application programs. An IMS region can connect to one or more DB2 subsystems. You can enter DB2 commands through the /SSR command of IMS.

Restrictions

IMS allows you to define as many external subsystem connections as are required. More than one connection can be defined for different DB2 subsystems. All DB2 connections must be within the same MVS system.

Requirements

The DB2 identification must be defined to the control region, the DL/I batch region, and optionally to each dependent region accessing that DB2 system. To make this identification, you must create a subsystem member (SSM) in the IMS.PROCLIB library, and identify the SSM to the applicable IMS regions. One SSM can be shared by all of the IMS regions, or a specific member can be defined for each region. The fields in this record are as follows:

  • SST=DB2 defines the external subsystem type.

  • SSN=ssid must be the DB2 subsystem name.

  • LIT=SYS1 specifies the language interface token supplied to IMS.

  • ESMT=DSNMIN10 specifies the external subsystem module table.

  • RTT= is an optional resource translation table (RTT). This table maps the IMS application names into DB2 plan names. If omitted, the load module name is used as the plan name. DB2 provides the DSNMAPN macro to generate an RTT.

  • REO= is the region error option to be used. A value of R, the default, causes an appropriate SQL return code to be passed back to the application, except on the first connection when the application is abended. A value of Q abends the application.

  • CRC= is the command recognition character (CRC) used by IMS to identify DB2 commands entered from an IMS terminal.

  • CONNECTION_NAME= specifies the name of the job step that is the coordinator for DB2 activity for DL/I batch. DB2 requires unique connection names for DB2 DL/I batch support. If two applications try to connect with the same connection name, then the second application is not allowed to connect to DB2.

  • PLAN= specifies the DB2 plan name for DL/I batch.

  • PROG= specifies the application program to loaded and execute.

Execution

Programs using the IMS attachment facility run under the control of IMS or as DL/I batch applications.

Units of Work

Like CICS, IMS manages synchronization points and coordinates committing or backing out the UOW with DB2. The SQL COMMIT and ROLLBACK statements are not allowed in IMS programs. Instead, the appropriate IMS facilities should be used to issue checkpoints, commit work, or roll back work. DB2 automatically backs out changes when an application program abends. DL/I changes may need to be backed out using the DL/I batch backout utility.

Program Characteristics

There are some specific characteristics for programs running under the IMS attachment facility.

Initialization

Programs using the IMS attachment require no special initialization processing. Even though a region can communicate with two or more DB2 subsystems, an IMS application can access only the DB2 subsystem referred to in the language interface that is link-edited. You can alter the SSM to route application requests to a different DB2 subsystem.

Programs do not need to code CONNECT statements, since the DB2 subsystem specification is controlled by the SSM. They can issue CONNECT statements to connect to remote databases defined in the local communications database.

SQL Processing

Programs use embedded SQL statements. The DB2 precompiler translates the statements into the appropriate language calls to the high-level interface module during compilation.

Error Checking

As with the TSO and CICS attachments, programs should check the SQLCODE or SQLSTATE returned in the SQLCA after every SQL statement to determine its status.

Termination

Normal termination for IMS/DB2 programs consists of closing cursors, if any, and following standard termination procedures for IMS programs. If an IMS program abends, IMS controls the termination and backout processing.


124 - Call Attachment Facility

Chapter 14. Attachment Programming

Call Attachment Facility

With the CAF, your application program can establish and control its own connection to DB2. Programs that run in MVS batch, TSO foreground, and TSO background can use CAF. It is also possible for IMS batch applications to access DB2 databases through CAF, though that method does not coordinate the commitment of work between the IMS and DB2 systems. We highly recommend that you use the DB2 DL/I batch support for IMS batch applications.

Capabilities

Programs using CAF can

  • Access DB2 from address spaces where there is no TSO, CICS, or IMS.

  • Access the IFI.

  • Access DB2 from multiple tasks within an address space.

  • Control the connection to DB2 explicitly.

  • Connect to DB2 implicitly using a default subsystem ID and plan name.

  • Receive a signal from DB2 on startup or shutdown.

Task Capabilities

Any task in an address space can establish a connection to DB2 through CAF. There can be only one connection for each TCB. A DB2 service request issued by a program running under a given task is associated with that task's connection to DB2. The service request operates independently of any DB2 activity under any other task.

Each connected task can run a plan. Multiple tasks in a single address space can specify the same plan, but each instance of a plan runs independently from the others. A task can terminate its plan and run a different plan without fully breaking its connection to DB2.

CAF does not generate task structures, nor does it provide attention-processing exits or functional recovery routines. You can provide whatever attention-handling and functional recovery your application needs, but you must use extended specify task abend exit (ESTAE/ESTAI) type recovery routines. You cannot use enabled unlocked task (EUT) functional recovery routines(FRR) .

Using multiple simultaneous connections can increase the possibility of deadlocks and DB2 resource contention. Your application design must consider that possibility.

Program Preparation

Preparing your application program to run in CAF is similar to preparing it to run in other environments, such as CICS, IMS, and TSO. You can prepare a CAF application either in the batch environment or by using the DB2 program preparation process.

Restrictions

Stored procedures that run in the DB2 Stored Procedure Address Space (SPAS) address space use the CAF implicitly. They should include the interface module in the link-edit step, but must not implement the calls to DSNALI.

Requirements

To connect to DB2 using CAF, the attachment language interface (DSNALI) module must either be linked into your load module or loaded dynamically. The first parameter passed to DSNALI is called the function. Table 14-3 lists the available functions.

Table 14-3. Function Options for DSNALI

Function

Description

CONNECT

Establishes the TCB as a user of the named DB2 subsystem. When the first task within an address space issues a connection request, the address space is also initialized as a user of DB2.

OPEN

Allocates a DB2 plan. You must allocate a plan before DB2 can process SQL statements. If you did not request the CONNECT function, OPEN implicitly establishes the task, and optionally the address space, as a user of DB2.

CLOSE

Optionally commits or abends any database changes and deallocates the plan. If OPEN implicitly requests the CONNECT function, CLOSE removes the task, and possibly the address space, as a user of DB2.

DISCONNECT

Removes the task as a user of DB2 and, if this is the last or only task in the address space with a DB2 connection, terminates the address space connection to DB2.

TRANSLATE

Returns a SQLCODE and printable text in the SQLCA that describes a DB2 hexadecimal error reason code.

Implicit Connections

If you do not explicitly specify executable SQL statements in a CALL DSNALI statement of your CAF application, CAF initiates implicit CONNECT and OPEN requests to DB2. Although CAF performs these connection requests using the default values defined below, the requests are subject to the same DB2 return codes and reason codes as explicitly specified requests. Implicit connections use the following defaults:

Subsystem name. The default subsystem name is specified in the module DSNHDECP. CAF uses the installation default DSNHDECP unless your own DSNHDECP is in a library in a STEPLIB of JOBLIB concatenation, or is in the link list. In a data-sharing group, the default subsystem name is the group attachment name.

Plan name. The member name of the database request module (DBRM) that DB2 produced when you precompiled the source program that contains the first SQL call. If your program can make its first SQL call from different modules with different DBRMs, then you cannot use a default plan name; you must use an explicit call using the OPEN function.

If your application includes both SQL and IFI calls, you must issue at least one SQL call before you issue any IFI calls. This ensures that your application uses the correct plan.

There are different types of implicit connections. The simplest is for the application to run neither CONNECT nor OPEN. You can also use CONNECT only or OPEN only. Each of these implicitly connects your application to DB2. To terminate an implicit connection, you must use the proper calls.

Your application program must successfully connect, either implicitly or explicitly, to DB2 before it can execute any SQL calls to the CAF DSNHLI entry point. Therefore, the application program must first determine the success or failure of all implicit connection requests.

For implicit connection requests, register 15 contains the return code and register 0 contains the reason code. The return code and reason code are also in the message text for SQLCODE 991. The application program should examine the return and reason codes immediately after the first executable SQL statement within the application program. If the implicit connection was successful, the application can examine the SQLCODE for the first and subsequent SQL statements.

Explicit Load of DSNALI

To load DSNALI, issue MVS LOAD service requests for entry points DSNALI and DSNHLI2. If you use IFI services, you must also load DSNWLI2. The entry point addresses that LOAD returns are saved for later use with the CALL macro.

By explicitly loading the DSNALI module, you beneficially isolate the maintenance of your application from future IBM service to the language interface. If the language interface changes, the change will probably not affect your load module. You must indicate to DB2 which entry point to use. You can do this in one of two ways:

  • Specify the precompiler option ATTACH(CAF). This causes DB2 to generate calls that specify entry point DSNHLI2. You cannot use this option if your application is written in FORTRAN.

  • Code a dummy entry point named DSNHLI within your load module. If you do not specify the precompiler option ATTACH, the DB2 precompiler generates calls to entry point DSNHLI for each SQL request. The precompiler does not know and is independent of the different DB2 attachment facilities.

When the calls generated by the DB2 precompiler pass control to DSNHLI, your code corresponding to the dummy entry point must preserve the option list passed in register 1 and call DSNHLI2, specifying the same option list.

Link-Editing DSNALI

You can include the CAF language interface module DSNALI in your load module during a link-edit step. The module must be in a load module library, which is included either in the SYSLIB concatenation or another INCLUDE library defined in the linkage editor JCL. Because all language interface modules contain an entry point declaration for DSNHLI, the linkage editor JCL must contain an INCLUDE linkage editor control statement for DSNALI; for example,

INCLUDE DB2LIB(DSNALI).

By coding these options, you avoid inadvertently picking up the wrong language interface module.

If you do not need explicit calls to DSNALI for CAF functions, including DSNALI in your load module has some advantages. When you include DSNALI during the link-edit, you need not code the previously described dummy DSNHLI entry point in your program or specify the precompiler option ATTACH. Module DSNALI contains an entry point for DSNHLI, which is identical to DSNHLI2, and an entry point DSNWLI, which is identical to DSNWLI2.

A disadvantage to link-editing DSNALI into your load module is that any IBM service to DSNALI requires a new link-edit of your load module.

Execution

Programs that use CAF can be invoked from TSO as commands or via the CALL command from a CLIST or REXX program. They can also be executed directly from JCL on an EXEC statement.

Units of Work

DB2 manages the UOW for CAF programs. Use the SQL COMMIT and ROLLBACK statements as appropriate within your program.

Program Characteristics

Programs using the CAF have some specific characteristics.

Initialization

For implicit connections, programs need simply execute their SQL statements normally. It is a good idea to check the standard return code after the first call to detect attachment errors. To establish an explicit connection, first call DSNALI with the CONNECT function, then again with the OPEN function.

SQL Processing

SQL statements are embedded in CAF programs just as they are in programs that use any of the other attachment facilities.

Error Checking

Because CAF is a callable interface, you may need to check the standard return code value after an SQL statement and before checking the SQLCODE or SQLSTATE. Errors that occur in the attachment code will return a bad return code, leaving the contents of the SQLCA as they were prior to the call. This type of error is more likely to occur in a stored procedure that is not properly set up to run in the DSNSPAS address space.

Termination

To explicitly close a CAF connection, call DSNALI using the CLOSE function and again using the DISCONNECT function. Explicitly closing the connection is optional. If a connected task terminates normally before the CLOSE function deallocates the plan, then DB2 commits any database changes that the thread made since the last commit point. If a connected task abends before the CLOSE function deallocates the plan, then DB2 rolls back any database changes since the last commit point.

In either case, DB2 deallocates the plan, if necessary, and terminates the task's connection before it allows the task to terminate. A tracing facility provides diagnostic messages that aid in debugging programs and diagnosing errors in the CAF code. In particular, attempts to use CAF incorrectly cause error messages in the trace stream.

DB2 Abend

If DB2 abends while an application is running, the application is rolled back to the last commit point. If DB2 terminates while processing a commit request, DB2 either commits or rolls back any changes at the next restart. The action taken depends on the state of the commit request when DB2 terminates.


125 - RRSAF

Chapter 14. Attachment Programming

RRSAF

An application program can use the RRSAF to connect to and use DB2 to process SQL statements, commands, or IFI calls. Programs that run in MVS batch, TSO foreground, and TSO background can use RRSAF.

RRSAF uses OS/390 Transaction Management and Recoverable Resource Manager Services (OS/390 RRS). With RRSAF, you can coordinate DB2 updates with updates made by all other resource managers that also use OS/390 RRS in an MVS system.

Capabilities

Programs that use RRSAF can

  • Run under UNIX System Services.

  • Sign on to DB2 with an alternate user ID.

  • Access DB2 from one or more tasks in an address space.

  • Use the IFI.

  • Control the exact state of the DB2 connection.

  • Capture DB2 startup and termination events.

Programs using RRSAF can be run from almost every environment available under z/OS and OS/390. They can be invoked from the command prompt in TSO, from a shell prompt under UNIX System Services, and like any non-DB2 on the EXEC card in JCL. Each TCB can have only one connection to DB2. Using RRSAF, this connection can be switched between tasks within the address space.

Restrictions

Stored procedures that execute in WLM environments use RRSAF implicitly. No calls to DSNRLI should be made by the stored procedure code.

Requirements

To use RRSAF to communicate with DB2, a program must call the DSNRLI program, passing it the appropriate functions. Several calls are required to identify the program to DB2, sign on, and create a thread. The program has considerable control over the process when compared to the TSO attachment where the program has to assume the connection has already been established.

Loading DSNRLI Explicitly

To load DSNRLI, issue MVS LOAD macros for entry points DSNRLI and DSNHLIR. If you use IFI services, you must also load DSNWLIR. Save the entry point address that LOAD returns and use it in the CALL macro.

By explicitly loading the DSNRLI module, you can isolate the maintenance of your application from future IBM service to the language interface. If the language interface changes, the change will probably not affect your load module. You must indicate to DB2 which entry point to use. You can do this in one of two ways:

  • Specify the precompiler option ATTACH(RRSAF). This causes DB2 to generate calls that specify entry point DSNHLIR.

  • Code a dummy entry point named DSNHLI within your load module. If you do not specify the precompiler option ATTACH, the DB2 precompiler generates calls to entry point DSNHLI for each SQL request. The precompiler does not know and is independent of the different DB2 attachment facilities.

When the calls generated by the DB2 precompiler pass control to DSNHLI, your code corresponding to the dummy entry point must preserve the option list passed in R1 and call DSNHLIR specifying the same option list.

Execution

Programs using RRSAF can be invoked from command lines under TSO or UNIX System Services, or directly from JCL, as in the following:

//MYJOB1  JOB
//STEP1   EXEC PGM=MYPGM
//STEPLIB  DD  DSN=MY.LOADLIB,DISP=SHR
//SYSPRINT DD  SYSOUT=*
//SYSOUT   DD  SYSOUT=*
//SYSIN    DD  DUMMY

The ability to code your DB2 program in JCL this way is a big bonus when operations staff are unfamiliar with batch-mode TSO.

Units of Work

To commit work in RRSAF applications, use the CPIC SRRCMIT function or the DB2 COMMIT statement. To roll back work, use the CPIC SRRBACK function or the DB2 ROLLBACK statement.

Use DB2 COMMIT and ROLLBACK statements when you know that the following conditions are true:

  • The only recoverable resource accessed by your application is DB2 data managed by a single DB2 instance.

  • The address space from which syncpoint processing is initiated is the same as the address space that is connected to DB2.

If your application accesses other recoverable resources, or syncpoint processing and DB2 access are initiated from different address spaces, use SRRCMIT and SRRBACK.

How to Program

To use RRSAF, you must first make available the RRSAF language interface load module, DSNRLI. This can be achieved by linking DSNRLI into your load module or loading it dynamically at execution time. Your program then calls DSNRLI to establish the connection to DB2.

The DSNRLI interface includes the program DSNRLI, which takes several parameters. The first parameter is the function you want performed. The functions listed in Table 14-4 are available.

Table 14-4. DSNRLI Functions

Function

Description

IDENTIFY

Establishes the task as a user of the named DB2 subsystem. When the first task within an address space issues a connection request, the address space is initialized as a user of DB2.

SWITCH TO

Directs RRSAF, SQL, or IFI requests to a specified DB2 subsystem.

SIGNON

Provides to DB2 a user ID and, optionally, one or more secondary authorization IDs that are associated with the connection.

AUTH SIGNON

Provides to DB2 a user ID, an Accessor Environment Element (ACEE), and optionally one or more secondary authorization IDs that are associated with the connection.

CONTEXT SIGNON

Provides to DB2 a user ID and optionally one or more secondary authorization IDs that are associated with the connection. You can execute CONTEXT SIGNON from an unauthorized program.

CREATE THREAD

Allocates a DB2 plan or package. CREATE THREAD must complete before the application can execute SQL statements.

TERMINATE THREAD

Deallocates the plan.

TERMINATE IDENTIFY

Removes the task as a user of DB2 and, if this is the last or only task in the address space that has a DB2 connection, terminates the address space connection to DB2.

TRANSLATE

Returns an SQL code and printable text, in the SQLCA, that describes a DB2 error reason code. You cannot call the TRANSLATE function from the FORTRAN language.

The effect of any function depends in part on what functions the program has already performed. Before using any function, be sure to read the description of its usage. To better understand how functions can be used, we'll provide code samples for some common routines that can be used to make this easy.

Initialization

The following code section shows the initialization portion of the OpenDB2() function implemented in C. This particular function takes the DB2 subsystem ID and the plan name to be used for this connection.

extern int OpenDB2(const char* db2ssid, const char* db2plan)
{
   char funcIdentify[19]          = "IDENTIFY          ";
   char funcSignon[19]            = "SIGNON            ";
   char funcCreateThread[19]      = "CREATE THREAD     ";

   long     fnret;

   char     Ssid[5] = "DSN ";
   char     Plan[9] = "TEST    ";
   char     Collection[19] = "                  ";
   char     Reuse[9] = "INITIAL ";

   char *   ribptr;
   char *   eibptr;

   long     startecb = 0;
   long     termecb = 0;
   long     ReturnCode = 0;
   long     ReasonCode = 0;

   char     CorrelationId[13];
   char     AcctToken[23];
   char     AcctInterval[7]   = "SIGNON";
   char     UserId[17];
   char     ApplId[33];
   char     WsId[19];

   long     i = 0;

Now that the housekeeping functions are out of the way, we use the IDENTIFY function to start the communication with DB2. This is where the DB2 subsystem ID gets specified to the attachment.

strncpy(Ssid, db2ssid, 4);
i = strlen(Ssid);
if (i < 4)  /* SSID must be blank padded */
{
    i = 4 - i;
    strncat(Ssid, "    ", i);
}

fnret = DSNRLI(&funcIdentify[0],
               &Ssid[0],
               &ribptr,
               &eibptr,
               &termecb,
               &startecb,
               &ReturnCode,
               &ReasonCode);

if (fnret != 0)
{
}

Then we use the SIGNON function. This provides an accounting token that can be used to identify our connection for charge-back purposes. We also get to set the correlation ID that is used to identify the connection to DB2 display commands and performance monitors.

strncpy(CorrelationId, "TEST", 4);
strncpy(&(CorrelationId[4]), db2plan, 8);

fnret = DSNRLI(&funcSignon[0],
               &CorrelationId[0],
               &AcctToken[0],
               &AcctInterval[0],
               &ReturnCode,
               &ReasonCode);

if (fnret != 0)
{
   /* Error handling */
}

The last part of establishing the connection is thread creation, where we specify the DB2 plan name for our application.

Strncpy(Plan, db2plan, 8);

 fnret = DSNRLI(&funcCreateThread[0],
                &Plan[0],
                &Collection[0],
                &Reuse[0],
                &ReturnCode,
                &ReasonCode);

 if (fnret != 0)
 {
    /* Error handling */
 }
 return 0;
}

When the OpenDB2() function returns, we are connected to DB2 and ready to execute SQL statements.

SQL Processing

SQL statements are embedded in RRSAF programs just as they are in programs that use any of the other attachment facilities.

Error Checking

Calls to DSNRLI return a status return code and reason code. The reason codes correspond to standard DB2 reason codes available in the IBM DB2 Message and Codes Manual-GC26-9940. Programs should check the SQLCODE or SQLSTATE returned in the SQLCA after every SQL statement to determine its status.

Termination

Closing the RRSAF connection to DB2 is optional and is almost the reverse of the initialization steps. Here is a bit of sample code to perform the close. Before calling this routine, the UOW must be committed. If the UOW is not committed, your program will abend. The routine first terminates the thread.

extern int CloseDB2()
{
    long     fnret;
    long     ReturnCode = 0;
    long     ReasonCode = 0;

    fnret = DSNRLI(&funcTerminateThread[0],
                   &ReturnCode,
                   &ReasonCode);
    if (fnret != 0)
    {
       /* Error Handling */
    }

It then terminates the identify.

   fnret = DSNRLI(&funcTerminateIdentify[0],
                  &ReturnCode,
                  &ReasonCode);
   if (fnret != 0)
   {
      /* Error Handling */
   }
  return 0;
}

If an application that is connected to DB2 through RRSAF terminates normally before the TERMINATE THREAD or TERMINATE IDENTIFY functions deallocate the plan, then OS/390 RRS commits any changes made after the last commit point.

If the application terminates abnormally before the TERMINATE THREAD or TERMINATE IDENTIFY functions deallocate the plan, then OS/390 RRS rolls back any changes made after the last commit point.

In either case, DB2 deallocates the plan, if necessary, and terminates the application's connection. A tracing facility provides diagnostic messages that help you debug programs and diagnose errors in the RRSAF code. The trace information is available only in a SYSABEND or SYSUDUMP dump.

DB2 Abend

If DB2 abends while an application is running, the application is rolled back to the last commit point. If DB2 terminates while processing a commit request, DB2 either commits or rolls back any changes at the next restart. The action taken depends on the state of the commit request when DB2 terminates.


126 - Summary

Chapter 14. Attachment Programming

Summary

With the exception of the DB2 utilities, all programs that access DB2 data use one of the five attachment facilities. This includes the DB2 commands, like BIND, that run under the DSN command processor using the TSO attachment. Query Management Facility (QMF) is an example of an IBM product that uses CAF as well as most performance monitoring tools.


127 - Additional Resources

Chapter 14. Attachment Programming

Additional Resources

IBM DB2 Application Programming and SQL Guide SC26-9933

IBM DB2 Messages and Codes GC26-9940


128 -

Part 5: Advanced Programming Functions

    Chapter 15. Object-Relational Programming

    Chapter 16. Locking and Concurrency

    Chapter 17. Application Performance and Optimization

    Appendix A. IBM Certified Solutions ExpertDB2 UDB Family Application Development

    Chapter B. Resources

    Chapter C. DB2CERT Database DDL


129 - Chapter 15. Object-Relational Programming

Part 5. Advanced Programming Functions

Chapter 15. Object-Relational Programming

  • Triggers

  • User-Defined Functions (UDFs)

  • Table Functions

  • User-Defined Data Types (Distinct Types)

  • Object-Relational Extensions

  • LOBs and Extenders

This chapter covers some of the more powerful features of DB2's SQL language. The extended programming features, UDFs, and table functions are discussed along with triggers and user-defined data types (UDTs). The object-relational extensions used to support these features are also covered, and we take a look at how to implement and use large objects (LOBs) and DB2 Extenders.


130 - Triggers

Chapter 15. Object-Relational Programming

Triggers

A trigger is a set of actions that will be executed when a defined event occurs. These are known as active triggers. The triggering events can be the following SQL statements:

  • INSERT

  • UPDATE

  • DELETE

Triggers are defined for a specific table and once defined, a trigger is automatically active. A table can have multiple triggers defined for it, and if multiple triggers are defined for a given table, the order of trigger activation is based on the trigger creation timestamp (the order in which the triggers were created). Trigger definitions are stored in the DB2 catalog tables.

  • SYSIBM.SYSTRIGGERS

    - One row for each trigger

    - TEXT column contains full text of CREATE TRIGGER

  • SYSIBM.SYSPACKAGE

    - One row for each trigger package

    - TYPE column set to T to indicate a trigger package

Trigger Usage

Some of the uses of a trigger include the following:

  • Data Validation: Ensures that a new data value is within the proper range. This is similar to table-check constraints, but it is a more flexible data-validation mechanism.

  • Data Conditioning: Implemented using triggers that fire before data record modification. This allows the new data value to be modified or conditioned to a predefined value.

  • Data Integrity: Can be used to ensure that cross-table dependencies are maintained.

The triggered action could involve updating data records in related tables. This is similar to referential integrity, but it is a more flexible alternative.

We can also use triggers to enforce business rules, create new column values or edit column values, validate all input data, or maintain summary tables or cross-reference tables. They provide for enhanced enterprise and business functionality and faster application development and global enforcement of business rules.

Limited only by our imagination, the trigger is our way of getting control to perform an action whenever a table's data is modified. A single trigger invoked by an update on a financial table could invoke a UDF and/or call a stored procedure to invoke another external action, which triggers an email to a pager to notify the DBA of a serious condition. Farfetched? No, it is already being done.

Triggers can cause other triggers to be invoked and, through the SQL, can call stored procedures. These stored procedures could issue SQL updates that invoke other triggers. This allows great flexibilitywe can use triggers to enforce business rules, create new column values or edit column values, validate all input data, or maintain summary tables or cross reference tables. The trigger is just a way of getting control whenever a table's data is modified.

There is currently a safe limit to the cascading of triggers, stored procedures, and UDFs, which is an execution time nesting depth of 16. This prevents the endless cascading that would be possible. There is a big performance concern here, because if the 17th level is reached, an SQLCODE of 724 is set but all 16 levels are backed out. That could be a significant problem and not something you want to see. The real issue here is processes that are executed outside the control of DB2, since they would not be backed out and it might be very difficult to determine what was changed. There are limitations in the calling sequences; for example, stored procedures that are Workload Manager (WLM)-managed cannot call stored procedures that are DB2-managed.

Trigger Activation

A trigger can be defined to fire (be activated) in one of two ways:

  • A before trigger will fire for each row in the set of affected rows before the triggering SQL statement executes. Therefore, the trigger body is seeing the new data values prior to its being inserted or updated into the table.

  • An after trigger will fire for each row in the set of affected rows or after the statement has successfully completed (depending on the defined granularity). Therefore, the trigger body is seeing the table as being in a consistent state (i.e., all transactions have been completed).

Another important feature about triggers is that they can fire other triggers (or the same trigger) or other constraints. These are known as cascading triggers.

During the execution of a trigger, the new and old data values can be accessible to the trigger, depending on the nature of the trigger (before or after). By using triggers you can:

  • Reduce the amount of application development and make development faster. Since triggers are stored in DB2 itself and are processed by DB2, you do not need to code the triggers or their actions into your applications.

  • Provide a global environment for your business rules. Since the triggers have to be defined only once and then are stored in the database, they are available to all applications executing against the database.

  • Reduce the maintenance of your applications. Since the trigger is handled by DB2 and is stored in the database itself, any changes to the trigger due to changes in your environment have to occur in only one, not multiple, applications.

Creating Triggers

Triggers are defined using the CREATE TRIGGER statement, which contains many options. The primary options are whether it is a before trigger or an after trigger, whether it is a row trigger or a statement trigger, and the language of the trigger. The language is currently only SQL, but that will probably change in the future. There is even rumor that the SQL procedure language is a candidate for triggers. The phrase MODE DB2SQL is the execution mode of the trigger. This phrase is required for each trigger to ensure that an existing application will not be negatively impacted if alternative execution modes for triggers are added to DB2 in the future. You can have up to 12 types of triggers on a single table. See Figure 15-1.

Figure 15-1. Trigger Types

NOTE

Triggers get invoked in the order they were created! A timestamp is recorded when the trigger is created (and recreated). A DROP and (re)CREATE of a trigger can completely mess up your process by changing the order in which triggers are executed. Be careful!

When adding triggers, the rows that are in violation of a newly added trigger will not be rejected. When a trigger is added to a table that already has existing rows, it will not cause any triggered actions to be activated. If the trigger is designed to enforce some type of integrity constraint on the data rows in the table, those constraints may not be enforced by rules defined in the trigger (or held true) for the rows that existed in the table before the trigger was added.

If an update trigger without an explicit column list is created, packages with an update usage on the target table are invalidated. If an update trigger with a column list is created, packages with update usage on the target table are only invalidated if the package also has an update usage on at least one column in the column-name list of the CREATE TRIGGER statement. If an insert trigger is created, packages that have an insert usage on the target table are invalidated. If a delete trigger is created, packages that have a delete usage on the target table are invalidated.

There is a lot of functionality that can be used within a trigger. For example, a CASE expression can be used in a trigger, but it needs to be nested inside a VALUES statement, as shown here:

BEGIN ATOMIC
   VALUES CASE
      WHEN condition
         THEN something
      WHEN other condition
         THEN something else   END
END;

The best method of understanding the usage of triggers is to see some in action. The DB2CERT database contains many relationships that can be maintained using triggers.

After Trigger

In the following example, a trigger is defined to set the value of the PASS_FAIL column for each of the tests taken by a candidate. (Note that we add this column for this scenario.) The trigger has been given the name PassFail (no relationship with the column called PASS_FAIL). Once the trigger has been created, it is active.

The PassFail trigger is an AFTER, INSERT, and FOR EACH ROW trigger. Every time there is a row inserted into the test_taken table, this trigger will fire. The trigger body section will perform an UPDATE statement to set the value of the PASS_FAIL column for the newly inserted row. The column is populated with either the value P (representing a passing grade) or the value F (representing a failing grade).

NOTE

Remember that a trigger defined against one table can modify other tables in the trigger body.

CREATE TRIGGER PassFail
  AFTER INSERT ON db2cert.test_taken
  REFERENCING NEW AS n
  FOR EACH ROW MODE DB2SQL
UPDATE db2cert.test_taken
  SET PASS_FAIL =
    CASE
      WHEN n.score >=
        (SELECT cut_score FROM db2cert.test
         WHERE number = n.number)
      THEN'P'
      WHEN n.score <
        (SELECT cut_score FROM db2cert.test
         WHERE number = n.number)
         THEN'F'
         END
   WHERE n.cid = cid
     AND n.tcid = tcid
     AND n.number = number
     AND n.date_taken = date_taken

Before Trigger

A before trigger will be activated before the trigger operation has completed. The triggering operation can be on an INSERT, UPDATE, or DELETE statement. This type of trigger is very useful for three purposes:

  • To condition data.

  • To provide default values.

  • To enforce data value constraints dynamically.

There are three before trigger examples shown below that are used in the DB2 Certification application. All three of these triggers have been implemented to avoid seat conflicts for test candidates. The triggers will fire during an insert of each new candidate for a test.

** Example 1 **
CREATE TRIGGER pre9 NO CASCADE BEFORE
   INSERT ON db2cert.test_taken
   REFERENCING NEW AS n
   FOR EACH ROW MODE DB2SQL
WHEN (n.start_time <'09:00:00')
   SIGNAL SQLSTATE 70003'
   ('Cannot assign seat before 09:00:00!')

** Example 2 **
CREATE TRIGGER aft5 NO CASCADE BEFORE
   INSERT ON db2cert.test_taken
   REFERENCING NEW AS n
   FOR EACH ROW MODE DB2SQL
WHEN (n.start_time +
   (SELECT SMALLINT(length) FROM db2cert.test
   WHERE number = n.number) MINUTES
      >'17:00:00')
   SIGNAL SQLSTATE'70004'
   ('Cannot assign seat after 17:00:00!')

** Example 3 **
CREATE TRIGGER start NO CASCADE BEFORE
   INSERT ON db2cert.test_taken
   REFERENCING NEW AS n
   FOR EACH ROW MODE DB2SQL
WHEN (
   EXISTS (SELECT cid FROM db2cert.test_taken
   WHERE seat_no = n.seat_no
   AND tcid = n.tcid
   AND date_taken = n.date_taken
   AND n.start_time BETWEEN
      start_time AND finish_time))
   SIGNAL SQLSTATE '70001' ('Start Time Conflict!')

If the conditions are encountered, an SQL error will be flagged using the SQL function called SIGNAL. A different SQLSTATE value will be provided when the triggered conditions are encountered.

The pre9 trigger, shown above, is used to ensure that a test candidate is not scheduled to take a test before 9:00 a.m. The aft5 trigger is used to ensure that a test candidate is not scheduled to take a test after 5:00 p.m. The start trigger is used to avoid conflicts during a testing day.

Row and Statement Triggers

In order to understand the concept of trigger granularity, it is necessary to understand the rows affected by the triggering operations. The set of affected rows contains all rows that are deleted, inserted, or updated by the triggering operations.

Row Triggers

The keyword FOR EACH ROW is used to activate the trigger as many times as the number of rows in the set of affected rows. The previous example shows a row trigger.

Statement Triggers

They keyword FOR EACH STATEMENT is used to activate the trigger once for the triggering operation.

Transition Variables and Tables

We can use transition variables and tables to see before and after images of data effected by trigger executiion.

Transition Variables

Transition variables allow row triggers to access columns of affected row data in order to see the row data as it existed before the triggering operation and see the row data as it existed after the triggering operation. These variables are implemented by a REFERENCING clause in the definition.

REFERENCING OLD AS OLD_ACCOUNTS
              NEW AS NEW_ACCOUNTS

The following example uses transition variables to prevent an update from occurring:

CREATE TRIGGER TR1 NO CASCADE BEFORE
   UPDATE ON EMP

   REFERENCING NEW AS T1
   FOR EACH ROW MODE DB2SQL
WHEN (
   EXISTS (SELECT 1
   FROM DEPT B, EMP C
   WHERE B.DEPTNO=T1.WORKDEPT
   AND B.MGRNO=C.EMPNO
   AND C.SALARY <= T1.SALARY)
SIGNAL SQLSTATE '70001' ('Salary too big!')

Here, whenever an update is made to the EMP table, the new value of the salary of the employee, referenced in the before trigger transition variable T1.SALARY is checked against the salary of that employee's manager. This is done by joining the employee table to the department table, using the transition variable T1.WORKDEPT to get the department information for the employee being updated. Then the EMP table is joined using the manager's employee number in order to get the salary of the manager.

Transition Tables

Transition tables allow after triggers to access a set of affected rows and see how they were before the triggering operation and then see all rows after the triggering operation. Transition tables are also implemented using the REFERENCING clause in the trigger definition.

REFERENCING OLD_TABLE AS OLD_ACCT_TABL
NEW_TABLE AS NEW_ACCT_TABLE

NOTE

Transition tables are materialized in DSNDB07.

Transition tables allow an SQL statement embedded in the trigger body to access the entire set of affected data in the state it was in before or after the change. In the following example, a fullselect reads the entire set of changed rows to pass qualifying data to a user defined function:

CREATE TRIGGER EMPMRGR
AFTER UPDATE ON EMP
REFERENCING NEW TABLE AS NTABLE
FOR EACH STATEMENT MODE DB2SQL
BEGIN ATOMIC
    SELECT SALARYALERT(EMPNO, SALARY)
    FROM NTABLE
    WHERE SALARY > 150000;
END;

Transition tables can also be passed to stored procedures and UDFs that are invoked within the body of the trigger. The actual table is not passed as a parameter, but instead a table locator is passed, which can then be used to establish a cursor within the stored procedure or UDF. The following example demonstrates the passing of a transition table to a UDF:

CREATE TRIGGER EMPMRGR
AFTER UPDATE ON EMP
REFERENCING NEW TABLE AS NTABLE
FOR EACH STATEMENT MODE DB2SQL
BEGIN ATOMIC
    VALUES (SALARYALERT(TABLE NTABLE));
END;

The corresponding function definition would look something like this:

CREATE FUNCTION SALARYALERT (TABLE LIKE EMP AS LOCATOR)
    RETURNS INTEGER
    EXTERNAL NAME SALERT
    PARAMETER STYLE DB2SQL
    LANGUAGE C;

The C language program would declare a cursor against the transition table by referencing the locator variable that was passed as a parameter in place of a table reference:

DECLARE C1 CURSOR FOR
    SELECT EMPNO, SALARY
    FROM TABLE(:LOC1 LIKE EMP)
    WHERE SALARY > 150000;

Once the input locator parameter is accepted into the :LOC1 variable, the cursor can be opened and processed.

Allowable Combinations

While there are many different combinations of triggers options available, not all are compatible. Table 15-1 shows the valid combinations for trigger options.

Table 15-1. Trigger Option Combinations

Granularity

Activation Time

Trigger Operation

Transition Variables Allowed

Transition Tables Allowed

ROW

BEFORE

INSERT

NEW

none

UPDATE

OLD, NEW

DELETE

OLD

AFTER

INSERT

NEW

NEW_TABLE

UPDATE

OLD, NEW

OLD_TABLE, NEW_TABLE

DELETE

OLD

OLD_TABLE

STATEMENT

BEFORE

Invalid

none

Invalid

AFTER

INSERT

NEW_TABLE

UPDATE

OLD_TABLE, NEW_TABLE

DELETE

OLD_TABLE

Trigger Packages

When a trigger is created, DB2 creates a trigger package. This package is different from packages that you created for an application program (for more information on packages, refer to Chapter 6, "Binding an Application Program"). Trigger packages can be rebound locally, but you cannot bind them (this is done automatically during creation). The package can be rebound only with the REBIND TRIGGER PACKAGE command, and this will allow you to change subsets of default bind options (CURRENTDATA, EXPLAIN, FLAG, ISOLATION, RELEASE). For more information on the bind options, refer to Chapter 6.

Trigger packages cannot be copied, freed, or dropped. In order to delete a trigger package, the DROP TRIGGER SQL statement must be issued.

NOTE

Rebinding trigger packages after creation is also useful for picking up new access paths.

The qualifier of trigger name determines package collection. For static SQL, the authorization ID of the QUALIFIER bind option will be the qualifier, and for dynamic SQL, whatever the CURRENT SQLID is will be the qualifier.

Trigger Invalidations

Invalid updates can be detected and stopped by triggers in a couple of ways. You can use the SIGNAL SQLSTATE or the RAISE_ERROR.

SIGNAL SQLSTATE

SIGNAL SQLSTATE is a new SQL statement that is used to cause an error to be returned to the application with a specified SQLSTATE code and a specific message to stop processing. This statement can be used only as a triggered SQL statement within a trigger and can be controlled with a WHEN clause. The example below shows the use of the SIGNAL statement.

WHEN NEW_ACCT.AMOUNT < (OLD_ACCT.AMOUNT)
   SIGNAL SQLSTATE '99001' ('Bad amount field')
RAISE_ERROR

RAISE_ERROR is not a statement but a built-in function that causes the statement that includes it to return an error with a specific SQLSTATE, SQLCODE 438, and a message. It does basically the same thing as the SIGNAL statement and can be used wherever an expression can be used. The RAISE_ERROR function always returns null with an undefined data type. RAISE_ERROR is most useful in CASE expressions, especially when the CASE expression is used in a stored procedure. The following example shows a CASE expression with the RAISE_ERROR function.

VALUES (CASE
  WHEN NEW_ACCT.AMOUNT < OLD_ACCT.AMOUNT
  THEN RAISE_ERROR('99001', 'Bad amount field'))
Forcing a Rollback

If you use the SIGNAL statement to raise an error condition, a rollback will also be performed to back out the changes made by an SQL statement as well as any changes caused by the trigger, such as cascading effects resulting from a referential relationship. SIGNAL can be used in either before or after triggers. Other statements in the program can either be committed or rolled back.

Performing Actions Outside of a Database

Triggers can contain only SQL, but through SQL, stored procedures and UDFs can be invoked. Since stored procedures and UDFs are user-written code, almost any activity can be performed from a triggered event. The action causing the trigger may need a message sent to a special place via email. The trigger might be a before trigger written to handle complex referential integrity checks, which could involve checking if data exists in another non-DB2 storage container. Through the use of stored procedures and UDFs, the power of a trigger is almost unlimited.

Performance Issues

Recursive triggers are updates applied by a trigger causing the same trigger to fire off. These can easily lead to loops and can be very complex statements. However, this may be required by some applications for related rows. You will need code to stop the trigger.

Ordering of multiple triggers can be an issue because triggers on same table are activated in order created (identified in the creation timestamp). The interaction among triggers and referential constraints can also be an issue, because the order of processing can be significant on results produced.

When invoking stored procedures and UDFs from triggers, there are performance and manageability concerns. Triggers can include only SQL but can call stored procedures and UDFs, which are user-written and therefore have many implications on integrity and performance. Transition tables can be passed to stored procedures and UDFs also.

Trigger cascading is when a trigger could modify the triggering table or another table. Triggers can be activated at the same level or different levels, and when activated at different levels, cascading occurs. This can occur only for after triggers. Cascading can occur for UDFs, stored procedures, and triggers. Figure 15-2 shows how to find out how many levels of cascading have occurred. This information can be found in a DB2PM accounting report.

Figure 15-2. Trigger Information in DB2PM Accounting Report

Monitoring Triggers

There are various ways to monitor the various actions of triggers. The DB2PM statistics and accounting reports show statistics such as

  • The number of times a trigger has been activated.

  • The number of times a row trigger was activated.

  • The number of times an SQL error occurred during the execution of a triggered action.

Other details can be found in the traces. For example, in IFCID 16 you can find information about the materialization of a work file in support of a transition table where TR is the transition table for triggers. Other information in IFCID 16 includes the depth level of the trigger (016), where 0 indicates that there are no triggers. You can also find the type of SQL that invoked the trigger:

I = INSERT,

U = INSERT into a transition table because of an update,

D = INSERT into a transition table because of a delete.

The type of referential integrity (RI) that caused an insert into a transition table for a trigger is also indicated with an S for SET NULL (can occur when the above is a U) or C for CASCADE DELETE (can occur when the above value is D).

If a transition table needs to be scanned for a trigger, you can find this occurrence in IFCID 17: TR for transition table scan for a trigger.

Catalog Information

The SYSIBM.SYSTRIGGERS catalog table contains information about the triggers defined in your databases. To find all the triggers defined on a particular table, the characteristics of each trigger, and to determine the order in which they are executed, you can issue the following query:

SELECT DISTINCT SCHEMA, NAME, TRIGTIME, TRIGEVENT,
       GRANULARITY, CREATEDTS
FROM SYSIBM.SYSTRIGGERS
WHERE TBNAME = table-name
  AND TBOWNER = table-owner
ORDER BY CREATEDTS

You can get the actual text of the trigger with the following statement:

SELECT TEXT, SEQNO
FROM SYSIBM.SYSTRIGGERS
WHERE SCHEMA = schema_name
  AND NAME = trigger_name
ORDER BY SEQNO

Triggers Versus Table-Check Constraints

If a trigger and a table-check constraint can enforce the same rule, it is better to use a table-check constraint to enforce business rules. You would want to explore the use of triggers only when a constraint is not enough to enforce a business rule. Constraints and declarative RI are more useful when you have only one state to enforce in a business rule. While triggers are more powerful than table-check constraints and can be more extensive in terms of rule enforcement, constraints can be better optimized by DB2.

Table-check constraints are enforced for all existing data at the time of creation, and are enforced for all statements affecting the data. A table-check constraint is defined on a populated table using the ALTER TABLE statement, and the value of the CURRENT RULES special register is DB2. Constraints offer a few other advantages over triggers, such as that they are written in a less procedural way than triggers and are better optimized. They protect data against being placed into an invalid state by any kind of statement, whereas a trigger applies only to a specific kind of statement, such as an update or delete.

Triggers are more powerful than check constraints because they can enforce several rules that constraints cannot. You can use triggers to capture rules that involve different states of data, maybe where you need to know the state of the data before and after a calculation.

Triggers and Declarative RI

Trigger operations may result from changes made to enforce DB2 enforced referential constraints. For example, if you are deleting a row from the EMPLOYEE table that causes propagated deletes to the PAYROLL table through referential constraints, the delete triggers that are defined on the PAYROLL table are subsequently executed. The delete triggers are activated as a result of the referential constraint defined on the EMPLOYEE table. This may or may not be the desired result, so we need to be aware of cascading effects when using triggers.

Triggers and UDFs

You can use a UDF in a trigger, and these types of functions can help to centralize rules to ensure that they are enforced in the same manner in current and future applications. To invoke a UDF in a trigger, the VALUES clause has to be used. Figure 15-3 shows an example of how to invoke a UDF in a trigger.

Figure 15-3. Invoking a UDF from a Trigger

In the example below, PAGE_DBA is a user-written program, perhaps in C or Java, that formulates a message and triggers a process that sends a message to a pager. By using these kinds of UDFs in triggers, it is possible for a trigger to perform any kind of task and not just be limited to SQL.

BEGIN ATOMIC
   VALUES(PAGE_DBA('Table spaces:' CONCAT TS.NAME,
      'needs to be reorged NOW!'));
END

UDFs are discussed in more detail later in this chapter.


131 - Object-Relational Extensions

Chapter 15. Object-Relational Programming

Object-Relational Extensions

With the object extensions of DB2, you can incorporate object-oriented concepts and methodologies into your relational database by extending DB2 with richer sets of data types and functions. With those extensions, you can store instances of object-oriented data types in columns of tables and operate on them using functions in SQL statements. In addition, you can control the types of operations that users can perform on those data types. The object extensions that DB2 provides are

  • Large objects (LOBs)

  • Distinct types

  • UDFs

Schemas

Schemas are qualifiers used for the object-relational extensions as well as stored procedures. They are used to qualify

  • User-Defined Distinct Types

  • UDFs

  • Stored Procedures

  • Triggers

All of the objects qualified by the same schema name can be thought of as a group of related objects. A schema name has a maximum length of 8 bytes. The schema name SYSIBM is used for built-in data types and built-in functions, and SYSPROC is used for some stored procedures delivered by IBM in support of the control center as well as Visual Explain.

Schema Names

The schema name can be specified explicitly when the object is referenced in the CREATE, ALTER, DROP, or COMMENT ON statement. If the object is unqualified and the statement is dynamically prepared, the SQL authorization ID contained in the CURRENT SQLID special register is used for the schema name of the objects.

Schema Privileges

There are certain authorities associated with schemas. Schema privileges include CREATEIN, ALTERIN, and DROPIN. This allows you to create, alter, or drop objects in the identified schema. If the schema name is an authorization ID, then that authorization ID has those privileges implicitly.

PATH Bind Option

The PATH bind option is applicable to BIND PLAN, BIND PACKAGE, REBIND PLAN, and REBIND PACKAGE. The list of schemas specified is used to resolve unqualified references to user-defined distinct types and UDFs in static SQL statements. It is also used to resolve unqualified stored procedure names when the SQL CALL statement specifies a literal for the procedure name. It specifies an ordered list of schemas to be searched to resolve these unqualified references.

CURRENT PATH Special Register

There is also a corresponding special register for the PATH. The SET CURRENT PATH statement changes the value of the PATH special register. This PATH special register is used in the same way as the PATH bind optionto resolve unqualified references in dynamic SQL. It can also be used to resolve unqualified stored procedure names in CALL host-variable statements. The PATH bind option is used to set the initial value for this special register. SYSIBM and SYSPROC do not need to be specified as part of the PATHthey are implicitly assumed as the first schema.

User-Defined Data Types

We looked briefly at what user-defined data types (UDTs) are and how they are implemented using Data Definition Language (DDL) in Chapter 2, "Database Objects." In this section we take a closer look at UDTs and some of their benefits.

By using UDTs, you can avoid some excess code in order to support data typing that is not included in the DB2 product. You enable DB2 to do strong-typing, which says that only functions and operations defined on the UDT can be applied to instances of the UDT. This is beneficial for applications so that you do not have to code for comparison errors.

Once the UDT is defined, column definitions can reference that type during the issuing of the CREATE or ALTER statements the same as they would any DB2 built-in data type. If a distinct type is specified without a schema name, the distinct type is resolved by searching the schemas in the current path.

UDTs allow you to use DB2 built-in data types in special ways. UDTs are built off of the DB2 built-in types. UDTs allow you to extend these types and declare specialized usage on them. DB2 then enforces these rules by performing only the kinds of computations and comparisons that you have defined for the data type.

Defining

In order to use a UDT, you must first create it. The UDTs are created by using one of the DB2 built-in types as a base. You create them using the CREATE DISTINCT TYPE statement, as shown below.

CREATE DISTINCT TYPE distinct-type-name
   AS source-data-type
   WITH COMPARISONS

The name of the distinct type is a two-part name, which must be unique within the DB2 subsystem. The qualifier is a schema name. The distinct type shares a common internal representation with its source data type. However, the distinct type is considered to be an independent data type that is distinct from the others.

An instance of a distinct type can be compared only with another instance of the same distinct type. The WITH COMPARISONS clause is to allow for comparison only between the same distinct type. This phrase is required if the source data type is not a LOB type such as BLOB, CLOB, or DBCLOB. Comparisons for these types are not allowed.

NOTE

LONG VARHCAR and LONG VARGRAPHIC cannot be used as source types.

NOTE

If you specify the WITH COMPARISONS on a distinct type with an LOB source type, you will get a warning message, but the comparisons are still not allowed.

Casting

There are two operations that are allowed on distinct types: comparisons and casting. You can compare the values of distinct types (non-LOB), or you can cast between the distinct type and the source type.

NOTE

Character and arithmetic operators that are used in built-in functions that are used on a source type are not automatically inherited by the distinct type. These operators and functions need to be created explicitly.

Comparison operators such as those listed in Table 15-2 are allowed on UDTs.

Table 15-2. Comparison Operators for UDTs

=

>=

¬>

IN

<>

<=

BEWTEEN

NOT IN

>

¬=

NOT BETWEEN

IS NOT NULL

<

¬<

IS NULL

NOTE

LIKE and NOT LIKE are not supported.

Casting functions are used to convert instances of source data types into instances of a different data types. These functions have the name of the target data type and will have a single parameter, which is the source data type. They will return the target data type. Two cast functions are generated by DB2 when the CREATE DISTINCT TYPE is issued. These are used to convert between the distinct type and its source type. They will be created in the same schema as the distinct type. The following shows an example of creating a UDT and then using it both with and without casting:

CREATE DISTINCT TYPE EURO AS DECIMAL (9,2) WITH COMPARISONS
   EURO(DECIMAL)
   -- where EURO is the target and DECIMAL is the source
   DECIMAL (EURO)
   -- where DECIMAL is the target and EURO is the source

Without casting  using the function name
   SELECT ITEM
   FROM INVENTORY
   WHERE COST > EURO (1000.00)

With casting  using cast function
   SELECT ITEM
   FROM INVENTORY
   WHERE COST > CAST (1000.00 AS EURO)

NOTE

Constants are always considered to be source-type values.

If you want to find all items that have a cost of greater than 1000.00 Euros, you will have to cast, because you cannot compare the data of type EURO with data of the source data type of the EURO which is DECIMAL. You will need to use the cast function to cast data from DECIMAL to EURO. You can also use the cast function DECIMAL to cast from EURO to DECIMAL and cast the column COST to type DECIMAL. Depending on the way you choose to castfrom or to the UDTyou can use the function name notation data-type(argument) or the cast notation CAST(argument AS data-type).

Built-In Functions for UDTs

The built-in data types come with a collection of built-in functions that operate on them. Some of these functions implement operators, such as the arithmetic operators on numeric data types and substring operators on character data types. Other functions include scalar and column functions, which are discussed in Chapter 4, "Advanced SQL Coding."

When you create a UDT, you can also specify that it inherit some or all of the functions that operate on the corresponding source type. The is done by creating new functions called sourced functions that operate on the UDT and duplicate the semantics of the built-in functions that work on the source type. The following example shows how to create a sourced function.

CREATE FUNCTION '+' (EURO, EURO) RETURNS EURO
        SOURCE SYSIBM.'+' (DECIMAL(9,2), DECIMAL(9,2))

You can also give UDTs distinct semantics of their own by creating external functions that you write in a host language, which will operate on your UDTs.

Privileges

You need to have privileges granted in order to use UDTs. The GRANT USAGE ON DISTINCT TYPE is used in order to grant privileges to use the UDT as a column data type in a CREATE or ALTER statement, or to use the UDT as a parameter in a stored procedure or UDF. The GRANT EXECUTE ON enables users to cast functions on a UDT.

Catalog Information

There is information about the UDTs stored in the DB2 catalog. The following tables contain information about UDTs.

  • SYSIBM.SYSDATATYPES: Row for each UDT

  • SYSIBM.SYSROUTINES: Row for each cast function

  • SYSIBM.SYSROUTINEAUTH: Authorizations for EXECUTE privilege

  • SYSIBM.SYSRESTAUTH: Authorizations for USAGE privilege

UDFs

UDFs form the basis of object-relational extensions to the SQL language along with UDTs and LOBs. Fundamentally, a database function is a relationship between a set of input data values and a result value. DB2 Universal Database comes with many built-in functions; however, it is possible to create your own column, scalar, and table functions.

While there are three types of functions in DB2, there are only two UDFs: scalar and table. There is no concept of a column function being user-defined.

NOTE

The built-in column and scalar functions are covered in Chapter 3, "Basic SQL Coding."

In DB2, you can create your own scalar or table functions. A UDF can be written in a high-level programming language such as COBOL, C, C++, or Java, or you can use a single SQL statement. There are three types of UDFs:

  • Sourced: A UDF based on another scalar UDF or on a built-in scalar or column function. This concept is similar to overloading classes in object-oriented programming.

  • SQL Scalar: A scalar UDF that is based upon a single SQL expression. The source code for an SQL UDF is contained entirely within the UDF definition.

  • External: A UDF that you write in a supported language. An external UDF can be further categorized as a scalar or table function.

External UDFs

An external UDF is similar to any other program written for the OS/390 or z/OS platform. External UDFs may or may not contain SQL statements, IFI (Instrumentation Facility Interface), or DB2 commands. They may be written in assembler, COBOL, C, C++, PL/I, or Java. External UDFs, once written and generated as dynamically loadable libraries or classes, must be registered with the database. An external function is defined to DB2 with a reference to an OS/390 load module that DB2 should load when the function is invoked. The OS/390 load module contains the object code for the application program that contains the logic of the external function. If the program contains SQL statements, then there is an associated package that contains the DBRM. External functions cannot be column functions. The congrat function shown below is an external scalar UDF and is registered using the CREATE FUNCTION statement.

CREATE FUNCTION congrat(VARCHAR(30),VARCHAR(40))
   RETURNS VARCHAR(30)
   EXTERNAL NAME 'CONGRAT'
   LANGUAGE C
   PARAMETER STYLE DB2SQL
   DETERMINISTIC
   FENCED
   READS SQL DATA
   COLLID TEST
   NO EXTERNAL ACTION
   DISALLOW PARALLEL;

DB2 passes parameters to external UDFs in a standard manner much in the same way that parameters are passed to stored procedures. DB2 uses the following structure:

Address of Parameter 1

Address of Parameter 2

Address of Parameter 3

…

Address of Result 1

Address of Result 2

Address of Result 3

…

Address of Parameter 1 Null Indicator

Address of Parameter 2 Null Indicator

Address of Parameter 3 Null Indicator

…

Address of Result 1 Null Indicator

Address of Result 2 Null Indicator

Address of Result 3 Null Indicator

…

Address of SQLSTATE

Address of Procedure Name

Address of Specific Name

Address of Message Text

Address of the Scratchpad (if SCRATCHPAD specified in DDL)

Address Call Type Indicator (if FINAL CALL specified in DDL)

Address of DBINFO (if DBINFO specified in DDL)

NOTE

A scalar function can return only a single result parameter, while table functions return multiple result parameters each representing a column in a row of the table being returned.

The SQLSTATE can be returned from the external UDF to DB2 to indicate a condition that DB2 can then act upon. It is highly recommended that the UDF return a SQLSTATE to the caller. The following SQLSTATEs can be returned:

  • 00000 returns SQLCODE 0

  • 01Hxx returns SQLCODE +462

  • 02000 returns SQLCODE +100

  • 38001 returns SQLCODE 487

  • 38002 returns SQLCODE 577

  • 38003 returns SQLCODE 751

  • 38004 returns SQLCODE 579

  • 38yxx returns SQLCODE 443

If the UDF returns a SQLSTATE that is not allowed, DB2 replaces the SQLSTATE with 39001, and returns a SQLCODE of 463.

Sourced UDFs

Sourced UDFs are registered simply by specifying the DB2 built-in source function. Sourced functions can be scalar functions or column functions, but cannot be table functions. Sourced functions are often helpful when there is a need allow for the use of a built-in function on a UDT (see previous section in this chapter for information on UDTs).

This example allows us to create an AVG function for the SCORE data type:

CREATE FUNCTION AVG (SCORE)
   RETURNS SCORE
   SOURCE SYSIBM.AVG(DECIMAL);

These CREATE FUNCTION statements place an entry for each UDF in the SYSIBM.SYSROUTINES catalog table, and the parameters are recorded in SYSIBM.SYSPARMS. These catalog tables can be queried for information about the UDFs.

SQL Scalar UDFs

An SQL scalar function is a UDF in which the entire functionality of the function is a single SQL expression and is coded into the CREATE FUNCTION statement. The function is identified as an SQL scalar function by coding the LANGUAGE SQL option of the CREATE FUNCTION statement. This enables you to code an expression used commonly within more than one statement and modularize that expression by storing it separately as a UDF. Any SQL statement can then reference the UDF in the same manner in which any scalar function can be invoked. This enables common expressions to be coded only once and stored separately in the DB2 catalog, centralizing the coding and administration of these types of functions.

The SQL expression is specified in the RETURN clause of the CREATE FUNCTION statement, and can contain references to the function input parameters as in the following example that computes the total number of months between two dates:

CREATE FUNCTION TOTMON (STARTX DATE, ENDY DATE)
RETURNS INTEGER
LANGUAGE SQL
CONTAINS SQL
NO EXTERNAL ACTION
DETERMINISTIC
RETURN ABS( (YEAR(STARTX - ENDY)*12) + MONTH(STARTX - ENDY) );

The expressions contained in the SQL scalar UDF cannot contain references to columns names or host variables. However, an SQL scalar UDF can invoke other UDFs, which may be external UDFs that can be an SQL program.

The source code for an SQL scalar function is actually stored in the SYSIBM.SYSVIEWS DB2 catalog table. When an SQL statement referencing a SQL scalar function is compiled, the function source from the SYSIBM.SYSVIEWS catalog table is merged into the statement. Package and plan dependencies on the SQL scalar functions, as with all UDFs, are maintained in the SYSIBM.SYSPACKDEP and SYSIBM.SYSPLANDEP tables respectively.

Table Functions

With DB2, you can also create another type of UDF called a table function. A table function is a UDF that returns a table to the SQL statement that calls it. This means that a table function can only be referenced in the FROM clause of a SELECT statement. The table function provides a means of including external data or complex processes in SQL queries. Table functions can read non-DB2 datafor instance, a file on the operating system or over the World Wide Webtabularize it, and return the data to DB2 as a relational table that can subsequently be treated like any other relational table. For example, the APPFORM table function in the next example takes in a candidate application form, processes it, and returns the data in an appropriate format to be inserted in the CANDIDATE table (except for the candidate ID, which is generated):

CREATE FUNCTION APPFORM(VARCHAR(30))
RETURNS TABLE
  (LNAME VARCHAR(30),
   FNAME VARCHAR(30),
   INITIAL CHAR(1),
   HPHONE PHONE,
   WPHONE PHONE,
   STREETNO VARCHAR(8),
   STREETNAME VARCHAR(20),
   CITY VARCHAR(20),
   PROV_STATE VARCHAR(30),
   CODE CHAR(6),
   COUNTRY VARCHAR(20))
EXTERNAL NAME APPFORM
LANGUAGE C
PARAMETER STYLE DB2SQL
NO SQL
DETERMINISTIC
NO EXTERNAL ACTION
FINAL CALL
DISALLOW PARALLEL
CARDINALITY 20;

If we wanted to insert a new candidate into the CANDIDATE table based on his or her application form, we could use the following SELECT statement:

INSERT INTO CANDIDATE
   SELECT CID,
      LNAME, FNAME, INITIAL,
      HPHONE, WPHONE,
      STREETNO, STREETNAME, CITY,
      PROV_STATE, CODE, COUNTRY
   FROM TABLE(APPFORM(' \DOCS\NEWFORM.TXT')) AS AP
Invoking User-Defined Functions

Scalar UDFs are invoked much in the same way as any built-in DB2 scalar function. A function name identifies the function, and one or more parameters pass information from the invoking SQL statement to the UDF. The parameters passed can be table columns, constants, or expressions. If an expression is passed to an external UDF, DB2 resolves the expression and then passes the result to the UDF. The result of the UDF execution replaces the function invocation at execution time. In the following example, the SQL scalar function TOTMON is used to calculate the number of months between two dates:

SELECT  HIREDATE, BIRTHDATE,
        TOTMON(HIREDATE, BIRTHDATE) as total_months,
FROM    DSN8710.EMP;

Here, the HIREDATE and BIRTHDATE columns are selected from the EMP table, and the TOTMON function (previously defined in this chapter) determines the total number of months between the two dates, which were fed to the function as parameters. In this case, the TOTMON function, being an SQL scalar function, is merged with the statement during statement compilation as if the expression itself were coded within the SQL statement.

A UDF can be defined as deterministic or not deterministic. A deterministic function is one that will return the same result from one invocation to the next if the input parameter values have not changed. While there is no mechanism within DB2 to "store" the results of a deterministic function, the designation can impact the invoking query execution path relative to materialization. In a situation in which a table expression has been nested within an SQL statement, a nondeterministic function may force the materialization of the inner query. For example,

SELECT   WORKDEPT, SUM(TOTAL_MONTHS), AVG(TOTAL_MONTHS)
FROM
(SELECT  WORKDEPT,
         TOTMON(HIREDATE, BIRTHDATE) as total_months,
 FROM    DSN8710.EMP) AS TAB1

GROUP BY WORKDEPT;

Here, if there is an index on the WORKDEPT column of the EMP table, then the inner table expression called TAB1 may not be materialized, but rather be merged with the outer select statement. This is possible because the TOTMON function is deterministic. If the TOTMON function was not deterministic, then DB2 would have to materialize the TAB1 table expression, possibly storing it in the DSNDB07 temporary table spaces and sorting to perform the desired aggregation. However, its not exactly clear as to whether or not having TOTMON be deterministic is a good thing. If the TOTMON function is CPU-intensive, it may be better to materialize the result of the inner table expression. This is because the merged TOTMON function (if it is deterministic) will actually be executed twice in the outer query, once per reference (for the SUM and AVG functions in this case).

A table function can be referenced in an SQL statement anywhere that a table can normally be referenced. The table function, or a nested table expression, is identified in the query by the use of the TABLE keyword as in the following example:

SELECT TAB1.EMPNO, TAB2.TEMPURATURE, TAB2.FORECAST
FROM   EMP, TABLE(WEATHERFUNC(CURRENT DATE)) AS TAB2

In the above query, the TABLE keyword was used to identify a nested table expression called TAB2 that was an invocation of the table UDF called WEATHERFUNC. The query returns the employee number along with some weather information in some of the columns that are returned from the WEATHERFUNC table function. This is a fairly simple invocation of a table function.

More importantly, you can embed correlated references within a nested table expression. While the weather may not be useful information to return with employee data, perhaps retrieving the resume and credit information from an external source is. In this case, we can pass the employee number as a correlated reference into the table expression identified by the TABLE keyword and ultimately pass it into the table UDF:

SELECT TAB1.EMPNO, TAB2.RESUME, TAB2.CREDITINFO
FROM   EMP AS TAB1, TABLE(EMPRPT(TAB1.EMPNO)) AS TAB2

The TABLE keyword tells DB2 to look to the left of the keyword when attempting to resolve any otherwise unresolvable correlated references within the table expression. If the join was coded in reverse (that is, the invocation of the EMPRPT table UDF appears in the statement before the EMP table), then the correlated reference to the TAB1.EMPNO column would not have been resolved, and the statement would not have compiled successfully.

The use of the TABLE keyword can be expanded beyond that of correlated references as input into table UDFs. The same keyword can be utilized with a nested table expression that may benefit from a correlated reference. This can be especially useful when the nested expression is performing an aggregation and only needs to work on a subset of the data in the table it is accessing. In the following example, we need to list the employee number and salary of each employee, along with the average salary and head count of all employees in their associated departments. This is traditionally coded as a left outer join of two table expressions, the first getting the employee numbers and salaries, and the second calculating the head count and average salary for all departments. If there is filtering against the employee table, then the entire table might be unnecessarily read to perform the aggregations:

SELECT   TAB1.EMPNO, TAB1.SALARY,
         TAB2.AVGSAL,TAB2.HDCOUNT
FROM
   (SELECT EMPNO, SALARY, WORKDEPT
    FROM   DSN8610.EMP
    WHERE  JOB='SALESREP') AS TAB1
LEFT OUTER JOIN
   (SELECT AVG(SALARY) AS AVGSAL,
           COUNT(*)AS HDCOUNT,
           WORKDEPT
    FROM   DSN8610.EMP
    GROUP  BY WORKDEPT) AS TAB2
ON TAB1.WORKDEPT = TAB2.WORKDEPT;

Here, the entire EMP table has to be read in the TAB2 nested table expression in order to calculate the average salary and headcount for all departments. This is unfortunate, because we only need the departments that employ sales reps. We can use the TABLE keyword and a correlated reference to TAB1 within the TAB2 expression to perform filtering before the aggregation:

SELECT   TAB1.EMPNO, TAB1.SALARY,
         TAB2.AVGSAL,TAB2.HDCOUNT
FROM     DSN8610.EMP TAB1
,TABLE(SELECT AVG(SALARY) AS AVGSAL,
              COUNT(*) AS HDCOUNT
       FROM   DSN8610.EMP
       WHERE  WORKDEPT = TAB1.WORKDEPT) AS TAB2

WHERE TAB1.JOB = 'SALESREP';
Polymorphism and UDFs

DB2 UDFs subscribe to the object-orientated concept of polymorphism. Ad hoc polymorphism (better described as overloading) allows an SQL statement to issue the same function against varying parameter lists and/or data types. This overloading requires us to create a unique definition for each variation of a particular function in data types or number of parameters. Polymorphism basically means "many changes," and for DB2 functions it means that many functions can have the same name. These functions are identified by their signature, which is comprised of the schema name, the function name, the number of parameters, and the data types of the parameters. This enables us to create UDFs for all of our UDTs. These sourced UDFs can assume the same name as the UDFs of built-in functions they are sourced from, but are unique in the system due to the data type of their parameter(s). It also allows us to define SQL or external UDFs to accommodate any variation in data type or number of parameters. For example, if we need a variation of our TOTMON function that accommodates timestamps, we could create the following function:

CREATE FUNCTION TOTMON (STARTX TIMESTAMP, ENDY TIMESTAMP)
RETURNS INTEGER
LANGUAGE SQL
CONTAINS SQL
NO EXTERNAL ACTION
NOT DETERMINISTIC
RETURN ABS( (YEAR(STARTX - ENDY)*12) + MONTH(STARTX - ENDY) );

The only thing that differs between this TOTMON and the original TOTMON is that the input parameters here are TIMESTAMPs instead of DATEs. From the application programming point of view, this enables an SQL statement to issue a TOTMON function regardless of whether it is using a pair of dates or timestamps as input. However, it requires that the people responsible for deploying the UDFs do so with consistency of functionality for like-named functions.

External UDF Execution

The external scalar and table UDF programs execute in an OS/390 WLM environment, much in the same way as stored procedures. The WLM environment is supported by one or more WLM address spaces. The WLM keywords that name the WLM environment in which to execute should be specified when creating the function, or else the program defaults to the WLM environment specified at installation time. This default environment can be seen in the SYSIBM.SYSROUTINES catalog table. UDFs execute under the same thread as the invoking program and will run at the same priority, utilizing the WLM enclave processing.

Monitoring and Controlling UDFs

You can invoke UDFs in a SQL statement wherever you can use expressions or built-in functions. UDFs, like stored procedures, run in WLM-established address spaces. DB2 UDFs are controlled by the following commands.

The START FUNCTION SPECIFIC command activates an external function that has been stopped. You cannot start built-in functions or UDFs that are sourced on another function. You can use the START FUNCTION SPECIFIC command to activate all or a specific set of stopped external functions. To activate an external function that is stopped, you would issue the following command:

START FUNCTION SPECIFIC (function-name)

The SCOPE (GROUP) option can also be used on the START FUNCTION command to allow you to start a UDF on all subsystems in a data sharing group.

The DB2 command DISPLAY FUNCTION SPECIFIC will display statistics about external UDFs that are accessed by DB2 applications. This command will display an output line for each function that a DB2 application has accessed. The information that is returned by this command will reflect a dynamic status for a point in time and may change before another DISPLAY is issued. This command does not display information about built-in functions or UDFs that are sourced on another function. To display statistics about an external UDF accessed by DB2 applications, issue the following command:

- DISPLAY FUNCTION SPECIFIC (function-name)
Stopping UDFs

The DB2 command STOP FUNCTION SPECIFIC will prevent DB2 from accepting SQL statements with invocations of the specified functions. This particular command will not prevent SQL statements with invocations of the functions from running if they have already been queued or scheduled by DB2. Built-in functions or UDF that are sourced on another function cannot be explicitly stopped. While the STOP FUNCTION SPECIFIC command is in effect, any attempt to execute the stopped functions are queued. You can use the STOP FUNCTION SPECIFIC command to stop access to all or a specific set of external functions.

This command stops an external function. Built-in functions or UDFs that are sourced on another function cannot be stopped. Use the START FUNCTION SPECIFIC command to activate all or a specific set of stopped external functions.

To prevent DB2 from accepting SQL statements with invocations of the specified functions, issue the following statement:

STOP FUNCTION SPECIFIC (function-name)
UDF Statistics

The optimizer will use statistics, if available, for estimating the costs for access paths where UDFs are used. The statistics that the optimizer needs can be updated by using the SYSSTAT.FUNCTIONS catalog view. There is a field in the statistics report that allows you to view the maximum level of indirect SQL cascading. This includes cascading due to triggers, UDFs, or stored procedures (see Figure 15-4).

Figure 15-4. Accounting Report Information for UDF Operations

Cost Information

User-defined table functions will add additional access cost to the execution of an SQL statement. In order for DB2 to determine the cost factor for the use of user-defined table functions in the selection of the best access path for an SQL statement, the total cost of the user-defined table function must be determined. This is determined by three components:

  • Initialization cost that results from the first call processing.

  • Cost that is associated with acquiring a single row.

  • Final call cost that performs the cleanup processing.

To determine the elapsed and CPU time spent for UDF operations, you can view an accounting report (see Figure 15-4).

Catalog Information

The SYSIBM.SYSROUTINES catalog table describes UDFs. To retrieve information about UDFs, you can use the following query:

SELECT SCHEME, NAME, FUNCTION_TYPE, PARM_COUNT
FROM SYSIBM.SYSROUTINES
WHERE ROUTINETYPE='F'

Large Objects

As of v6, DB2 allows us to store large objects. It has new datatypes to handle these objects, and there are several application processing issues associated with handling these new types of data.

LOB Datatypes

Three DB2 data types support LOBs:

  • BLOB data type (binary large object)

    - Binary strings (not associated to a CCSID)

    - Good for storing image, voice, and sound data

  • CLOB datatype (character large object)

    - Strings made of single-byte characters or single-/double-byte characters with an associated CCSID

    - Use if data is larger than VARCHAR allows

  • DBCLOB datatype (double-byte character large object)

    - Strings made of double-byte characters with an associated CCSID

Each of these can contain up to 2 gigabytes of data, although in most cases the amount of storage for individual columns will be considerably less (depending on the type of data stored). There is a large use today of the 32KB long VARCHAR column, which has limitations in both size and functionality. Most of this use will probably be replaced by using LOBs in the future, certainly for new applications and functions.

LOB Implementation

LOBs are implemented with structures that are different than normal tables and tablespaces. A LOB tablespace must be created for each column (or each column of each partition) of a base LOB table. This tablespace contains the auxiliary table, which must have an auxiliary index associated with it. The LOB tablespace has a different recovery scheme, optional logging, and different locking options. For information on LOB locking, refer to Chapter 16, "Locking and Concurrency."

If a table contains a LOB column and the plan or package is bound with SQLRULES(STD), then DB2 will implicitly create the LOB tablespace, the auxiliary table, and the auxiliary index. DB2 will choose the name and characteristics for these implicitly created objects.

NOTE

It is better to develop naming standards beforehand for these objects and control placement of them. This is critical for management and performance.

INSERTing and LOADing LOBs

LOB loading and insertion is also different than processes for non-LOB data. The methods are also entirely different depending on whether or not extenders are used. Without extenders, there are some real limitations that need to be addressed when inserting LOB data, primarily the 32KB limit and logging impacts. If the total length of the LOB column and the base table row is less than 32KB, then the LOAD utility can insert the LOB column. When the limits of LOAD are exceeded, then SQL INSERT or UPDATE statements need to be used. But the SQL INSERT has its own limitations in that enough memory needs to be available to hold the entire value of the LOB. The limitations are the amount of memory available to the application and the amount of memory that can be addressed by the language used. If the LOBs are all small, then it is not as much of an issue, as memory and language constructs would be available. But when dealing the very large LOBs, the differences can be seen easily when comparing the C language construct with COBOL.

C language for a LOB host variable,

SQL TYPE IS CLOB(20000K) my_clob;

is generated by DB2 as

struct { unsigned long length;
         Char data[20960000];
       } my_clob;

COBOL language for a LOB host variable,

01 MY-CLOB     USAGE IS SQL TYPE IS CLOB(20000K).

is generated by DB2 as

01  MY-CLOB.
    02  MY-CLOB-LENGTH    PIC 9(9) COMP.
    02 MY-CLOB-DATA.
       49  FILLER     PIC  X(32767).
       49  FILLER     PIC  X(32767).
       49  FILLER     PIC  X(32767).
--Repeated 622 times

This is another area where extenders assist in solving the problem. When a table and column are enabled for an extender, the whole process changes. An INSERT statement can be used in the program to contain extender functions (UDFs) that allow the image to be loaded into the database directly from an external file. Actually with the image extender, for example, the image content is inserted into an administrative support table, and another record is then inserted into another administrative table describing the attributes of the image, such as number of colors, thumbnail-sized version, format characteristics (JPEG, TIF, etc.). The extenders require WLM to be installed in support of the extender UDFs and stored procedures, and specifically using WLM in goal mode for performance reasons.

Even though the LOB data is stored in an auxiliary table, the insert statement specifies the base table. You can read the LOB data from a file in your DB2 program and place the data into the declared DB2 LOB variable. The insert statement then simply references the LOB variable. For example, if you wanted to insert employee resumes into the EMP_RESUME table, which includes a 2MB CLOB data type to hold resumes, you declare the resume variable in your program:

SQL TYPE IS CLOB(2000K) resume;

Then you populate the resume variable with the CLOB data and perform the insert:

EXEC SQL INSERT INTO EMP_RESUME VALUES (:EMPNO, :RESUME);

DB2 uses contiguous storage in data spaces to store LOBs that your program is manipulating. Because LOBs can be quite large, DB2 avoids materializing LOBs until completely necessary. The amount of storage required depends on the size of the LOBs and the number of LOBs referenced within a statement. The amount of storage required by your program and DB2 can become quite large. For this reason, you can use LOB locators to manipulate LOB data without retrieving that data from the DB2 table. A LOB locator is declared in the application program:

SQL TYPE IS CLOB_LOCATOR resume_loc;

An SQL statement can reference the locator, and the LOB is not materialized in DB2 until absolutely necessary, and it is never moved into the application memory:

SELECT RESUME
INTO   :resume_loc
FROM   EMP_RESUME
WHERE  EMPNO=:empno;

Further SQL statements can reference the locator variable, allowing the LOB to be manipulated in various ways. One way would be by using SQL SET commands. DB2 will manipulate the LOB data within the table, and only materialize the LOB as needed.

LOBs and UDTs

Being able to store LOBs and manipulate them through extenders is only part of the story. The capability also exists to define new distinct data types based on the needs of particular applications. A UDT, also known as a distinct type, provides a way to differentiate one LOB from another LOB, even of the same base type, such as BLOB or CLOB. A UDT is not limited to objects and can be created for standard data types as well as LOBs.

Even though stored as LOBs (binary or character), image, video, spatial, XML, and audio objects are treated as types distinct from BLOBs and CLOBs and distinct from each other. For example, suppose an application that processes spatial data features needs a polygon data type. You can create a distinct type named polygon for polygon objects, as follows:

CREATE DISTINCT TYPE polygon AS BLOB (512K)

The polygon-type object is treated as a distinct type of object even though internally it is represented as a 512-KB binary object (BLOB). UDTs are used like SQL built-in types to describe the data stored in columns of tables.The extenders create distinct datatypes for the type of object they process, such as image, audio, and video, which makes it easier for applications to incorporate these types of objects.

CREATE TABLE DB2_MAG_DEMO
 (GEO_ID CHAR(6),
  EURO_ANNUAL    EURO_DOLLAR,
  OZ_ANNUAL      AUSTRALIAN_DOLLAR,
  US_ANNUAL      US_DOLLAR,
  DEMO_GRAPHIC   POLYGON)

Casting functions allow operations between different data typesfor example, comparing a slide from a video UDT to an expression. You must cast the expression to a UDT (video in this example) in order for the comparison to work. There are casting functions supplied with DB2 (CHAR, INTEGER, and so on), and there are others created automatically whenever a UDT is created with the CREATE DISTINCT TYPE statement.


132 - Extenders

Chapter 15. Object-Relational Programming

Extenders

Extenders for DB2 help in the use of LOBs, the base storage for the object-relational environment. Extenders are a complete package that defines distinct data types and special functions for many types of LOBs, including image, audio, video, text, XML, and spatial objects. This allows us not to worry over defining these data types and functions in applications. You can use SQL to manipulate these data types and functions. LOBs can be from relatively small to extremely large, and can be cumbersome to deal with.


133 - LOB and Extender Usage

Chapter 15. Object-Relational Programming

LOB and Extender Usage

When using an extender for a particular LOB type, there are additional options that actually allow the data to be stored in its native format in separate files, such as a picture that is a single JPEG file. In this example, the hierarchical path name would be stored in support tables that would allow the extender to use this indirect reference to process the actual data. The extenders also require administrative support tables that vary based on the extender used. These tables are also referred to as metadata tables, as their content enables the extenders to appropriately handle user requests, such as inserting audio, displaying images, and so on. These tables identify base tables and columns that are enabled for the extender and reference other support tables used to hold attribute information about LOB columns. Triggers supplied by the extenders are used to update many of these support tables when underlying LOB data is inserted, updated, or deleted. At the present time, there are six extenders available in the DB2 family: image, audio, video, text, XML, and spatial. Many others are planned, and vendors also supply extender packages.

Applications generally use SQL to retrieve pointers to the data, and UDFs are used to assist with more complex and unique operations. Extender APIs will be more commonly used as all the coding is supplied for dealing with the LOBs. The extender for image data comes with 18 UDFs; audio has 27 UDFs, video has 18 UDFs, and the QBIC (Query By Image Content) API has 24 UDFs. For applications, that is a considerable advantage both from a "not-having-to-program-it" standpoint and easing the pain of the learning curve. For example, when dealing with the image extenders, there are several different formats supported. The common ones (BMP, EPS, GIF, JPG, TIF) are provided, of course, along with over 15 other formats. This means that if I were browsing through a series of pictures, each LOB picture could be of a different format, but the program would not have to be aware of this because it would be taken care of by the extender. The same is true of the text extender. A user could browse through a series of text documents, one in Microsoft Word format, another in Word Perfect, and so on. But it is not browsing documents, playing a video, and streaming audio that represent the most power. It is the searching ability of the LOB extenders. For example, with the text extender, searching can be done by soundex, synonym, thesaurus, proximity, linguistic, and several other criteria. With images, the QBIC API is supplied to allow searching by image content, and this is a very extensive and powerful API.

Application programming for objects will generally require the use of the extenders. Without their use, there is basically little that can be done without extensive user programming. The power of objects comes with the UDFs and API libraries that are packaged with the extenders. They allow an application to easily store, access, and manipulate any of the supported object types. Although the current list supplied is only the six extenders previously mentioned, many others are in development and will be released in the future as they are completed. The application programmer will be able to use UDFs in the SQL to position to the necessary LOB and then use an API to manipulate it, such as to display a picture on the screen. So, there are really two completely different libraries to strategize from. As a simple example, without forcing it to match any particular programming language, the following represents first storing a picture in a LOB and then displaying it on the screen. First, insert the data into the LOB by using the DB2IMAGE extender:

EXEC SQL BEGIN DECLARE SECTION;
    storage_type;
EXEC SQL END DECLARE SECTION;
SET storage_type = MMDB_STORAGE_TYPE_INTERNAL

EXEC SQL INSERT INTO MY_PERSONAL_DIGITAL_PICTURES
    VALUES ('OZ TRIP 2',
        'Sydney Opera House',
        DB2IMAGE (
            CURRENT SERVER,
            'c:/My Pictures/1999/Australia/OpraHse.jpg',
            'ASIS',
            :storage_type));

Second, retrieve and display the data on the screen using API DBiBROWSE:

EXEC SQL BEGIN DECLARE SECTION;
    image_handler;
EXEC SQL END DECALRE SECTION;

EXEC SQL SELECT PICTURE INTO :image_handler
    WHERE NAME = 'Sydney Opera House';
Set return_code to DBiBROWSE("ib %s,
    MMDB_PLAY_HANDLE,
    image_handler,
    MMDB_PLAY_BI_WAIT);

From the pseudocode, it is easy to see that the extenders offer significant power and enable applications to be written quickly. In addition, most of the work is going on at the server, and the client is simply the recipient of all that power. When implementing extenders, keep in mind that the program will need to have enough memory available to support the use of LOBs on GUI clients.


134 - Enabling Extenders

Chapter 15. Object-Relational Programming

Enabling Extenders

A Software Developers Kit (SDK) and a client and server runtime environment are provided with the DB2 extenders installation package. DB2 extender applications can be executed in a server machine that has the extender client runtime code (automatically installed when the server runtime code is installed) and server runtime code. Extender applications can also be run on a client machine with the client runtime code, and you must ensure that a connection can be made to the server.

Extenders are available in DB2 Version 6 client/server environment. OS/390 is the supported server, and clients can be Windows NT, Windows 98, Solaris, AIX, or OS/390.

When storing image, audio, video, or text objects, you do not store the object in the user table but instead use an extender-created character string referred to as a handle that represents the objects, and the handle will be stored in the user table. The object is actually stored in an administrative support table (or file identifier if the content is a file). The attributes and handles are also stored in these administrative tables. The extender then links the handle in the user table to the object and its attributes in the administrative tables.

Text Extenders

Text extenders bring full-text retrieval to SQL queries for searching large text documents intelligently. With the use of text extenders, you can search several thousand large text documents very quickly. You can also search based upon word variations and synonyms. These documents can be stored directly in the database or in a separate file.

Files such as native word-processing documents can be search by keywords, wildcards, phrases, and proximity. IBM has built into these text extenders a high-performance linguistic search technology, giving you multiple options for searching and retrieving documents. These text searches can be integrated with your normal SQL queries. This enables you to integrate into your SELECT statements the ability to perform attribute and full-text searches very easily.

The following example shows how to perform this integration. In this example, we perform a SELECT from a table that also performs a search on a specified document using a text extender called DB2TX.CONTAINS. We are searching the legal cases document to see if the words "malpractice" and "won" appear in the same paragraph for cases occurring after 1990-01-01. LEGCSE_HANDLE refers to the column LEGCSE that contains the text document.

SELECT DOC_NUM, DOC_DATE
FROM LEGAL_CLAIMS
WHERE DOC_DATE > '1990-01-01'
AND DB2TX.CONTAINS
    (LEGCSE_HANDLE,
    "malpractice"
    IN SAME PARAGRAPH AS "won") = 1

Text extenders allow applications to

  • Search documents of several languages and formats.

  • Perform wildcard searches using masks.

  • Perform a search for words that sound like the search input.

  • Perform fuzzy searches for like words (various spellings).

  • Perform searches for specific text, synonyms, phrases, and proximity.

  • Perform free-text searches where the input is a natural language.

Indexing Text Extenders

Scans are just as undesirable in text documents as they are with our DB2 tables. We need to create indexes so that sequential scans of documents are not necessary. By using a text index, you can speed up the searches performed on these documents.

A text index contains important words as well as a list of words known as stop words, such as and and the, which will not be in a text index. This list can be modified, but you would only want to do it once at installation time. When a request is made, the index is searched for the important terms to determine which documents contain those specified terms.

To set up a text index, you first record the text documents that need to be indexed in a log table. This process occurs when a DB2 trigger is fired off during an insert, update, or delete of a column of a text document. Then, when the terms are inserted or updated in the text document, they are added to the index. They are also deleted from the index if they are deleted from the text document.

There are four types of text indexes, and the type must be established before you implement columns that will be using text extenders. Not all search options are available by all index types, so you want to make sure the index will suit your criteria for searching. The four types of indexes are as follows:

  • Linguistic: In this type of index linguistic processing is performed during the analysis for the text when creating an index. Before a word is inserted into the index, it is reduced to its base form. Queries also use linguistic processing when searching against this index. This index requires the least amount of space, but searches may be longer than those done against a precise index.

  • Precise: In this index the search terms are exactly as they are in the text document and are case-sensitive. The same processing is used for the query search terms, so they must match exactly. The search can be broadened by using masks. This index provides a more precise search, and the retrieval and indexing is fast, but more space is required for its storage.

  • Dual: Dual indexes are combinations of linguistic and precise indexes. This allows the user to decide which type of search to use. This index requires the most amount of disk space. It is slower for searching and indexing than the linguistic indexes and is not recommended for a large number of text documents.

  • Ngram: The Ngram index is used primarily for indexing DBCS documents; it analyzes text by parsing sets of characters. This index type also supports fuzzy searches.

When creating tables that will support the ability to search text using extenders, you must consider a few design options. You can create one text index for all text columns in the table, or you can have several different text indexesone for each text column. Using separate indexes for each text column offers the most flexibility in terms of support for your searches. It also gives you other options, such as how frequently the index is updated and where it is stored. One common index is easier to maintain, but is less flexible. If your indexes are large, consider storing them on separate disks, especially if you expect to have concurrent access to the indexes.

You can also have multiple indexes on a single text column. You may want to do this if you need the ability to allow different types of searches on a text column. And just like other DB2 indexes, these indexes will need to be reorganized too. If you have a text column that is continually updated, you will need to reorganize it. However, when using these indexes, the text extender automatically reorganizes them in the background. Despite this feature, you still may have to reorganize an index manually every so often, depending on its volatility. This is done with the REORGANIZE INDEX command. Issue the GET INDEX STATUS command to see if an index needs reorganization.

Frequency of Index Updates

When text documents are added, deleted. or changed, their content must be synchronized with the index. This information is automatically stored by triggers in a log table, and the documents will be indexed the next time an index update is executed.

The indexes can be immediately updated via the UPDATE INDEX command, but it is easier to have this performed automatically on a periodic basis. This time-based information is kept in an environment variable called DB2TXUPDATEFREQ, which provides default settings that can be changed during the ENABLE TEXT COLUMN or ENABLE TEXT TABLE commands. For an existing index, you can use the CHANGE INDEX SETTINGS command to change the variable settings.

The variable for determining when indexing should occur is based on the minimum number of queued text documents in the log table, and when this minimum is reached, the index is updated. Because updating indexes is a very resource-intensive and time-consuming task, this frequency should be set carefully.

Catalog View for Text Extenders

There is a catalog view created for each subsystem when you run the ENABLE SERVER. This view is DB2TX.TEXTINDEXES. It has information about the tables and the columns that have been enabled for the text extender. The entries are made during table, column, or external file enablement. If they are disabled, the row is removed. You can view the entries in the catalog view via SQL. In this view you can see such information as how often the indexes are scheduled for updates, whether or not you have a multiple-index table, and the type of index.

Image, Audio, and Video Extenders

The DB2 video extender can store as many as three representative frames per shot. By displaying the frames, you get a quick yet effective view of a video's content. The DB2 video extender provides sample programs that demonstrate how to build and display a video storyboard.

Video storyboards allow you to preview videos before you download and view them. This can save you time and reduce video traffic on the network. When image data is placed into a table using the DB2IMAGE UDFs, many processes are performed for the application automatically. The following code demonstrates using this function.

EXEC SQL INSERT INTO CONSULTANTS VALUES(
    :cons_id,
    :cons_name,
    DB2IMAGE(
        CURRENT SERVER,
        '/RYC/images/current.bmp'
        'ASIS',
        MMDB_STORAGE_TYPE_INTERNAL,
        :cons_picture_tag);

In this particular example, the DB2IMAGE reads all the attributes about the image (height, width, colors, layers, pixels, and more) from the source image file header, in this case the current.bmp. All the input is of a standard supported format, and all graphic files contain header information about the structure of the content. The function then creates a unique handle for the image and records all the information in the support table for administrative control of the image. This table contains

  • The handle for the image

  • A timestamp

  • The image size in bytes

  • The comment contained in :cons_picture_tag

  • The content of the image

The content of the image source file is inserted into the LOB table as a BLOB. There is no conversion done, and the image is stored in its native format. There is a record in the administrative table that contains all the image-specific attributes, such as the number of colors in the image, as well as a thumbnail-sized version of the image.

This example uses the storage type constants. We used MMDB_STORAGE_TYPE_INTERNAL to store the image into a database table as a BLOB. By using the extenders, we could have stored it elsewhere. If you want to store the object and have its content remain in the original file on the server, you can specify the constant MMDB_STORAGE_TYPE_EXTERNAL. Just because you are using LOBs does not mean that they have to be in DB2-managed tables. The administrative support table for image extenders tells where the LOB is actually stored. This does require Open Edition support services on the OS/390. From a performance perspective, there are many considerations as to where the LOB is stored, how it is used, where it is materialized, and so on.

XML Extenders

XML has been added to the list of available extenders. For the next generation B2B e-commerce solutions, XML is the standard for data interchange. With the XML extender for DB2, you will be able to leverage your critical business information in DB2 databases in order to engage in B2B solutions using XML-based interchange formats.

In terms of Web publishing, you can use XML documents stored in DB2 in a single column or as a collection of data items in multiple columns and tables. The text extender in DB2 supports structured documents like XML. The powerful search functions provided can now be applied to a section or a list of sections within a set of XML documents. This can significantly improve the effectiveness of the search. Additionally, specific XML elements or attributes can be automatically extracted into traditional SQL data types to leverage DB2's sophisticated indexing and SQL query capabilities. The DB2 XML extender also supplies a visual administration tool for easy definitions for mapping elements and attributes from an XML document into columns and tables.


135 - Summary

Chapter 15. Object-Relational Programming

Summary

In this chapter we talked about very powerful DB2 and SQL features, such as UDFs and triggers. These features can reduce the amount of application development time and maintenance. We can use these features to encapsulate our code into one place for use by many applications.

DB2 has implemented some object-relational functions, such LOB support, UDTs, and UDFs. These features also allow us great flexibility and power in our applications. LOBs, of course, give us the ability to store large amounts and different types of data, such as multimedia, giving us the ability to develop very sophisticated applications.


136 - Additional Resources

Chapter 15. Object-Relational Programming

Additional Resources

IBM DB2 V7 for OS/390 Image, Audio, and Video Extenders Administration and Programming SES1-2199-0

IBM DB2 V7 for OS/390 XML Extender Administration and Programming SES1-2201-00

IBM DB2 V7 for OS/390 Text Extender Administration and Programming SES1-2200-00


137 - Chapter 16. Locking and Concurrency

Part 5. Advanced Programming Functions

Chapter 16. Locking and Concurrency

  • Locking Data

  • Lock Attributes

  • Avoiding Locks

  • Claims and Drains

  • Escalation and Promotion

It would be easy to have one process simply lock all the data while using it, but that of course would lead to other applications being unable to access the data during this time. Concurrency, the ability for multiple applications to access the same data at the same time, needs to be allowed but also controlled so that we prevent lost updates, access to uncommitted data, and unrepeatable reads (data changing between reads).

A balance must be achieved for maximum concurrency of all processes. There are many controls in DB2 to allow us to achieve maximum concurrency while maintaining the integrity of our data. These range from the parameters we bind our programs with to options of the DDL for the creation of objects, to subsystem level parameters.

DB2 uses locks to control concurrency within a database, that is, to manage simultaneous access to a resource by more than one user (also referred to as serialization). Locks also prevent access to uncommitted data, which prevents updates from becoming lost (part of data integrity) and allows a user to see the same data, without the data ever changing, within a period of processing called a commit scope. From a performance standpoint, everything done in DB2 has a tradeoff. In locking, there is a tradeoff between concurrency and performance, as more concurrency comes at a higher cost of CPU usage due to lock management. There are also cases where DB2 will override the locking strategy designed, because processes hold locked resources exceeding the site established thresholds. However, only certain combinations of parameters cause this to occur.


138 - Locking Data

Chapter 16. Locking and Concurrency

Locking Data

DB2 uses transaction locking (via the IRLMInternal Resource Lock Manager), latches, and other non-IRLM mechanisms to control concurrency and access of SQL statements and utilities. These mechanisms are there to associate a resource with a process so that other processes cannot access the same resource when it would cause lost updates and access to uncommitted data. Generally, a process will hold a lock on manipulated data until it has completed its work. This way it ensures that other processes do not get hold of data that has been changed but not committed. Another use is for repeatable read, when an application has the need to reread data that must still be in the same state as it was when it was initially read. There are also user options to avoid locking and allow for access to uncommitted data, and system settings and mechanisms to provide for lock avoidance when it would not cause a data integrity problem.

Not all objects need to have locks acquired on them to establish concurrency. The following objects can be locked:

  • User tables

  • Catalog tables

  • Directory tables

Indexes are not locked, as serialization is controlled by latches, and concurrency is controlled by data locking. There are also drains and claims used to control utilities and DB2 commands. Draining allows utilities and commands to acquire partial or full control of a needed object with minimal interruption to concurrent access.

DB2 often needs to access data in the catalog, and the data being read or updated must be locked. The following locks can be used:

  • During binding

    - SKCT (Skeleton Cursor Table for a plan)

    - SKPT (Skeleton Package Table for a package)

  • During DDL activity

    - DBD (Database Descriptor)

Lock Attributes

Locks should be viewed as having

  • Size: How much data is locked.

  • Mode: Whether or not others are allowed to read and/or update the locked object.

  • Duration: How long the lock is held.

Each plays a role in the acquisition and release of a lock, and understanding these attributes can help us use them wisely and avoid contention.

More than one type of lock can exist for a specific user for a particular tablespace. This depends on the mode of the lock. For example, locks might be held on the tablespace, table, page, and row simultaneously for a particular user. Each lock has its own mode.

Lock Sizes

Locks can be taken on various objects in DB2. The size of the lock determines how much of the total object will be locked. There are several objects that can be locked in DB2, determining the lock size:

  • Non-LOB data:

    - Tablespace Lock the entire tablespace.

    - Table Only segmented tablespaces allow for an individual table to be locked.

    - Partition Lock only a partition.

    - Page Lock an individual page in a table.

    - Row Lock an individual row in a table.

  • LOB data

    - LOB locks.

Tablespace locks are the most encompassing lock, and of course this allows for the least amount of concurrency. It would seem that for maximum concurrency, we should use row locking; however, locks are overhead and row-level locks can cause excessive overhead in terms of processing time and storage. Page locking is generally the acceptable lock level for the majority of situations. There are always exceptions, however, such as table locking (discussed later).

NOTE

It is important to understand that in the hierarchy of locks, row locks and page locks occur at the same level. If either a page lock or a row lock is escalated, it moves to the same higher level, and a row lock can never escalate to a page lock.

LOCK TABLE Statement

There are some situations that may call for the ability to exclusively lock a table or partition. There is a single SQL statement that can override locking at any time: the LOCK TABLE IN EXCLUSIVE MODE statement. A typical reason to override locking is if you want to take a snapshot of data and be able to access a table without any other concurrent processes changing data. You can allow other processes read-only access to the table by using the LOCK TABLE IN SHARE MODE statement. This is different from the repeatable read (RR) isolation, because RR prevents changes only from rows or pages that you have already accessed. You can prevent all other access with LOCK TABLE IN EXCLUSIVE MODE.

The LOCK TABLE/TABLESPACE statement can be used only to get a lock, in either share (S) mode or exclusive (X) mode. The lock is acquired when the SQL statement is executed. Its release is dependent upon the previous settings of the ACQUIRE and RELEASE parameters. The table or tablespace lock is released at thread deallocation if RELEASE(DEALLOCATE) was specified in the options when the program was bound. The lock also can be released at either COMMIT or ROLLBACK time if the RELEASE(COMMIT) option was specified at bind time. Despite the type of locking held when the SQL LOCK TABLE statement was issued, when the COMMIT or ROLLBACK is issued, the system falls back to page-level locking unless another SQL LOCK TABLE statement is issued. A user or application must constantly reissue the SQL LOCK TABLE statement after the COMMIT or ROLLBACK when RELEASE(COMMIT) has been specified if locking is still needed at the table or tablespace level.

The LOCK TABLE IN EXCLUSIVE MODE statement can also be used to avoid additional overhead if you are updating a large portion of a table. This can be more efficient, because by preventing concurrent accesses to the data, DB2 avoids the overhead to lock and unlock each page during updates.

Timeouts can also be prevented by using either the LOCK TABLE IN EXCLUSIVE or IN SHARE MODE statement. This allows you to process the data quickly without the possibility of having to contend for locks with other applications.

If further granularity is needed, you can choose to lock only the partition, as seen in the following example:

LOCK TABLE CERTTB PART 1 IN EXCLUSIVE MODE

This example would take an X lock on Part 1 regardless of any other locks held on other partitions in the tablespace.

NOTE

The PART keyword can be used only on tablespaces defined with LOCKPART(YES).

Selective Partition Locking

By using LOCKPART(YES) for a partitioned tablespace, only the individual partitions are locked when they are accessed. This is known as selective partition locking (SPL). It also provides the ability to tell DB2 not to escalate locks to the tablespace level, but rather to the partition level. This allows for less propagation of locks to the coupling facility in a data sharing environment and better concurrency for applications accessing data in various partitions. This can be especially useful if usage against the partitions is spread over multiple members using affinity routing.

However, SLP will help in a nondata sharing environment only if an agent actually escalates. If you are not having escalation problems, then you may want to consider not using SPL. Without SPL, the parent intent lock is taken on the last partition, regardless of which ones you access. These locks are almost always intent locks and therefore almost never cause a problem. With SPL, the parent intent lock is taken on whichever partition you access. If escalation occurs, with SPL it occurs just for the partition (or partitions) on which excessive locks occurred. Since, without SPL, the parent lock is only on the last one, we escalate the lock size to the entire page set and access to all partitions is denied.

LOB Locking

There is a new lock mode for LOBs called a LOB lock. LOB locks have different characteristics from regular locks. There is no concept of row or page locking with a LOB. LOB locking is not at all like the traditional transaction-level locking. Since LOBs are in an associated object, concurrency between the base table and the LOB must be maintained at all times, even if the base table is using UR (uncommitted read). A LOB lock still needs to be held on the LOB to provide consistency and most importantly to maintain space in the LOB tablespace. LOB locks avoid conflicts between readers and deletes and updates. A SELECT or DELETE will acquire a share-mode LOB lock. The lock doesn't prevent the DELETE, but it will prevent the reuse of the deallocated pages until all of the LOB locks are released. A shadow copy of the LOB will exist until the LOB locks are released. INSERTs will acquire exclusive LOB locks on new LOBs (an UPDATE is basically a DELETE followed by an INSERT). The LOCK TABLE statement, which acquires a lock on the entire object, can still be used and will not require individual LOB locks.

The ACQUIRE option of BIND has no effect on when the tablespace lock on the LOB tablespace is taken. Locks on LOB tablespaces are acquired when they are needed. The tablespace lock is released according to the value specified on the RELEASE option of BIND with a couple of exceptions: when a cursor is defined WITH HOLD or a LOB locator is held. When a cursor is defined WITH HOLD, LOB locks are held through commit operations. When a LOB value is assigned to a LOB locator, the lock acquired will remain until the application commits. If the application uses HOLD LOCATOR, the locator and the LOB lock must be held and cannot be freed until certain conditions exist. The locks would be held until the first commit operation after a FREE LOCATOR statement is issued or until the thread is deallocated. Using LOB columns generally requires an increase in the number of locks held by a process. As a starting point for preventing unforeseen problems, LOCKMAX should be nonzero on the LOB tablespaces. An even better strategy is to use the gross locks during heavy inserting processes to prevent most of the locking difficulties.

Lock Modes

The following are the lock modes in DB2:

  • IS intent share

  • S share

  • IX intent exclusive

  • U update

  • SIX share with intent exclusive

  • X exclusive

Modes are easy to understand with a simple formula. If the table or tablespace lock has an I in it, which stands for intent, then row or page locks are in use on the individual pages. In all other cases, the table or tablespace lock will be the only lock used. The intent locks act as an indicator to DB2 to identify what is occurring within the table or tablespace. Some locking is beyond the control of the programmer and designer, while other locks can be controlled to a degree. Table 16-1 lists the compatibility of the different lock modes for tablespaces, tables, and partitions. Table 16-2 lists the compatibilities for pages and rows.

Table 16-1. Tablespaces, Tables, and Partitions

Lock Mode

IS

IX

S

U

SIX

X

IS

yes

yes

yes

yes

yes

no

IX

yes

yes

no

no

no

no

S

yes

no

yes

yes

no

no

U

yes

no

yes

no

no

no

SIX

yes

no

no

no

no

no

X

no

no

no

no

no

no

Table 16-2. Pages and Rows

Lock Mode

S

U

X

S

yes

yes

no

U

yes

no

no

X

no

no

no

Table or Tablespace Locks

When using page or row locks, the table or tablespace lock will be

  • IS

    - Lock owner wants to read only (may lock pages/rows)

    - Allow read of lock owner's pages/rows and read/update of all other pages/rows

    1. - The lock owner has share locks on the pages, which allows other users to read and update.

  • IX

    - Lock owner wants to update (may lock pages/rows)

    - Allow read/update of all other pages/rows

    1. - The lock owner can have share, update, or exclusive locks on the pages. Other users can still read and update.

  • SIX

    - Lock owner wants to read (will not lock pages/rows)

    - Lock owner wants to update (may lock pages/rows)

    - Allow read of all other pages/rows

    1. - The lock owner can have share, update, or exclusive locks on the pages. Other users can still read, but no other user can update.

NOTE

SIX is not a common lock. This mode usually occurs when an IX lock already exists and a share has to be acquired.

When not using row or page locks, the table/tablespace lock will be:

  • S

    - Lock owner wants to read only

    - Others are allowed read only

    1. - No one can update.

  • U

    - Lock owner wants to read with possibility of update

    - Others allowed read only

    1. - No other user can update.

  • X

    - Lock owner wants to update

    - Other access not allowed

    1. - User needs exclusive use of the table or tablespace. No other user is allowed.

Page or row locks

Page locks can only be one of three types:

  • S: Restricts other users to read-only use of this page. S or U locks can be acquired by other users. Using SELECT or FETCH without update intent will acquire this lock

  • U: This allows the user to go to the actual update step if required. Other applications can get S locks, but nothing else.

  • X: User has updated the data on the page and no other user can get any page lock on the page

The lock mode is determined by the Data Manipulation Language (DML) statement according to the following:

SELECT... | S
SELECT...FOR UPDATE OF... | U
UPDATE/DELETE/INSERT | X

DB2 does not allow update (UPDATE/INSERT/DELETE) of uncommitted changes by other users. Reading of uncommitted data is allowed only if isolation level of UR is specified in the SQL WITH clause or as a BIND option.

Lock Durations

Table, Partition, and Tablespace Lock Durations

Tablespace and table lock duration is determined by the BIND ACQUIRE and RELEASE parameters.

  • ACQUIRE determines when table, tablespace, or partition locks are taken.

    - ALLOCATE: When the first SQL statement is issued, the maximum required lock is taken on all the objects in the plan or package.

    - USE: When a SQL statement is issued, the required lock is taken on the involved objects.

  • RELEASE determines when table, tablespace, or partition locks are released

    - DEALLOCATE: At the end of the program.

    - COMMIT: At COMMIT.

There is an exception that applies when a cursor has been defined using the WITH HOLD option. The locks needed to maintain position of the cursor are then held until the next commit after the cursor is closed (RELEASE COMMIT) or until the application deallocates it resources (RELEASE DEALLOCATE).

Page or Row Lock Durations

The duration of the lock defines the actual length of time that the lock will be held (the period between acquiring and releasing the lock). We can control how long locks are held through various means, such as commit scopes, program bind parameters, and system parameters. We of course want to maximize concurrency, so we do not want to hold locks longer than necessary (using a large lock for the duration of the process), but we do not want to consume excessive memory and CPU overhead by taking an excessive number of smaller locks (such as taking several row locks over a period of time for the same process).

Isolation levels are set when a program is bound or when used in an individual SQL statement using the WITH ISOLATION clause. The isolation levels directly affect the duration that locks are held. The isolation levels that can be used either at bind time or with an individual SQL statement are

  • UR uncommitted read

  • CS cursor stability

  • RS read stability

  • RR repeatable read

Of these, cursor stability, read stability, and repeatable read have to do with lock durations, where uncommitted read has to do with overriding locks.

Cursor Stability

This level of program isolation holds a lock on the row or page (depending on the lock size defined) only if the cursor is actually positioned on that row or page. The lock will be released when the cursor moves to a new row or page, but the lock will be held until a commit is issued if changes are being made to the data. This option allows for the maximum concurrency for applications that are accessing the same data, but cannot allow uncommitted reads.

Read Stability

This option holds locks on all rows or pages qualified by stage 1 predicates for the application until the commit is issued. Nonqualified rows or pages, even though touched, are not locked, as with the RR option. Uncommitted changes of other applications cannot be read, but if an application issues the same query again, any data changed or inserted by other applications will be read, since RS allows other applications to insert new rows or update rows that could fall within the range of the query. This option is less restrictive but similar in function to repeatable read.

Repeatable Read

This option holds a lock on all rows or pages touched by an application program since the last commit was issued, whether or not all those rows or pages satisfied the query. It holds these locks until the next commit point, which ensures that if the application needs to read the data again, the values will be the same (no other process could update the locked data). This option is the most restrictive in terms of concurrency of applications.

Uncommitted Read

This option tells DB2 not to take any locks and to ignore other locks and allow read access to the locked data. It allows an application to run concurrently with other processes (except mass deletes and utilities that drain all claim classes).

Table 16-3 shows a comparison of the different isolation levels.

Table 16-3. Isolation Level Comparisons

Access by Other Applications

UR

CS

RS

RR

Can the application see uncommitted changes made by other application processes?

yes

no

no

no

Can the application update uncommitted changes made by other application processes?

no

no

no

no

Can the re-execution of a statement be affected by other application processes?

yes

yes

yes

no

Can updated rows be updated by other application processes?

no

no

no

no

Can updated rows be read by other application processes that are running at an isolation level other than UR?

no

no

no

no

Can updated rows be read by other application processes that are running at the UR isolation level?

yes

yes

yes

yes

Can accessed rows be updated by other application processes?

yes

no

no

no

Can accessed rows be read by other application processes?

yes

yes

yes

yes

S Share Lock Duration

Using SELECT or FETCH without update intent will acquire this lock. It is released for plans bound with CS when:

  • A TSO process issues a SQL COMMIT or ROLLBACK.

  • An IMS process issues the next SYNCH or ROLB.

  • A CICS synch point call occurs.

  • A noncursor SQL statement completes without update.

  • The cursor position moves to a new row/page without update.

  • The cursor is closed.

Using the cursor WITH HOLD option will hold the locks over COMMIT or ROLLBACK processes in TSO and CAF. If there is no COMMIT used in the program, the locks will be held until the cursor is closed. It is important to understand that the lock will be held on the previous row/page until DB2 gets the lock on the new one.

U Update Lock Duration

A FETCH on a cursor that specifies FOR UPDATE OF acquires this lock. UPDATE and DELETE statements without a cursor also acquire this lock. UPDATE and DELETE statements cause an implicit SELECT to occur first, matching the conditions in the WHERE clause. During this SELECT, DB2 places a U lock on the page accessed, before completing the UPDATE or DELETE. DB2 releases the lock for plans bound with CS when

  • A TSO process issues an SQL COMMIT or ROLLBACK.

  • An IMS process issues the next SYNCH or ROLB.

  • The next synch point call occurs in CICS.

  • A noncursor SQL statement has completed without update.

  • The cursor position moves to a new page without update.

  • The cursor is closed without an update having occurred.

Using the cursor WITH HOLD option in TSO will hold the lock over COMMIT and ROLLBACK. However, the COMMIT will demote the U lock back to an S lock. If an update is to occur, then the lock will be promoted to an X lock before changing the data page.

X Exclusive Lock Duration

Exclusive locks are released when

  • A TSO process issues a SQL COMMIT or ROLLBACK.

  • An IMS process issues the next SYNCH or ROLB.

  • The next synch point call occurs in CICS.

The lock will be held over COMMIT and ROLLBACK in TSO and CAF when using the cursor WITH HOLD option. However, the COMMIT will demote the X lock back to an S lock.


139 - Avoiding Locks

Chapter 16. Locking and Concurrency

Avoiding Locks

Page and row locking can be avoided at execution time by letting the system use lock avoidance mechanisms. DB2 can test to see if a row or page has committed data on it. If it does, then no lock is required on the data at all. Lock avoidance is only valid for read-only or ambiguous cursors and requires a combination of events and settings to occur. First, the statement must be a read-only or an ambiguous cursor along with the proper isolation level and the appropriate CURRENTDATA setting. The best setting for maximum lock avoidance is using an isolation level of CS, either as a bind parameter or on the individual SQL statement, and CURRENTDATA set to NO as a bind option.

Lock avoidance is normally the default for most use, as it removes a lot of locking overhead. DB2 executes a small instruction set to determine if an IRLM lock is truly needed for read-only cursors or ambiguous cursors.

Page and row locking may also be overridden at bind time or execution time. Locking can be overridden for read-only cursors (not ambiguous cursors) by using the UR isolation level at bind time or on the individual statement level, as shown below:

EXEC SQL SELECT ... WITH ISOLATION UR

An SQL SELECT statement is considered to be read-only when it uses any of the following:

  • JOIN

  • SELECT DISTINCT

  • GROUP BY

  • ORDER BY

  • UNION

  • UNION ALL

  • SELECT of a column function

  • FOR FETCH ONLY (FOR READ ONLY)

  • SELECT FROM nonupdateable catalog table

If the SELECT statement does not incorporate any of the above, it is said to be ambiguous, meaning that DB2 does not know for sure if modifying DML will be issued against the cursor. The CURRENTDATA setting of NO states to DB2 that the ambiguous cursor is read-only. If the statement is targeted by updating SQL, then you will get an error. Table 16-4 shows when locking is avoided or overridden.

Table 16-4. Lock Avoidance Determination

Isolation Level

CURRENTDATA

Cursor Type

Avoid Locks on Returned Data

Avoid Locks on Rejected Data

UR

n/a

read-only

n/a

n/a

CS

yes

read-only

no

yes

updateable

ambiguous

no

read-only

yes

updateable

no

ambiguous

yes

RS

n/a

read-only

no

yes

updateable

ambiguous

RR

n/a

read-only

no

no

updateable

ambiguous

NOTE

If your program is bound with ISOLATION(UR), mass deleters cannot run concurrently with your program.


140 - System Parameters

Chapter 16. Locking and Concurrency

System Parameters

Table 16-5 lists some system parameters (DSNZPARMs) that are used to control aspects of locking.

Table 16-5. System Parameters for Locking

Parameter

Description

RECURHL

The use of the RECURHL = YES DSNZPARM can help with concurrency because it allows DB2 to release the locks that are held by a cursor defined WITH HOLD.

IRLMRWT

This is the number of seconds that a transaction will wait for a lock before a timeout is detected. The IRLM uses this for timeout and deadlock detection. Most shops take the default of 60 seconds, but in some high-performance situations where detection must occur sooner (so the applications are not incurring excessive lock wait times), it is been set lower. If timeouts or deadlocks are hit often, the applications is reviewed and tuned.

XLKUPDLT

This DSNZPARM, new with Version 6, allows you to specify the locking method to use when a searched UPDATE or DELETE is performed. The default is NO, best for concurrency, which says that DB2 will use an S or U lock when scanning qualifying rows and then upgrades to an X lock when a qualifying row is found. The value of YES is useful in a data sharing environment when the searches involve an index, because it takes an X lock on qualifying rows or pages.

NUMLKTS

This represents the maximum number of locks on an object. If you are turning off lock escalation (LOCKMAX 0), you will need to increase this number. If you are using LOCKMAX SYSTEM, then the value here will be the value for SYSTEM.

NUMLKUS

This is the maximum number of page or row locks that a single application can have held concurrently on all tablespaces. This includes data pages, index pages, subpages, and rows. If you specify 0, then there is no limit on the number of locks. You want to be careful with 0, because if you turn off lock escalation and do not commit frequently enough, you could run into storage problems (DB2 uses 250 bytes for each lock).


141 - Claims and Drains

Chapter 16. Locking and Concurrency

Claims and Drains

Claims and drain locks are used to control currency between SQL processes and utilities, with partition independence being a major focus. Utilities and SQL can concurrently access and update different partitions, including different logical partitions of nonpartitioned indexes.

NOTE

A logical partition refers to the set of index entries that point to rows in a particular data partition. Logical partitions exist only in nonpartitioned indexes of partitioned tables. An index entry belongs to one and only one logical partition.

Claims

When an application first accesses an object within a unit of work, it makes a claim on the object. It releases the claim at the next commit point. Unlike a transaction lock, the claim cannot persist past the commit point. To access the object in the next unit of work, the application must make a new claim. Claims can be acquired on:

  • Simple tablespace

  • Segmented tablespace

  • Index space

  • Data partition

  • Index partition

There are three different claim classes: write, repeatable read, and cursor stability; they are described in Table 16-6.

Table 16-6. Claim Classes

Claim Class

Isolation Level

Allows Reading

Allows Updating

Allows Inserting

Allows Deleting

Write

Any

yes

yes

yes

yes

Repeatable read

RR

yes

no

no

no

Cursor stability

CS

yes

no

no

no

Claims are released at COMMIT except for utilities and cursors defined WITH HOLD still positioned on an object. All SQL processes are claimers, but only occasionally is a utility a claimer (e.g., online load resume).

NOTE

There is no limit in DB2 to the number of concurrent claimers.

Drains

Drain locks are used to serialize access to partitions and page sets among utilities, commands, and SQL applications. The drain is initiated at any time, but the actual takeover of an object occurs only when all access to the object has been quiesced. The drain process acquires a lock to prevent subsequent access from occurring until the lock is released.

To drain a resource, a utility or command first acquires a drain lock and then waits until all claimers of a particular class on the resource are released. When all claims on the resource in a claim class are released, the resource is considered drained. A utility trying to take over can time out if a long-running SQL process does not release the claim quick enough.

A utility that needs only read-only access will drain on the write class, which will prevent any new updating claimers. A utility that needs to change data will drain all claim classes.


142 - Locking Issues and Problems

Chapter 16. Locking and Concurrency

Locking Issues and Problems

There are times when too much locking can be a problem, resulting in suspensions, timeouts, or even deadlocks. We will take a look at how these situations can occur.

Timeouts and Deadlocks

While waiting for a lock, a process can exceed an allowable amount of wait time that has been established. A systemwide option determines the maximum time a process can wait before it gets a resource unavailable error. This value is called the RESOURCE TIMEOUT value and is calculated by the following formula:

  1. Divide RESOURCE TIMEOUT by DEADLOCK TIME.

  2. Round the result up to the next largest integer.

  3. Multiply this integer by the DEADLOCK TIME.

  4. Multiply the result by the appropriate factor.

Table 16-7 shows the resource timeout factors.

Table 16-7. Timeout Factors

Component

Factor

Notes

Transaction and queries

x 1

BIND

x 3

IMS BMP

x 4

IMS Fast Path

x 6

Nonmessage processing

Utility

x Utility timeout

Defaults to 6

The result is the timeout value that is always greater than or equal to the RESOURCE TIMEOUT. When the timeout value has been reached, the requesting task is informed of the unavailable resource. There are several conditions that can cause a timeout value to be exceeded by a process, and each returns a different message to a different location.

The deadlock time is determined by another system parameter, DEADLOCK TIME (default 5 seconds). This is the time interval between two successive scans for a deadlock. For every deadlock interval, the IRLM will verify whether there are deadlock situations. In those cases, DB2 will inform the task (usually the one that made the smallest number of changes) that a deadlock has occurred. The other tasks will continue without any problems. The main causes of a timeout are the following:

  • A program holding a lock has not freed it soon enough.

  • A deadlock has occurred between DB2 and a non-DB2 resource.

The main causes for deadlocks are the following:

  • Two hot pages

  • Lock escalation

  • One hot page, promotion from S to X lock, and FOR UPDATE OF missing on the cursor

When a timeout or deadlock has occurred, error codes and messages are sent to the following:

  • To the application program:

    - 911 = "THE CURRENT UNIT OF WORK HAS BEEN ROLLED BACK DUE TO DEADLOCK OR TIMEOUT, REASON [reason-code], TYPE OF RESOURCE [resource-type], AND RESOURCE NAME [resource-name]."

    1. - The reason code indicates whether a timeout or a deadlock has occurred.

    2. - The application is rolled back to the previous commit. On receipt of the 911 return code, the application should terminate or retry.

    - 913 = "UNSUCCESSFUL EXECUTION CAUSED BY DEADLOCK OR TIMEOUT, REASON [reason-code], TYPE OF RESOURCE [resource-type], AND RESOURCE NAME [resource-name]."

    1. - The reason code indicates whether a timeout or a deadlock has occurred.

    2. - The current unit of work has not been rolled back. The application should either commit or roll back. Then the application should terminate or retry.

  • To the console:

    - DSNT376I message

    - DSNT500I message

Coding Retry Logic for Locking Errors

A 911 SQL return code means that a deadlock or a timeout occurred and DB2 has issued a successful ROLLBACK to the last commit point. If the ROLLBACK was not successful, the application will receive a 913 SQL return code signifying that a ROLLBACK was not performed. There is also a 912 SQL return code, which occurs when the maximum number of lock requests has been reached for the database (because insufficient memory was allocated to the lock list). With a 912 or a 913 return code, the application needs to issue a COMMIT or ROLLBACK before proceeding with any other SQL.

When a 911 occurs, the choice of whether or not to use retry logic depends on the individual application. If a large amount of work has been rolled back, and if there are other non-DB2 files present, it may be difficult to reposition everything and retry the unit of work. With most 911 situations, a restart process (vendor-supplied or user-written) is generally easier than a programmatic reposition and retry. If a small amount of work was lost, then a simple retry could be performed up to some fixed number of times. It is important not to retry with a breakpoint, since the source of the problem that caused the negative codes might still exist.

With the 913 SQL return code, the single statement could be retried, and if successful, the program could simply continue on. However, if repeated attempts at retry logic fail, then the application probably needs to be rolled back.

Displaying Locks

You can display the locks that are being held to solve application concurrency problems. By using the -DISPLAY DATABASE (dbname) LOCKS command you can see many properties about a given lock, as shown in Figure 16-1.

Figure 16-1. DISPLAY DATABASE LOCKS.

Lock Promotion and Escalation

In order to best protect data based on the process, DB2 may choose to increase either the mode of the lock or the size of the lock. This is done through lock escalation and promotion.

Lock Escalation

Lock escalation can occur when the value for LOCKMAX is reached. At this time DB2 will release all of the locks held in favor of taking a more comprehensive lock (i.e., release several page or row locks to escalate to a table lock). DB2 tries to balance the number of locks on objects based upon the amount of concurrent access. The LOCKMAX option will then further determine when/if escalation occurs.

NOTE

Lock escalation can occur for objects defined with LOCKSIZE ANY, PAGE, or ROW. ANY just allows DB2 the choice of lock to take initially.

The value of LOCKMAX is set on the CREATE TABLESPACE statement to define how many locks can be held simultaneously on an object. Locks will be escalated when this number is reached. You can specifically set this value to a number, or if you leave it at the default of SYSTEM (if you use LOCKSIZE ANY; otherwise, the default is 0 for specific object locks such as page, row, table, and tablespace), it will use the number set by the NUMLKTS DSNZPARM.

You can turn off lock escalation by using the LOCKMAX = 0 parameter on the CREATE TABLESPACE statement. If you choose to turn off lock escalation, be sure that applications accessing those objects are committing frequently and you have adjusted the DSNZPARM NUMLKTS to allow for more locks to be taken; otherwise, you run the risk of hitting negative SQL codes when you reach the maximum number of locks (without escalation, you could hold more, smaller locks). Lock escalation is there to protect you from taking excessive system resources, so if you turn it off, you will need to control it. If you are CPU-bound, it may not be a good idea to turn off lock escalation because it will take DB2 longer to traverse long chains of locks and it will take more CPU for IRLM latch activity.

Lock Promotion

There is a lock mode that will be used for any table, tablespace, or tablespace partition for an SQL statement, and it is reflected in the PLAN_TABLE populated by EXPLAIN in the column TSLOCKMODE if the isolation can be determined at bind time. This is the lock mode that the SQL statement would use for the table or tablespace lock if and only if it had not been raised by a preceding SQL statement. For example, an SQL SELECT statement might have a TSLOCKMODE of IS, yet during execution, it could have been promoted to IX, and that is what the SELECT statement would use. This is called lock promotion, but it generally is not a concernjust a fact.


143 - Summary

Chapter 16. Locking and Concurrency

Summary

In this chapter, we discussed how concurrency(serialization) is controlled. To protect the data as it is being modified, rules are established and the changes are grouped into units of work. The updated data is made permanent by the COMMIT statement or removed by the ROLLBACK statement. The rules of concurrency are determined by the isolation level, the lock size, and the rules of lock duration.

DB2 implements the isolation level semantics of data access by implicitly acquiring locks on behalf of applications. Applications can decide to lock a resource for exclusive or share modes. The resources that can be locked are the row, page, table, tablespace, and partition.

If a requested lock is more restrictive, and another application already has the resource locked, a wait on the release of the lock will occur. The amount of time an application will wait is determined by systemwide parameters for both resource timeout and deadlocks.

If multiple applications require access to data that is held by other applications, a deadlock scenario can occur. DB2 will detect the occurrence of any deadlocks and force one of the transactions to roll back. Every lock requested requires memory in the IRLM, and the amount of lock storage is configurable using IRLM parameters.


144 - Additional Resources

Chapter 16. Locking and Concurrency

Additional Resources

IBM DB2 UDB for OS/39 Administration Guide SC26-9931


145 - Chapter 17. Application Performance and Optimization

Part 5. Advanced Programming Functions

Chapter 17. Application Performance and Optimization

  • Planning

  • DB2 Architecture Overview

  • Database Monitoring

  • SQL Monitoring and Tuning

  • Optimization

  • Problem Determination

Understanding the performance of the DB2 database management system, its databases, and active applications in a dynamic environment requires monitoring. This means that a database administrator should gather information regarding the usage of the database. An application programmer may also require SQL statement execution information. Gathering database information using DB2's monitoring facilities and information regarding SQL statement processing is discussed.

In this chapter, the various DB2 facilities for monitoring and gathering information that is input into the tuning process is reviewed along with the explain process, trace, commands, and other tools used to monitor DB2 database objects and SQL statements. These tools may be used to perform the following tasks:

  • Understand user and application activity within DB2.

  • Better understand how an SQL statement is processed.

  • Determine the sources and causes of problems.

  • Tune buffer pool and system parameters.

  • Improve database and application performance.


146 - Elements of Performance

Chapter 17. Application Performance and Optimization

Elements of Performance

Performance is the way a computer system behaves given a particular workload. Performance is measured through the system's response time, throughput, and availability. It is affected by

  • The resources available

  • How well the resources are utilized

Performance tuning should be undertaken when you want to improve the cost-benefit ratio of your system. Specific situations include the following:

  • You want to process a larger, more demanding workload without increasing processing costs that may include having to acquire additional hardware.

  • You want to obtain faster system response time or higher throughput without increasing processing costs.

  • You want to reduce processing costs without negatively affecting service to the client(s).

Translating performance from technical terms to economic terms is difficult. Performance tuning costs money through labor and machine resources, so the cost of tuning must be weighed against the benefits tuning may or may not deliver.

Some of these benefits, including less resource usage and the ability to add more users to the system, are tangible, whereas other benefits, such as increased customer satisfaction, are less tangible from a monetary perspective.


155 - Additional Resources

Chapter 17. Application Performance and Optimization

Additional Resources

IBM DB2 UDB for OS/390 Command Reference Guide SC26-9934

IBM DB2 UDB for OS/390 Administration Guide SC26-9931

IBM DB2 PM for OS/390 General Information GC26-9172


147 - Tuning Guidelines

Chapter 17. Application Performance and Optimization

Tuning Guidelines

The following guidelines should be considered in developing an overall approach to performance tuning:

  • Remember the law of diminishing returns: Your greatest performance benefits usually come from your initial efforts. Further changes generally produce smaller and smaller benefits and require greater effort.

  • Do not tune just for the sake of tuning: Tune to relieve identified constraints. If you tune resources that are not the primary cause of performance problems, this can have little or no effect on response time until you have relieved the major constraints, and it can actually make subsequent tuning work more difficult. If there is any significant improvement potential, it lies in improving the performance of the resources that are major factors in the response time.

  • Consider the whole system: You can never tune one parameter or system in isolation. Before you make any adjustments, consider how it will affect the system as a whole.

  • Change one parameter at a time: Do not change more than one performance tuning parameter at a time. Even if you are sure that all the changes will be beneficial, you will have no way of evaluating how much each change has contributed. You also cannot effectively judge the tradeoff you have made by changing more than one parameter at a time. Every time you adjust a parameter to improve one area, you almost always affect at least one other area that may not have been considered.

  • Measure and reconfigure by levels: For the same reasons that you should change only one parameter at a time, tune one level of your system at a time. You can use the following list of levels within a system as a guide:

    - Hardware

    - Operating system

    - Application server and requester

    - Database

    - SQL statements

    - Application programs

  • Check for hardware and software problems: Some performance problems may be corrected by applying service to your hardware, your software, or to both. Do not spend excessive time monitoring and tuning your system when simply applying service may be the solution to the problem.

  • Understand the problem before upgrading hardware: Even if it seems that an additional storage or processor resource could immediately improve performance, take the time to understand where the bottlenecks are. You may spend money on additional disk storage only to find that you do not have the processor resource to exploit it.

  • Put fallback procedures in place before you start tuning: Because changes are being made to an existing system, you must be prepared to back out those changes if they do not have the desired effect or have a negative effect on the system.

Performance Improvement Process

Monitoring and tuning a database and its applications should be performed using the following basic process:

  1. Establish performance indicators.

  2. Define performance objectives.

  3. Develop a performance monitoring plan.

  4. Implement the plan.

  5. Analyze the measurements. Determine if the objectives have been met. If so, consider reducing the number of measurements to keep to a minimum the amount of resources consumed for monitoring.

  6. Determine the major constraints in the system.

  7. Decide where you can afford to make tradeoffs and which resources can bear an additional load. Most tuning activities involve tradeoffs among system resources and various elements of performance.

  8. Adjust the configuration of the system. If you think that it is feasible to change more than one tuning option, implement one at a time.

  9. Based on the results, start another iteration of the monitoring cycle.

You may want to follow the above process for periodic monitoring or when significant changes occur to the system, to the workload taken on by the system, or to both.

How Much Can a System Be Tuned?

There are limits to how much you can improve the efficiency of a system. Consider how much time and money you should spend on improving system performance and how much the spending of additional time and money will help the users of the system.

Your system may perform adequately without any tuning at all, but it probably will not perform to its potential. Each database is unique. As soon as you develop your own database and applications for it, investigate the tuning parameters available and learn how you can customize their settings to reflect your situation. In some circumstances, there will be only a small benefit from tuning a system. In most circumstances, however, the benefit may be significant.

If your system encounters performance bottlenecks, it is likely that tuning will be effective. If you are close to the performance limits, and you increase the number of users on the system by about 10 percent, the response time may rise by much more than 10 percent. In this situation, you will need to determine how to counterbalance this degradation in performance by tuning your system. However, there is a point beyond which tuning cannot help. At that point, you should consider revising your goals and expectations within that environment. Or you should change your system environment by considering more disk storage, faster or additional processors, additional memory, or faster networking solutions.

A Less Formal Approach

If you do not have enough time to set performance objectives and to monitor and tune in a comprehensive manner, you can address performance by listening to your users. Find out if they are having performance-related problems. You can usually locate the problem or determine where to start looking for the problem by asking a few simple questions. For example, you can ask your users

  • What do you mean by slow response? Is it 10 percent slower or 10 times slower than you expect it to be?

  • When did you notice the problem? Is it recent, or has it always been there?

  • Do you know of other users who are complaining of the same problem? Are those complaining one or two individuals or a whole group?

  • Are the problems you are experiencing related to a specific transaction or application program?

  • Do your problems appear during regular periods, such as at lunch hour, or are they continuous?


148 - Access Paths and Optimization

Chapter 17. Application Performance and Optimization

Access Paths and Optimization

If you want to know how a query will be executed by DB2, you must analyze its access path, which is the method for retrieving data from a specific table. The explain facility will provide information about how DB2 accesses the data to resolve the SQL statements.

You should understand at a high level how SQL statements are processed by the DB2 database engine: Each SQL statement is analyzed by DB2, and then it is determined how to process the statement during a static bind or when executed dynamically. The method used to retrieve data from tables is called the access plan.

The component within DB2 that determines the access plan to be used is known as the optimizer. During the static preparation of an SQL statement, the SQL compiler is called on to generate an access plan. The access plan contains the data access strategy, including index usage, sort methods, locking semantics, and join methods.

The executable form of the SQL statement is stored in the system tables when a BIND command is executed. This is called a DBRM (database request module), which can then be bound into a package. For more on packages refer to Chapter 6, "Binding an Application Program."

Sometimes, the complete statement is not known at application development time. In this case, the compiler is invoked during program execution to generate an access plan for the query that can be used by the database manager to access the data. Such a SQL statement is called a dynamic SQL statement. The access plans for a dynamic SQL statement are not stored in the system catalogs. They can be cached in memory in the dynamic SQL cache and will not be re-prepared if the access plans for the dynamic SQL statements already exist in the dynamic SQL cache.

Explain

Explain is a monitoring tool that produces information about the following:

  • A plan, package, or SQL statement when it is bound. The output appears in a table you create, called PLAN_TABLE, which is also called a plan table. For experienced users, you can use PLAN_TABLE to give optimization hints to DB2. We will look at access path hints later in this chapter.

  • An estimated cost of executing an SQL SELECT, INSERT, UPDATE, or DELETE statement. The output appears in a table you create, called DSN_STATEMNT_TABLE, which is also called the statement table.

  • User-defined functions (UDFs) referred to in the statement, including the specific name and schema. The output appears in a table you create, called DSN_FUNCTION_TABLE, which is also called a function table.

We will look at the data contained in these three tables and how to use this data to improve query performance.

Gathering Explain Data

There are two different ways to populate the PLAN_TABLE:

  • Executing the SQL statement EXPLAIN: You can populate PLAN_TABLE by executing the SQL statement EXPLAIN. In the statement, specify a single explainable SQL statement in the FOR clause. You can execute EXPLAIN either statically from an application program or dynamically, using QMF or SPUFI.

  • Binding with the option EXPLAIN(YES): You can populate PLAN_TABLE by executing the SQL statement in a package bound EXPLAIN(YES).

  • Before you can use EXPLAIN, you must create the PLAN_TABLE to hold the results of EXPLAIN. A copy of the statements needed to create the table are in the DB2 sample library under the member name DSNTESC. (Unless you need the information they provide, it is not necessary to create a function table or statement table to use EXPLAIN.)

NOTE

DB2 does not automatically delete rows from the PLAN_TABLE. To clear the table of obsolete rows, use DELETE, just as you would for deleting rows from any table.

NOTE

With every release of DB2, the PLAN_TABLE is subject to change. Be sure to create a new, or alter, the existing table to pick up the new columns.

Examining Explain Data

Explains will populate this table, and from there you must interpret the data and act accordingly. Table 17-1 shows the columns in the PLAN_TABLE.

Table 17-1. PLAN_TABLE

Column Name

Description

QUERYNO

A number intended to identify the statement being explained. For a row produced by an EXPLAIN statement, specify the number in the QUERYNO clause. For a row produced by non-EXPLAIN statements, specify the number using the QUERYNO clause, which is an optional part of the SELECT, INSERT, UPDATE, and DELETE statement syntax. Otherwise, DB2 assigns a number based on the line number of the SQL statement in the source program.

FETCH statements do not each have an individual QUERYNO assigned to them. Instead, DB2 uses the QUERYNO of the DECLARE CURSOR statement for all corresponding FETCH statements for that cursor.

When the values of QUERYNO are based on the statement number in the source program, values greater than 32,767 are reported as 0. Hence, in a very long program, the value is not guaranteed to be unique. If QUERYNO is not unique, the value of TIMESTAMP is unique.

QBLOCKNO

The position of the query in the statement being explained (1 for the outermost query, 2 for the next query, and so forth). For better performance, DB2 might merge a query block into another query block. When that happens, the position number of the merged query block will not be in QBLOCKNO.

APPLNAME

The name of the application plan for the row. Applies only to embedded EXPLAIN statements executed from a plan or to statements explained when binding a plan. Blank if not applicable.

PROGNAME

The name of the program or package containing the statement being explained. For statements explained dynamically, such as QMF or SPUFI, then the associated plan/package is listed. Blank if not applicable.

PLANNO

The number of the step in which the query indicated in QBLOCKNO was processed. This column indicates the order in which the steps were executed.

METHOD

A number (0, 1, 2, 3, or 4) that indicates the join method used for the step:

0 = First table accessed, continuation of previous table accessed, or not used.

1 = Nested loop join. For each row of the present composite table, matching rows of a new table are found and joined.

2 = Merge scan join. The present composite table and the new tables are scanned in the order of the join columns, and matching rows are joined.

3 = Sorts needed by ORDER BY, GROUP BY, SELECT DISTINCT, UNION, a quantified predicate, or an IN predicate. This step does not access a new table.

4 = Hybrid join. The current composite table is scanned in the order of the join-column rows of the new table. The new table is accessed using list prefetch.

CREATOR

The creator of the new table accessed in this step; blank if METHOD is 3.

TNAME

The name of a table, created temporary table, declared temporary table, materialized view, table expression, or an intermediate result table for an outer join that is accessed in this step; blank if METHOD is 3.

Materialized results may show the temporary table name of the work file in the form DSNWFQB(qblockno) or DSN_DIM_TBLX(qblockno) for materialized snowflakes in a star schema query. Merged views show the base table names and correlation names. A materialized view is another query block with its own materialized views, tables, and so forth.

TABNO

Values are for IBM use only.

ACCESSTYPE

The method of accessing the new table:

I = By an index (identified in ACCESSCREATOR and ACCESSNAME)

I1 = By a one-fetch index scan

N = By an index scan when the matching predicate contains the IN keyword

R = By a tablespace scan

M = By a multiple index scan (followed by MX, MI, or MU)

MX = By an index scan on the index named in ACCESSNAME

MI = By an intersection of multiple indexes

MU = By a union of multiple indexes

Blank = Not applicable to the current row

MATCHCOLS

For ACCESSTYPE I, I1, N, or MX, the number of index keys used in an index scan; otherwise, 0.

ACCESSCREATOR

For ACCESSTYPE I, I1, N, or MX, the creator of the index; otherwise, blank.

ACCESSNAME

For ACCESSTYPE I, I1, N, or MX, the name of the index; otherwise, blank.

INDEXONLY

Whether access to an index alone is enough to carry out the step, or whether data too must be accessed. Y = Yes; N = No. For UPDATE/DELETE, this indicates whether an index alone is enough to determine the row(s) to be updated or deleted.

SORTN_UNIQ

Whether the new table is sorted to remove duplicate rows. Y = Yes; N = No.

SORTN_JOIN

Whether the new table is sorted for join method 2 or 4. Y = Yes; N = No.

SORTN_ORDERBY

Whether the new table is sorted for ORDER BY. Y = Yes; N = No.

SORTN_GROUPBY

Whether the new table is sorted for GROUP BY. Y = Yes; N = No.

SORTC_UNIQ

Whether the composite table is sorted to remove duplicate rows. Y = Yes; N = No.

SORTC_JOIN

Whether the composite table is sorted for join method 1, 2, or 4. Y = Yes; N = No.

SORTC_ORDERBY

Whether the composite table is sorted for an ORDER BY clause or a quantified predicate. Y = Yes; N = No.

SORTC_GROUPBY

Whether the composite table is sorted for a GROUP BY clause. Y = Yes; N = No.

TSLOCKMODE

An indication of the mode of lock to be acquired on the new table or its tablespace or tablespace partitions. If the isolation can be determined at bind time, the values are

IS = Intent share lock

IX = Intent exclusive lock

S = Share lock

U = Update lock

X = Exclusive lock

SIX = Share with intent exclusive lock

N = UR isolation; no lock

If the isolation cannot be determined at bind time, then the lock mode determined by the isolation at runtime is shown by the following values.

NS = For UR isolation, no lock; for CS, RS, or RR, an S lock.

NIS = For UR isolation, no lock; for CS, RS, or RR, an IS lock.

NSS = For UR isolation, no lock; for CS or RS, an IS lock; for RR, an S lock.

SS = For UR, CS, or RS isolation, an IS lock; for RR, an S lock.

The data in this column is right justified. For example, IX appears as a blank followed by I followed by X. If the column contains a blank, then no lock is acquired.

TIMESTAMP

Usually, the time at which the row is processed, to the last .01 second. If necessary, DB2 adds .01 second to the value to ensure that rows for two successive queries have different values.

REMARKS

A field into which you can insert any character string of 254 or fewer characters.

PREFETCH

Whether data pages are to be read in advance by prefetch. S = pure sequential prefetch; L = prefetch through a page list; blank = unknown at bind time or no prefetch.

COLUMN_FN_EVAL

When an SQL column function is evaluated. R = while the data is being read from the table or index; S = while performing a sort to satisfy a GROUP BY clause; blank = after data retrieval, after any sorts, or not applicable.

MIXOPSEQ

The sequence number of a step in a multiple index operation.

1, 2, … n = For the steps of the multiple index procedure (ACCESSTYPE is MX, MI, or MU.)

0 = For any other rows (ACCESSTYPE is I, I1, M, N, R, or blank.)

VERSION

The version identifier for the package. Applies only to an embedded EXPLAIN statement executed from a package or to a statement that is explained when binding a package. Blank if not applicable.

COLLID

The collection ID for the package. Applies only to an embedded EXPLAIN statement executed from a package or to a statement that is explained when binding a package. Blank if not applicable.

ACCESS_DEGREE

The number of parallel tasks or operations activated by a query. This value is determined at bind time; the actual number of parallel operations used at execution time could be different. This column contains 0 if there is a host variable.

ACCESS_PGROUP_ID

The identifier of the parallel group for accessing the new table. A parallel group is a set of consecutive operations, executed in parallel, that have the same number of parallel tasks. This value is determined at bind time; it could change at execution time.

JOIN_DEGREE

The number of parallel operations or tasks used in joining the composite table with the new table. This value is determined at bind time and can be 0 if there is a host variable. The actual number of parallel operations or tasks used at execution time could be different.

JOIN_PGROUP_ID

The identifier of the parallel group for joining the composite table with the new table. This value is determined at bind time; it could change at execution time.

SORTC_PGROUP_ID

The parallel group identifier for the parallel sort of the composite table.

SORTN_PGROUP_ID

The parallel group identifier for the parallel sort of the new table.

PARALLELISM_MODE

The kind of parallelism, if any, that is used at bind time:

I = Query I/O parallelism

C = Query CP parallelism

X = Sysplex query parallelism

MERGE_JOIN_COLS

The number of columns that are joined during a merge scan join (Method = 2).

CORRELATION_NAME

The correlation name of a table or view that is specified in the statement. If there is no correlation name, then the column is blank.

PAGE_RANGE

Whether the table qualifies for page range screening, so that plans scan only the partitions that are needed. Y = Yes; blank = No.

JOIN_TYPE

The type of an outer join.

F = FULL OUTER JOIN

L = LEFT OUTER JOIN

S = STAR JOIN

blank = INNER JOIN or no join

RIGHT OUTER JOIN converts to a LEFT OUTER JOIN when you use it, so that JOIN_TYPE contains L.

GROUP_MEMBER

The member name of the DB2 that executed EXPLAIN. The column is blank if the DB2 subsystem was not in a data-sharing environment when EXPLAIN was executed.

IBM_SERVICE_DATA

Values are for IBM use only.

WHEN_OPTIMIZE

When the access path was determined:

blank = At bind time, using a default filter factor for any host variables, parameter markers, or special registers.

B = At bind time, using a default filter factor for any host variables, parameter markers, or special registers; however, the statement is reoptimized at runtime using input variable values for input host variables, parameter markers, or special registers. The bind option REOPT(VARS) must be specified for reoptimization to occur.

R = At runtime, using input variables for any host variables, parameter markers, or special registers. The bind option REOPT(VARS) must be specified for this to occur.

QBLOCK_TYPE

For each query block, the type of SQL operation performed. For the outermost query, it identifies the statement type. Possible values:

SELECT = SELECT

INSERT = INSERT

UPDATE = UPDATE

DELETE = DELETE

SELUPD = SELECT with FOR UPDATE OF

DELCUR = DELETE WHERE CURRENT OF CURSOR

UPDCUR = UPDATE WHERE CURRENT OF CURSOR

CORSUB = Correlated subquery

NCOSUB = Noncorrelated subquery

TABLEX = Table Expression

UNION = UNION

UNIONA = UNION ALL

BIND_TIME

The time at which the plan or package for this statement or query block was bound. For static SQL statements, this is a full-precision timestamp value. For dynamic SQL statements, this is the value contained in the TIMESTAMP column of PLAN_TABLE appended by four zeroes.

OPTHINT

A string that you use to identify this row as an optimization hint for DB2. DB2 uses this row as input when choosing an access path.

HINT_USED

If DB2 used one of your optimization hints, it puts the identifier for that hint (the value in OPTHINT) in this column.

PRIMARY_ACCESSTYPE

Indicates whether direct row access will be attempted first:

D = DB2 will try to use direct row access. If DB2 cannot use direct row access at runtime, it uses the access path described in the ACCESSTYPE column of PLAN_TABLE.

blank = DB2 will not try to use direct row access

PARENT_QBLOCK

Number that indicates the QBLOCKNO of the parent query.

TABLE_TYPE

The type of new table:

F = Table Function

Q = Temporary Intermediate Result table (not materialized). Exception is a materialized snowflake within a star join query.

T = Table

W = Work file

Access Path Evaluation

We now take a look at how to examine some of the most useful data in the PLAN_TABLE and determine what the DB2 optimizer is using to access the data.

Index Access

The following describes the different types of index access and how they represented in the PLAN_TABLE.

Index Access (ACCESSTYPE is I, I1, N or MX). If the column ACCESSTYPE in the plan table has a value I, I1, N, or MX, DB2 uses an index to access the table named in column TNAME. The columns ACCESSCREATOR and ACCESSNAME identify the index.

Multiple Index Access (ACCESSTYPE = M). This value indicates that DB2 uses a set of indexes to access a single table. A set of rows in the plan table contain information about the multiple index access. The rows are numbered in column MIXOPSEQ in the order of execution of steps in the multiple index access. (If you retrieve the rows in order by MIXOPSEQ, the result is similar to postfix arithmetic notation.)

Number of Matching Index (MATCHCOLS = n). If MATCHCOLS is 0, the access method is called a nonmatching index scan. All the index keys and their row identifiers (RIDs) are read. If MATCHCOLS is greater than 0, the access method is called a matching index scan: The query uses predicates that match the index columns.

In general, the matching predicates on the leading index columns are equal or IN predicates. The predicate that matches the final index column can be an equal, IN, or range predicate (<, <=, >, >=, LIKE, or BETWEEN). The following example illustrates matching predicates:

SELECT *
FROM EMP
WHERE JOBCODE = '5'
AND LOCATION ='CA'
AND SALARY > 60000
AND AGE > 21;
INDEX XEMP5 on (JOBCODE,LOCATION,SALARY,AGE);

The index XEMP5 is the chosen access path for this query, with MATCHCOLS = 3. Two equal predicates are on the first two columns, and a range predicate is on the third column. Though the index has four columns in the index, only three of them can be considered matching columns.

NOTE

At most, one IN predicate can be a matching predicate; the exception, however, is a noncorrelated IN subquery. IN-list predicates cannot be matching predicates for MX access or list prefetch.

Index Only Access (INDEXONLY = Y). In this case, the method is called index-only access. For a SELECT operation, all the columns needed for the query can be found in the index, and DB2 does not access the table. For an UPDATE or DELETE operation, only the index is required to read the selected row.

Index-only access is not possible when returning varying-length data in the result set or when a VARCHAR column has a LIKE predicate, unless the VARCHAR FROM INDEX field of installation panel DSNTIP4 is set to YES, and plan or packages have been rebound to pick up the change.

If access is by more than one index, INDEXONLY is Y for a step with access type MX, because the data pages are not actually accessed until all the steps for intersection (MI) or union (MU) take place.

When an SQL application uses index-only access for a ROWID column, the application claims the tablespace or tablespace partition. As a result, contention may occur between the SQL application and a utility that drains the tablespace or partition. Index-only access to a table for a ROWID column is not possible if the associated tablespace or partition is in an incompatible restrictive state. For example, an SQL application can make a read claim on the tablespace only if the restrictive state allows readers.

Table Access

The following information describes the different types of table accesses and how they are represented in the PLAN_TABLE

Tablespace Scans (ACCESSTYPE=R, PREFETCH = S). Tablespace scan (R = Relational Scan) is most often used for one of the following reasons:

  • Access is through a temporary table. (Index access is not possible for temporary tables.)

  • A matching index scan is not possible because an index is not available or no predicates match the index columns.

  • A high percentage of the rows in the table are returned. In this case an index is not really useful, because most rows need to be read anyway.

  • The indexes that have matching predicates have low cluster ratios and are therefore efficient only for small amounts of data.

Assume that table DB2USER1.CANDIDATE has no index on the column identifier (CID). The following is an example that uses a tablespace scan:

SELECT *FROM DB2USER1.CANDIDATE WHERE CID = :CIDHV;

In this case, at least every row in the CANDIDATE table must be examined to determine whether the value of CID matches the given value.

Prefetching (PREFETCH = L, S, or blank). Prefetching is a method of determining in advance that a set of data pages is about to be used and then reading the entire set into a buffer with a single asynchronous I/O operation. If the value of PREFETCH is

  • S, the method is called sequential prefetch. The data pages that are read in advance are sequential. A tablespace scan always uses sequential prefetch. An index scan might not use it.

  • L, the method is called list prefetch. One or more indexes are used to select the RIDs for a list of data pages to be read in advance; the pages need not be sequential. Usually, the RIDs are sorted. The exception is the case of a hybrid join (METHOD = 4) when the value of column SORTN_JOIN is N.

  • Blank, prefetching is not chosen as an access method. However, depending on the pattern of the page access, data can be prefetched at execution time through a process called sequential detection (also know as dynamic prefetch).

NOTE

DB2 always attempts to use sequential prefetch for a tablespace scan. For a segmented tablespace, if DB2 determines that less than four pages will be read at runtime, then sequential prefetch is disabled. The OPTIMIZE FOR 1 ROW also potentially disables sequential and list prefetch at bind time.

SORT (SORTN_ and SORTC_)

The plan tables show the reasons a sort was invoked. Those reasons could include a sort of data rows or a sort of RIDs in a RID list. SORTN_JOIN indicates that the new table of a join is sorted before the join. (For hybrid join, this is a sort of the RID list.) When SORTN_JOIN and SORTC_JOIN are both Y, two sorts are performed for the join. The sorts for joins are indicated on the same row as the new table access.

NOTE

A sort of the composite table for a join (SORTC_JOIN) is beneficial in avoiding death by random I/O. Providing cluster ratio for an index and keycard statistics for multicolumn cardinalities gives DB2 the information to determine whether a query will suffer from excessive synchronous I/O. In this case sorting the composite for a nested loop or sorting both (if required) for a sort merge or hybrid join can provide sequential access to the data.

SORTC_UNIQ indicates a sort to remove duplicates, as might be needed by a SELECT statement with DISTINCT or UNION. SORTC_ORDERBY usually indicates a sort for an ORDER BY clause. But SORTC_UNIQ and SORTC_ORDERBY also indicate when the results of a noncorrelated subquery are sorted, both to remove duplicates and to order the results. A SORTC_GROUPBY would indicate a sort for processing a GROUP BY clause.

NOTE

If more than one SORTC indicator is set to Y on the same explain output line, then DB2 is actually performing one sort to accomplish two tasks, such as sorting for uniqueness and ordering. This does not apply to SORTN_JOIN and SORTC_JOIN, as one sort is for the composite and one is for the new table.

To perform list prefetch, DB2 sorts RIDs into ascending page number order. A RID sort is usually not indicated in the PLAN_TABLE, but a RID sort normally is performed whenever list prefetch is used. The only exception to this rule is when a hybrid join is performed and a single, highly clustered index is used on the inner table. In this case SORTN_JOIN is N, indicating that the RID list for the inner table was not sorted.

NOTE

SORTN_GROUPBY, SORTN_ORDERBY, and SORTN_UNIQ are currently not used by DB2.

Nested loop join (METHOD = 1). For a nested loop join, DB2 scans the composite (outer) table. For each row in that table that qualifies (by satisfying the predicates on that table), DB2 searches for matching rows of the new (inner) table. It concatenates any it finds with the current row of the composite table. If no rows match the current row, then

  • For an inner join, DB2 discards the current row.

  • For an outer join, DB2 concatenates a row of null values.

Stage 1 and stage 2 predicates can eliminate unqualified rows before the physical joining of rows occurs. Nested loop join is often used if

  • The outer table is small.

  • Predicates with small filter factors reduce the number of qualifying rows in the outer table.

  • An efficient, highly clustered index exists on the join columns of the inner table.

  • The number of data pages accessed in the inner table is small.

NOTE

The nested loop join repetitively scans the inner table. That is, DB2 scans the outer table once and scans the inner table as many times as the number of qualifying rows in the outer table. Hence, the nested loop join is usually the most efficient join method when the values of the join column passed to the inner table are in sequence and the index on the join column of the inner table is clustered, or the number of rows retrieved in the inner table through the index is small. If the tables are not clustered in the same sequence, then DB2 can sort the composite to match the sequence of the inner table. Accesses to the inner table can then utilize sequential or dynamic prefetch.

Merge scan join (METHOD = 2). Merge scan join is also known as merge join or sort merge join. For this method, there must be one or more predicates of the form TABLE1.COL1 = TABLE2.COL2, where the two columns have the same data type, length, and null attributes. If the null attributes do not match, then the maximum number of merge join columns is 1. The exception is a full outer join, which permits mismatching null attributes.

NOTE

Join columns cannot be matching columns for a merge scan join. Instead, these columns are listed as MERGE_JOIN_COLS in the plan table. Local predicates can be matching predicates and will be applied before the join.

DB2 scans both tables in the order of the join columns. If no efficient indexes on the join columns provide the order, DB2 might sort the outer table, the inner table, or both. The inner table is put into a work file; the outer table is put into a work file only if it must be sorted. When a row of the outer table matches a row of the inner table, DB2 returns the combined rows.

A merge scan join is often used if

  • The qualifying rows of the inner and outer table are large, and the join predicate does not provide much filtering; that is, in a many-to-many join.

  • The tables are large and have no indexes with matching columns.

  • Few columns are selected on inner tables. This is the case when a DB2 sort is used. The fewer the columns to be sorted, the more efficient the sort is.

NOTE

A merge scan join is always chosen for a full outer join.

Hybrid join (METHOD = 4). The method applies only to an inner join and requires an index on the join column of the inner table. The method requires obtaining RIDs in the order needed to use list prefetch. In the successive steps, DB2

  1. Scans the outer table (OUTER).

  2. Joins the outer tables with RIDs from the index on the inner table. The result is the phase 1 intermediate table. The index of the inner table is scanned for every row of the outer table.

  3. Sorts the data in the outer table and the RIDs, creating a sorted RID list and the phase 2 intermediate table. The sort is indicated by a value of Y in column SORTN_JOIN of the plan table. If the index on the inner table is highly clustered, DB2 can skip this sort; the value in SORTN_JOIN is then N.

  4. Retrieves the data from the inner table, using list prefetch.

  5. Concatenates the data from the inner table and the phase 2 intermediate table to create the final composite table.

Hybrid join is often used if

  • A nonclustered index or indexes are used on the join columns of the inner table.

  • The outer table has duplicate qualifying rows

NOTE

DB2 may also choose to sort the composite for a hybrid join.

Star Join (METHOD = 0, 1; JOIN TYPE = S). Star join is the access path utilized in processing a star schema. A star schema is a logical database design that is included in many data warehouse and decision-support applications. A star schema is composed of a fact table and a number of dimension tables that are connected to it. A dimension table contains several values that are given an ID, which is used in the fact table instead of all the values. You can think of the fact table, which is much larger than the dimension tables, as being in the center surrounded by dimension tables; the result resembles a star formation.

To access the data in a star schema, you write SELECT statements that include join operations between the fact table and the dimension tables; no join operations exist between dimension tables. A query must satisfy a number of conditions before it qualifies for the Star Join access path. The first requirement is detection of the fact table. Given that the access path objective is efficient access to the fact table, it is important that the fact table is correctly identified.

  1. The first fact table detection algorithm is known as the unique index check. Beginning outside-in, the optimizer will evaluate each set of join predicates. For each set of join predicates between two tables, the table with a unique index on the join predicates is considered to be the parent in a parentchild relationship. As DB2 continues outside-in, the table without any further children (and which therefore only has parents) is considered to be the fact table.

  2. The second fact table detection algorithm is based upon the values of the STARJOIN DSNZPARM, which are:

    - ENABLE: Star join is enabled and the fact table is 25 times larger than the largest dimension table.

    - DISABLE: Star join is disabled (default).

    - 1: The Fact table will be the largest in the Star Join query.

    - 232,768: This is the fact table and the largest dimension table ratio. The fact table must be n times larger than the largest dimension table.

  3. The third fact table detection algorithm is the topology check, whereby the fact table is considered to be the table with the most number of join predicates in the query.

Once a fact table is identified using any of the three fact table detection algorithms, then the following conditions must be met for DB2 to use the star join technique:

  • Number of tables in the query block must be at least 10 (altered via DSNZPARM SJTABLES).

  • All join predicates are between the fact table and the dimension tables, or within tables of the same dimension (snowflake).

  • All join predicates between the fact and dimension tables must be equijoin (equal join) predicates.

  • All join predicates between the fact and dimension tables must be Boolean term predicates (fact to dimension join predicates cannot be ORed).

  • A local predicate on a dimension table cannot be ORed with a local predicate of another dimension table.

  • A single fact table column cannot be joined to columns of different dimension tables in join predicates. For example, fact table column F1 cannot be joined to column D1 of dimension table T1 and also joined to column D2 of dimension table T2.

  • No correlated subqueries exists across dimensions.

  • The data type and length of both sides of a join predicate are the same between the fact and dimension tables.

  • Dimensions cannot be a table function.

  • After DB2 simplifies join operations, no outer join operations can exist between the fact and dimension tables.

A successful match on all of the above star schema detection rules will immediately qualify the query for star join optimization. A failure on any of the above rules for a fact table will result in the next fact table detection algorithm to be evaluated. A failure of these rules for all of the fact table detection rules will result in the query being optimized using standard dynamic programming (exhaustive search) techniques or algorithms.

NOTE

When star join is performed, it is identified by an S in the JOIN_TYPE column of the PLAN_TABLE, but only for dimension tables that are accessed before the fact table.

For a star schema, even though the intersection of all dimensions with the fact table can produce a small result set, the predicates applied to one single dimension table are typically insufficient to reduce the enormous number of fact table rows.

If a join based upon related tables (dimension to fact table) does not provide adequate performance, then an alternative is to join unrelated tables. Joining of unrelated tables results in a Cartesian product, whereby every row of the first table is joined with every row of the second.

Performing a Cartesian join of all dimension tables before accessing the fact table may not be efficient. DB2 must decide how many dimension tables should be accessed first to provide the greatest level of filtering of fact table rows using available indexes. This can be a delicate balance, as further Cartesian products will produce a massive increase in the size of the intermediate result sets. Alternatively, minimal prejoining of unrelated dimension tables may not provide adequate filtering for the join to the fact table. For an efficient Cartesian process, DB2 employs a logical rather than physical Cartesian of the dimension tables. Each dimension or snowflake (further normalized dimension) covered by the chosen fact table index is accessed independently before the fact table. Each qualifying dimension (and snowflake) has all local predicates applied, with the result sorted into join column order, and finally materialized into its own separate work file.

If many of the dimensions involve snowflakes, then this preprocessing and materialization significantly reduces the number of overall tables joined, since the snowflake is resolved into a single dimension.

Rather than requiring the physical work file storage involved in a physical Cartesian, DB2 simulates a Cartesian by repositioning itself within each work file to potentially join all possible combinations to the central fact table. The sequence of this simulated Cartesian join respects the column order of the selected fact table index.

The sparseness of data within the fact table implies a significant number of values generated by the Cartesian process are not to be found by a join to the fact table. To minimize the CPU overhead of joining unnecessarily derived rows to the fact table, DB2 introduces an index key feedback loop to return the next highest key value whenever a not-found condition is encountered.

A hit on the fact table index will return the matching fact table row. A miss will return the next valid fact table index key so that the data manager can reposition itself within the dimension work files, thus skipping composite rows with no possibility of obtaining a fact table match.

NOTE

To further improve the performance of the join to the fact table, the entire join has been pushed down to data manager (stage 1); but only for star join access from the composite (dimensions) to the fact table. This ensures a reduced path length, since rows no longer need to be returned to RDS (stage 2) for the join to occur. The join method used by this process is a nested loop join.

Parallelism Usage (PARALLELISM_MODE = I, C, or X). Parallel processing applies only to read-only queries. The values are

I = Parallel I/O operations

C = Parallel CP operations

X = Sysplex query parallelism

Non-null values in columns ACCESS_DEGREE and JOIN_DEGREE indicate to what degree DB2 plans to use parallel operations. However, this can change at runtime. Parallelism is discussed later in this chapter.

DSN_STATEMNT_TABLE

This table is populated (if it exists) when EXPLAIN is run. Some of the columns are similar to those in the PLAN_TABLE, and some are new and only related to the statement cost. The columns that are unique to the DSN_STATEMENT_TABLE are

  • STMT_TYPE Type of SQL statement

  • COST_CATEGORY How much information was available

  • PROCMS Estimated processor cost in milliseconds

  • PROCSU Estimated processor cost in service units

  • REASON Reasons that COST_CATEGORY may be inaccurate

The COST_CATEGORY determination is affected by such thing as number of tables, number of rows in the tables, column cardinality, cluster ratio, first key cardinality, full key cardinality, number leaf pages, number of index levels, host variables, special registers, triggers, UDFs, RI, LOBs, and expressions. Table 17-2 describes the contents of the DSN_STATEMNT table, and Table 17-3 describes the contents of the DSN_FUNCTION_TABLE.

Table 17-2. DSN_STATEMNT Table

Column name

Description

QUERYNO

A number intended to identify the statement being explained. If QUERYNO is not unique, the value of EXPLAIN_TIME is unique.

APPLNAME

The name of the application plan for the row, or blank.

PROGNAME

The name of the program or package containing the statement being explained, or blank.

COLLID

The collection ID for the package, or blank.

GROUP_MEMBER

The member name of the DB2 that executed EXPLAIN, or blank.

EXPLAIN_TIME

The time at which the statement is processed. This time is the same as the BIND_TIME column in PLAN_TABLE.

STMT_TYPE

The type of statement being explained. Possible values:

SELECT = SELECT

INSERT = INSERT

UPDATE = UPDATE

DELETE = DELETE

SELUPD = SELECT with FOR UPDATE OF

DELCUR = DELETE WHERE CURRENT OF CURSOR

UPDCUR = UPDATE WHERE CURRENT OF CURSOR

COST_CATEGORY

Indicates if DB2 was forced to use default values when making its estimates. Possible values:

A = Indicates that DB2 had enough information to make a cost estimate without using default values.

B = Indicates that some condition exists for which DB2 was forced to use default values. See the values in REASON to determine why DB2 was unable to put this estimate in cost category A.

PROCMS

The estimated processor cost in milliseconds for the SQL statement. The estimate is rounded up to the next integer value. The maximum value for this cost is 2,147,483,647 milliseconds, which is equivalent to approximately 24.8 days. If the estimated value exceeds this maximum, the maximum value is reported.

PROCSU

The estimated processor cost in service units for the SQL statement. The estimate is rounded up to the next integer value. The maximum value for this cost is 2,147,483,647 service units. If the estimated value exceeds this maximum, the maximum value is reported.

REASON

A string that indicates the reasons for putting an estimate into cost category B.

HOST VARIABLES: The statement uses host variables, parameter markers, or special registers.

TABLE CARDINALITY: The cardinality statistics are missing for one or more of the tables used in the statement.

UDF: The statement uses user-defined functions.

TRIGGERS: Triggers are defined on the target table of an INSERT, UPDATE, or DELETE statement.

REFERENTIAL CONSTRAINTS: Referential constraints of the type CASCADE or SET NULL exist on the target table of a DELETE statement.

Table 17-3. DSN_FUNCTION_TABLE

Column name

Description

QUERYNO

A number intended to identify the statement being explained. If QUERYNO is not unique, the value of EXPLAIN_TIME is unique.

APPLNAME

The name of the application plan for the row, or blank.

PROGNAME

The name of the program or package containing the statement being explained, or blank.

COLLID

The collection ID for the package, or blank.

GROUP_MEMBER

The member name of the DB2 that executed EXPLAIN, or blank.

EXPLAIN_TIME

The time at which the statement is processed. This time is the same as the BIND_TIME column in PLAN_TABLE.

SCHEMA_NAME

The schema name of the function invoked in the explained statement.

FUNCTION_NAME

The name of the function invoked in the explained statement.

SPEC_FUNC_ID

The specific name of the function invoked in the explained statement.

FUNCTION_TYPE

The type of function invoked in the explained statement. Possible values:

S = Scalar function

T = Table function

VIEW_CREATOR

If the function specified in the FUNCTION_NAME column is referenced in a view definition, the creator of the view. Otherwise, blank.

VIEW_NAME

If the function specified in the FUNCTION_NAME column is referenced in a view definition, the name of the view. Otherwise, blank.

PATH

The value of the SQL path that was used to resolve the schema name of the function.

FUNCTION_TEXT

The text of the function reference (the function name and parameters). If the function reference is over 100 bytes, this column contains the first 100 bytes. For functions specified in fixed notation, FUNCTION_TEXT contains only the function name. For example, for a function named /, which overloads the SQL divide operator, if the function reference is A/B, FUNCTION_TEXT contains only /.

Access Path Hints (Optimization Hints)

DB2 provides a facility for telling DB2 how to process a query. This is done by giving DB2 hints. The process of giving hints to DB2 is relatively simple, but determining what those hints should be is not. Giving optimization hints to DB2 is useful in the following situations:

  • To ensure consistency of response times across rebinds and across release migrations.

  • To temporarily bypass the access path chosen by DB2.

The facility for implementing access path hints requires many tasks to be performed as well as making sure the subsystem has been enabled for hints. Some of the items that will be affected by using hints are

  • Modifying the SQL to use the hint.

  • Updating a PLAN_TABLE with the correct access path information or using an existing one.

  • Changing the bind options for those affected.

Even after a hint has been established, it is not always possible for the optimizer to use it. As part of the normal bind process, the optimizer will have to evaluate the hint and determine if it is valid. Processes will have to be in place to make sure that rebinds do not change the process. For this reason, hints should not be used unless all else fails in establishing an acceptable access path.

Using Statistics to Model Production Environment

There are statistics in the catalog that the optimizer uses in calculating the costs of SQL to determine the best access path to pick. In building a test environment, it is often helpful to copy statistics from a production environment or to update the statistics to an approximation of what production might be like. Table 17-4 lists the catalog statistics that can be updated and are also used by the optimizer in access path selection.

Table 17-4. Catalog Statistics

Table

Statistics

SYSIBM.SYSCOLDIST

CARDF

COLGROUPCOLNO

COLVALUE

FREQUENCYF

NUMCOLUMNS

TYPE

SYSIBM.SYSCOLUMNS

COLCARDF

HIGH2KEY

LOW2KEY

SYSIBM.SYSINDEXES

CLUSTERRATIOF

FIRSTKEYCARDF

FULLKEYCARDF

NLEAF

NLEVELS

SYSIBM.SYSROUTINES

CARDINALITY

INITIAL_INSTS

INITIAL_IOS

INSTS_PER_INVOC

IOS_PER_INVOC

SYSIBM.SYSTABLES

CARDF

NPAGES

NPAGESF

PCTROWCOMP

SYSIBM.SYSTABLESPACE

NACTIVE

SYSIBM.SYSTABSTATS

CARDF

NPAGES

NOTE

There are many other statistics used for access path selection that cannot be updated by the user.

Guidelines for Using Explain Output

There are a number of ways in which analyzing the explain data can help you to tune your queries and environment. For example, are indexes being used? Creating appropriate indexes can have a significant benefit on performance. Using the explain output, you can determine if the indexes you have created to help a specific set of queries are being used. In the explain output, you should look for index usage in the following areas:

  • Join Predicates

  • Local Predicates

  • GROUP BY clauses

  • ORDER BY clauses

  • The select list

You can also use explain to evaluate whether a different index can be used instead of an existing index or no index at all. After creating a new index, collect statistics for that index using the RUNSTATS utility and rebind the query.

NOTE

Collecting KEYCARD statistics can enhance the optimizer's access path selection for queries involving joins.

Over time, you may notice, through the explain data, that instead of an index scan, a table scan is now being used. This can result from a change in the clustering of the table data. If the index that was previously being used now has a low cluster ratio, you want to

  • Reorganize your table to cluster the data according to that index.

  • Use the RUNSTATS command to update the catalog statistics.

  • Rebind the query.

  • Reexamine the explain output to determine whether reorganizing the table has affected the access plan.

NOTE

The more indexes created, the more importance is placed on accurate and detailed statistics. This allows DB2 to differentiate between the indexes for access path selection. Increasing the number of indexes increases the potential access paths that DB2 must evaluate. This may lead to a less efficient access path being selected if statistics do not adequately distinguish each index for DB2.

Is the type of access appropriate for the application? You can analyze the explain output and look for types of access to the data that, as a rule, are not optimal for the type of application being executed. For example,

  • Online Transaction Processing (OLTP) Queries: OLTP applications are prime candidates to use matching index scans with range-delimiting predicates, because they tend to return only a few rows that are queries, using an equality predicate against a key column. If your OLTP queries are using a table scan or nonmatching index scan, you may want to analyze the explain data to determine the reasons a matching index scan was not used.

  • Read-Only Queries: The search criteria for a read-only query may be vague, causing a large number of rows to qualify. If the user usually looks only at a few screens of the output data, he or she may want to try to ensure that the entire answer set need not be computed before some results are returned. In this case, the goals of the user are different from the basic operating principle of the optimizer, which attempts to minimize resource consumption for the entire query, not just the first few screens of data.

For example, if the explain output shows that both merge scan join and sort operators were used in the access plan, the entire answer set will be materialized in a temporary table before any rows are returned to the application. In this case, you can attempt to change the access plan by using the OPTIMIZE FOR clause on the SELECT statement. The value specified for the OPTIMIZE clause should represent the number of rows to be processed by the application. In this way, the optimizer can attempt to choose an access plan that does not produce the entire answer set in a temporary table before returning the first rows to the application.

Visual Explain

Visual Explain is a graphical user interface (GUI) utility that gives the database administrator or application developer the ability to examine the access plan determined by the optimizer. It provides

  • An easy-to-understand display of a selected access path.

  • Suggestions for changing an SQL statement.

  • An ability to invoke EXPLAIN for dynamic SQL statements.

  • An ability to provide DB2 catalog statistics for referenced objects of an access path.

  • A subsystem parameter browser with keyword find capabilities.

Visual Explain can be used to analyze previously generated explains or to gather explain data and explain dynamic SQL statements.


149 - Designing Indexes for Performance

Chapter 17. Application Performance and Optimization

Designing Indexes for Performance

The following sections show the different access paths provided by indexes. We should ensure that indexes are in place to provide the best access path possible for all critical queries.

Indexes for Efficient Access

DB2 uses the following index access paths:

  • Matching index scan (MATCHCOLS > 0)

  • Index screening

  • Nonmatching index scan (ACCESSTYPE = I and MATCHCOLS = 0)

  • IN-list index scan (ACCESSTYPE = N)

  • Multiple index access (ACCESSTYPE is M, MX, MI, or MU)

  • One-fetch access (ACCESSTYPE = I1)

  • Index-only access (INDEXONLY = Y)

  • Equal unique index (MATCHCOLS = number of index columns)

Matching Index Scan (MATCHCOLS > 0)

In a matching index scan, predicates are specified on either the leading or all of the index key columns. These predicates provide filtering; only specific index pages and data pages need to be accessed. If the degree of filtering (cardinality) is high, the matching index scan is efficient.

Index matching predicates are applied in the sequence of the index columns. Therefore, coding sequence is not important for index matching predicates. DB2 evaluates WHERE clause predicates based upon the following sequence:

  1. Indexed predicates

    - Matching predicates

    - Index screening predicates

  2. Stage 1 predicates

  3. Stage 2 predicates

Excluding index matching predicates, within each stage (screening, stage 1 or 2), predicates are generally applied in the following sequence:

  1. All equal predicates (and IS NULL).

  2. All range predicates (and IS NOT NULL).

  3. All other predicates.

The final rule for predicate evaluation dictates that within each of the above guidelines, predicates are evaluated in the sequence that they are coded. This gives some control, and therefore the programmer should code the most restrictive predicates first.

Index Screening

In index screening, predicates are specified on index key columns but are not part of the matching columns. Those predicates improve subsequent data page access by reducing the number of rows that qualify while searching the index. For example, with an index on T(C1,C2,C3,C4) in the following SQL statement, C3 > 0 and C4 = 2 are index screening predicates, whereas C1 = 1 is a matching index predicate.

SELECT *FROM T
WHERE C1 =1
AND C3 >0 AND C4 =2
AND C5 =8;
Nonmatching Index Scan (ACCESSTYPE = I and MATCHCOLS = 0)

In a nonmatching index scan, no matching columns are in the index. Hence, all the index keys must be examined. Because a nonmatching index scan usually does not provide strong filtering, only a few cases provide an efficient access path if subsequent data pages must also be accessed. If the access path is index-only, then a nonmatching index scan may prove beneficial, especially if the index is smaller than the tablespace.

NOTE

An index-only nonmatching index scan may not always be more efficient than a tablespace scan. A tablespace may be smaller than an index if the number of index keys is large or the tablespace is compressed. Also, assuming both are of similar size, an index scan may be less efficient because the scan must follow the leaf page pointer chain, which may not be sequential due to index page splits.

IN-List Index Scan (ACCESSTYPE = N)

An IN-list index scan is a special case of the matching index scan, in which a single indexable IN predicate is used as a matching equal predicate. You can regard the IN-list index scan as a series of matching index scans with the values in the IN predicate being used for each matching index scan. The following example has an index on (C1,C2,C3,C4) and might use an IN-list index scan:

SELECT *FROM T
WHERE C1=1 AND C2 IN (1,2,3)
AND C3>0 AND C4<100;

This example could result in an ACCESSTYPE = N and MATCHCOLS = 3 (C1, C2, C3). C4 would be an index screening predicate.

NOTE

At most, one IN predicate can be a matching predicate; the exception, however, is a noncorrelated IN subquery. IN-list predicates cannot be matching predicates for MX access or list prefetch.

Multiple Index Access (ACCESSTYPE is M, MX, MI, or MU)

Multiple index access uses more than one index to access a table. It is a good access path when

  • No single index provides efficient access.

  • A combination of index accesses provides efficient access.

RID lists are constructed for each of the indexes involved. The unions (OR conditions) or intersections (AND conditions) of the RID lists produce a final list of qualified RIDs that is used to retrieve the result rows, using list prefetch. You can consider multiple index access as an extension to list prefetch with more complex RID retrieval operations in its first phase. The complex operators are union and intersection. DB2 may choose multiple index access for the following query:

SELECT *FROM EMP
WHERE (AGE =34)OR
(JOB ='MANAGER');

For this query,

  • EMP is a table with columns EMPNO, EMPNAME, DEPT, JOB, AGE, and SAL.

  • EMPX1 is an index on EMP with key column AGE.

  • EMPX2 is an index on EMP with key column JOB.

One-Fetch Access (ACCESSTYPE = I1)

One-fetch index access requires retrieving only one row. It is the best possible access path and is chosen whenever it is available. It applies to a statement with a MIN or MAX column function: The order of the index allows a single row to give the result of the function. Either an ascending or descending index can be utilized to satisfy a MIN or MAX function using one-fetch index access.

Index-Only Access (INDEXONLY = Y)

With index-only access, the access path does not require any data pages because the access information is available in the index. Conversely, when an SQL statement requests a column that is not in the index, updates any column in the table, or deletes a row, DB2 has to access the associated data pages. Because the index is generally smaller than the table itself, an index-only access path usually processes the data efficiently.

NOTE

The number of levels of the index can determine whether index-only access will be chosen instead of index and data access via a different index. Assume IX1 has four levels and provides an index-only access path, and IX2 has three levels and is not index-only. DB2 may choose IX2 and access the data pages, since both access paths result in four I/Os.

Equal Unique Index (MATCHCOLS = number of index columns)

An index that is fully matched and unique, and in which all matching predicates are equal predicates, is called an equal unique index case. This case guarantees that only one row is retrieved. If there is no one-fetch index access available, this is considered the most efficient access over all other indexes that are not equal unique. (The uniqueness of an index is determined by whether or not it was defined as unique.) Sometimes DB2 can determine that an index that is not fully matching is actually an equal unique index case. This is based upon the existence of another unique index with a subset of the key columns.

Indexes to Help Avoid Sorts

As well as providing selective access to data, indexes can also order data, sometimes eliminating the need for sorting. Some sorts can be avoided if index keys are in the order needed by ORDER BY, GROUP BY, a join operation, or DISTINCT in a column function. A DISTINCT sort can also be avoided if a unique index exists on the selected columns and/or WHERE clause columns. In other cases, as when list prefetch is used, the index does not provide useful ordering, and the selected data might have to be sorted.

When it is absolutely necessary to prevent a sort, consider creating an index on the column or columns necessary to provide that ordering. Consider also using the clause OPTIMIZE FOR 1 ROW to discourage DB2 from choosing a sort for the access path. Consider the following query:

SELECT C1,C2,C3 FROM T
WHERE C1 >1
ORDER BY C1 OPTIMIZE FOR 1 ROW;

An ascending index on C1 or an index on (C1,C2,C3) could eliminate a sort.

NOTE

The OPTIMIZE FOR 1 ROW has implications other than avoiding a sort and therefore should be utilized only when necessary. Consider specifying a value that represents the number of rows that are required to be processed by the application.

Not all sorts are inefficient. For example, if the index that provides ordering is not an efficient one and many rows qualify, it is possible that using another access path to retrieve and then sort the data could be more efficient than the inefficient, ordering index.

Index Advisor Facility

The index advisor is a management tool that provides assistance in the designing of indexes on tables. It is useful in the following situations:

  • Finding the best indexes for a problem query.

  • Finding the best indexes for a set of queries (workload) subject to resource limits that are optionally applied.

  • Testing out an index on a workload without having to create the index.

There are two concepts associated with this facility: workload and virtual indexes.

A workload is a set of SQL statements (SELECT, INSERT, UPDATE, DELETE) that DB2 has to process over a given period of time. The information in the workload is concerned with the type and frequency of the SQL statements over a given period of time. The index advisor uses this workload information in conjunction with the database information to recommend indexes. The goal of the advising engine is to minimize the total workload cost.

Virtual indexes are indexes that do not exist in the current database schema. These indexes could be either recommendations that the facility has made or indexes that are being proposed to be created but should be modeled for the effect using the advisor facility.

For DB2 for OS/390 and z/OS, this tool works on a set of dynamic SQL statements (only dynamic SQL is currently supported; static will be delivered in a later release). This process is performed by creating a modeling database for DB2 for OS/390 on a DB2 for UNIX, Windows, or Linux workstation using configuration parameters to mimic DB2 for OS/390 and z/OS. One way to use this tool is to invoke it through the Control Center.


150 - Query Parallelism

Chapter 17. Application Performance and Optimization

Query Parallelism

In order to reduce elapsed time for a query, DB2 can provide a query with parallel resources, such as several I/O paths or processors. By taking advantage of these resources, queries can run in a shorter period of time, allowing more work to be pushed through the system. Parallelism can help improve the performance of I/O and CPU bound read-only queries. It can help queries that are reading large amounts of data, regardless of the filtration.

There is some overhead associated with the use of parallelism in terms of CPU. DB2 scales processor-intensive work across all available processors. Parallelism can average less than 1 percent additional CPU overhead for long-running queries and less than 10 percent for short-running queries.

I/O and CPU Parallelism

DB2 can utilize two different methods for achieving query parallelism: I/O or CPU. With I/O parallelism the goal is to move elapsed time towards CPU time by splitting data access into equal, sequential prefetch streams to bring I/O time down to estimated CPU time. If CPU is estimated at 1 second, and I/O at 3 seconds, the three I/O parallel streams of approximately equal size will be started. Each I/O stream should cost about 1 second. This is implemented with a round-robin type of GET paging. With current releases of DB2, I/O parallelism is very infrequently chosen, instead the more preferred method is CPU parallelism.

The goal of CPU parallelism is to move elapsed time towards CPU time, by splitting queries into equal multiple smaller queries and process those queries in multiple execution units, or parallel tasks. At execution time, DB2 will take into consideration the number of CPUs available, and if there are not enough CPUs to support the degree of parallelism initially chosen by the optimizer, the degree will be degraded.

When Parallelism Is Chosen

DB2 parallelism is decided at both the time of the bind and at runtime. If parallelism is not chosen at bind time, there is no possibility of it being chosen at runtime. Even if parallelism is chosen at bind time, it may not be used at runtime due to several factors. If there is not enough space in the virtual buffer pool to support the requested degree of parallelism, the degree can be reduced from that chosen at bind time or parallelism can be turned all together. If host variables are used in the SQL query, this can prevent DB2 from determining which partitions will qualify in a query; therefore the degree chosen for parallelism will be decided at runtime. If the machine on which DB2 is running does not have hardware sort at runtime, parallelism will be disabled. If DB2 determines that an ambiguous cursor can be updated, then parallelism will be disabled. If parallelism is disabled, the query does not failDB2 simply uses a sequential plan for access to the data.

During BIND or PREPARE, DB2 chooses the access path best suited for the query and then does a postoptimization step to identify the sections of the access path that will benefit most from parallelism. It then identifies the part of the actual query that can be executed in parallel, and then determines the degree of parallelism to be used.

Sysplex Query Parallelism

Sysplex query parallelism works in much the same multitasking way as CPU parallelism; in addition, it gives us the ability to take a complex query and run across multiple members in a data sharing group.

Sysplex query parallelism is best used with isolation level UR (uncommitted read) to avoid excess lock propagation.

A query is issued by a coordinator, who sends the query to the assistant members in the group. The data is then processed and returned to the coordinator either by a work file (the coordinator will read each assistant's work files) or by cross-system coupling facility (XCF) links when a work file is not necessary.

Queries Best Suited for Parallelism

Queries with the following characteristics will be able to take advantage of parallelism:

  • Long-running, read-only queries, both static and dynamic SQL, from both local and remote sites, and when using either private or DRDA protocols

  • Tablespace scans and index scans

  • Joins

  • Nested loop

  • Merge scan

  • Hybrid without sort on new tables

  • Sorts

  • Aggregate functions

There are only a few places where parallelism will not be considered:

  • Queries that use materialization of views

  • Queries that perform materialization because of nested table expressions

  • Queries performing a merge scan join of more than one column

  • Queries using direct row access

The following will cause only Sysplex parallelism not to be considered:

  • Queries with list prefetch and multiple index access

  • Queries accessing LOB data

Parallelism should not be used if a system is already CPU-constrained, because parallelism would only add to the problem in most situations.

NOTE

CPU parallelism cannot be used when a cursor is defined WITH HOLD, since this cursor's use is potentially interrupted by a commit, which causes a stoppage in processing.

Short-running queries are usually not going to see a great benefit from parallelism (generally, a short-running query is one that is subsecond). But how often are long-running queries separated from short-running queries? Well, if you are trying to get the benefits from parallelism without placing unnecessary overhead where it does not belong, consideration for this type of granularity of processing will need to be done.

There are two potential options: You could separate the long-running queries into a separate package and bind it DEGREE(ANY) in a different collection, and then use the SET CURRENTPACKAGE statement to switch between it and a program bound with DEGREE(1) for shorter queries that are better to let run sequentially. Or, you can set the macro SPRMPTH to disable parallelism for short-running queries. The default for this value is 120; thus, any query with an estimated cost of less than 120 milliseconds will have parallelism disabled. Parallelism is enabled for any query above this threshold.


151 - Database Monitoring

Chapter 17. Application Performance and Optimization

Database Monitoring

Database monitoring should be an ongoing proactive process. There are a variety of ways to monitor DB2 such as traces and specialized monitoring software.

DB2 PM

IBM's DB2 PM (DB2 Performance Monitor) is a performance analysis tool for both the subsystem and applications. Its primary objective is to report DB2 instrumentation data in a form that is easy to understand and analyze. DB2 PM presents this instrumentation data in the following ways:

  • The Batch reports present the data you select in comprehensive reports or graphs containing systemwide and application-related information for both single DB2 subsystems and DB2 members of a data sharing group. You can combine instrumentation data from several different DB2 locations into one report. Batch reports can be used to examine performance problems and trends over a period of time.

  • The Online Monitor gives a current "snapshot" view of a running DB2 subsystem, including applications that are running. Its history function displays information about subsystem and application activity in the recent past.

  • The Statistics reports provide an excellent source of information, such as buffer pools, EDM pools, RID processing, and logging, all at a subsystem level.

  • The Accounting reports provide information about applications for specific time periods. Those are the most popular, most useful reports for ongoing analysis, trend analysis, and predictive monitoring.

There are also some more specific reports, such as the Lock Detail Analysis report for monitoring locking problems. The more detailed reports require additional traces to be turned on and should be used only for problem analysis and not run on a continual basis. Both Accounting and Statistics reports have long and short versions. Which is used depends on the amount of detail needed for analysis.

DB2 PM also includes User-Tailored Reports (UTRs) that allow you to tailor reports for more precise analysis.

The online portion of the DB2 PM product has a very user-friendly GUI. Figure 17-1 shows the main screen of the DB2 PM GUI. It has a look and feel similar to the DB2 Control Center. From here you can monitor all of your DB2 subsystems and your data-sharing environment. Figure 17-2 gives you a look at a detail screen.

Figure 17-1. DB2 PM GUI main screen.

Figure 17-2. DB2 PM GUI locking detail screen.

Resource Limit Facility

DB2's resource limit facility (governor) lets you perform the following activities:

  • Set warning and error thresholds by which the governor can inform users (via your application programs) that a certain processing limit might be exceeded for a particular dynamic SELECT, INSERT, UPDATE, or DELETE statement. This is called predictive governing.

  • Stop a currently executing dynamic SQL statement (SELECT, INSERT, UPDATE, or DELETE) that exceeds the processor limit that you have specified for that statement. This is sometimes called reactive governing to differentiate its function from that of predictive governing, a function that is also handled by the resource limit facility. The resource limit facility does not control static SQL statements, whether or not they are executed locally or remotely.

  • Restrict bind and rebind activities to avoid performance impacts on production data.

  • Restrict particular parallelism modes for dynamic queries.


152 - Tracing Problems in DB2

Chapter 17. Application Performance and Optimization

Tracing Problems in DB2

These traces can be used for problem determination:

  • DB2 trace

  • IMS attachment facility trace

  • CICS trace

  • Three TSO attachment facility traces

  • CAF trace stream

  • OS/390 RRS trace stream

  • MVS component trace used for IRLM

In this section we look at DB2 traces. For information about other trace capabilities, refer to the appropriate product documentation.

DB2 Traces

DB2 trace allows you to trace and record subsystem data and events. There are five different types of trace, and DB2 trace can record six types of data: statistics, accounting, audit, performance, monitor, and global. The tables later in this chapter indicate which instrumentation facility IDs (IFCIDs) are activated for the different types of trace, the classes within those trace types, and the information each IFCID returns. The trace records are written using generalized trace facility (GTF) or system management facility (SMF) records. We now take a look at the types of data DB2 collects for each trace class.

Statistics

The data collected in the statistics trace allows you to conduct DB2 capacity planning and to tune the entire set of DB2 programs. The statistics trace reports information about how much the DB2 system services and database services are used. It is a systemwide trace and should not be used for charge-back accounting. Use the information the statistics trace provides to plan DB2 capacity or to tune the entire set of active DB2 programs.

Statistics trace classes 1, 3, 4, and 5 are the default classes for the statistics trace if statistics is specified YES in panel DSNTIPN. If the statistics trace is started using the START TRACE command, then class 1 is the default class.

  • Class 1 provides information about system services and database statistics. It also includes the system parameters that were in effect when the trace was started.

  • Class 3 provides information about deadlocks and timeouts.

  • Class 4 provides information about exceptional conditions.

  • Class 5 provides information about data sharing.

If you specified YES in the SMF STATISTICS field on the Tracing Panel (DSNTIPN), the statistics trace starts automatically when you start DB2, sending class 1, 3, 4, and 5 statistics data to SMF. SMF records statistics data in both SMF type 100 and 102 records. IFCIDs 0001, 0002, 0202, and 0230 are of SMF type 100. All other IFCIDs in statistics trace classes are of SMF type 102. From panel DSNTIPN, you can also control the statistics collection interval (STATISTICS TIME field). The statistics trace is written on an interval basis, and you can control the exact time that statistics traces are taken.

Accounting

The accounting trace provides data that allows you to assign DB2 costs to individual authorization IDs and to tune individual programs. The DB2 accounting trace provides information related to application programs, including such things as

  • Start and stop times

  • Number of commits and aborts

  • The number of times certain SQL statements are issued

  • Number of buffer pool requests

  • Counts of certain locking events

  • Processor resources consumed

  • Thread wait times for various events

  • RID pool processing

  • Distributed processing

  • Resource limit facility statistics

Accounting times are usually the prime indicator of a performance problems, and most often should be the starting point for analysis. DB2 times are classified as follows:

  • Class 1: This time shows the time the application spent since connecting to DB2, including time spent outside DB2.

  • Class 2: This shows the elapsed time spent in DB2. It is divided into CPU time and waiting time.

  • Class 3: This elapsed time is divided into various waits, such as the duration of suspensions due to waits for locks and latches or waits for I/O.

DB2 trace begins collecting this data at successful thread allocations to DB2 and writes a completed record when the thread terminates or when the authorization ID changes.

Accounting data for class 1 (the default) is accumulated by several DB2 components during normal execution. This data is then collected at the end of the accounting period; it does not involve as much overhead as individual event tracing.

On the other hand, when you start class 2, 3, 7, or 8, many additional trace points are activated. Every occurrence of these events is traced internally by DB2 trace, but these traces are not written to any external destination. Rather, the accounting facility uses these traces to compute the additional total statistics that appear in the accounting record, IFCID 003, when class 2 or class 3 is activated. Accounting class 1 must be active to externalize the information.

To turn on accounting for packages and DBRMs, accounting trace classes 1 and 7 must be active. Though you can turn on class 7 while a plan is being executed, accounting trace information is only gathered for packages or DBRMs executed after class 7 is activated. Activate accounting trace class 8 with class 1 to collect information about the amount of time an agent was suspended in DB2 for each executed package. If accounting trace classes 2 and 3 are activated, there is minimal additional performance cost for activating accounting trace classes 7 and 8.

If you want information from either or both accounting class 2 and 3, be sure to activate classes 2 and/or 3 before your application starts. If these classes are activated during the application, the times gathered by DB2 trace are only from the time the class was activated.

Accounting trace class 5 provides information on the amount of elapsed time and task control block (TCB) time that an agent spent in DB2 processing instrumentation facility interface (IFI) requests. If an agent did not issue any IFI requests, these fields are not included in the accounting record.

If you specified yes for SMF ACCOUNTING on the Tracing Panel, the accounting trace starts automatically when you start DB2 and sends IFCIDs that are of SMF type 100 to SMF. The accounting record IFCID 0003 is of SMF type 101.

Performance

The performance trace provides information about a variety of DB2 events, including events related to distributed data processing. You can use this information to further identify a suspected problem or to tune DB2 programs and resources for individual users or for DB2 as a whole. To trace performance data, you must use the START TRACE(PERFM) command. Performance traces cannot be automatically started.

Audit

This trace provides data that can be used to monitor DB2 security and access to data to ensure that data access is allowed only for authorized purposes. On the CREATE TABLE or ALTER TABLE statements, you can specify whether or not a table is to be audited and in what manner; you can also audit security information, such as any access denials, grants, or revokes for the table. The default causes no auditing to take place. If you specified yes for AUDIT TRACE on the Tracing Panel, audit trace class 1 starts automatically when you start DB2. By default, DB2 sends audit data to SMF.

Monitor

The monitor trace records data for online monitoring with user-written programs. This trace type has several predefined classes; those that are used explicitly for monitoring are listed here:

  • Class 1 (the default) allows any application program to issue an IFI READS request to the IFI facility. If monitor class 1 is inactive, a READS request is denied. Activating class 1 has a minimal impact on performance.

  • Class 2 collects processor and elapsed time information. The information can be obtained by issuing a READS request for IFCID 0147 or 0148. In addition, monitor trace class 2 information is available in the accounting record, IFCID 0003. Monitor class 2 is equivalent to accounting class 2 and results in equivalent overhead. Monitor class 2 times appear in IFCIDs 0147, 0148, and 0003 if either monitor trace class 2 or accounting class 2 is active.

  • Class 3 activates DB2 wait timing and saves information about the resource causing the wait. The information can be obtained by issuing a READS request for IFCID 0147 or 0148. In addition, monitor trace class 3 information is available in the accounting record, IFCID 0003. As with monitor class 2, monitor class 3 overhead is equivalent to accounting class 3 overhead. When monitor trace class 3 is active, DB2 can calculate the duration of a class 3 event, such as when an agent is suspended due to an unavailable lock. Monitor class 3 times appear in IFCIDs 0147, 0148, and 0003 if either monitor class 3 or accounting class 3 is active.

  • Class 5 traces the amount of time spent processing IFI requests.

  • Class 7 traces the amount of time an agent spent in DB2 to process each package. If monitor trace class 2 is active, activating class 7 has minimal performance impact.

  • Class 8 traces the amount of time an agent was suspended in DB2 for each package executed. If monitor trace class 3 is active, activating class 8 has minimal impact.

Invoking Traces

Traces can be started automatically via the DB2 install panels, or they can be stopped and started dynamically by using the TRACE commands. The trace commands include

  • START TRACE: Invokes one or more types of trace.

  • DISPLAY TRACE: Displays the trace options that are in effect.

  • STOP TRACE: Stops any trace that was started by either the START TRACE command or the parameters specified when installing or migrating.

  • MODIFY TRACE: Changes the trace events (IFCIDs) being traced for a specified active trace. Several parameters can be specified to further qualify the scope of a trace. Specific events within a trace type as well as events within specific DB2 plans, authorization IDs, resource manager IDs, and locations, can be traced. The destination to which trace data is sent can also be controlled.

Trace Classes

It is important to have the appropriate classes always gathering information about your DB2 subsystem and its activity. It is a general recommendation that you have SMF accounting class 1, 2, and 3, and SMF statistics class 1, 3, and 4 (1 and 3 at a minimum) selected during normal execution. Any other trace classes should not be run constantly because they cause excessive overhead if run for long periods of time.

When executing other traces, it is wise to time the trace to only the IFCIDs necessary for the appropriate performance analysis or problem diagnosis. These traces also should only be run for short periods of time. Following is an example of limiting a trace.

-START TRACE(PERFTC1) CLASS(8) IFCID(0221) PLANNAME(CERTPLA)

In the above example, this limits a performance trace to class 8 with IFCID 221, which is used to view the actual degree of parallelism at runtime.

IFCIDs

Tables 17-5 through 17-9 show the various IFCIDs that are started for each different type of class within a trace.

Table 17-5. Accounting Trace

Class

IFCID

Description

1

3

All accounting

106

System parameters in effect

239

Overflow for package accounting

2

200

UDF entry/exit signal

232

DB2 thread entry/exit signal

3

6

Beginning of a read I/O operation

7

CC after read I/O operation

8

Beginning of synchronous write I/O

9

CC of sync or async write I/O

32

Beginning of wait for log manager

33

End of wait for log manager

44

Lock suspend or identify call IRLM

45

Lock resume

51

Shared latch resume; serviceability

52

Shared latch wait, serviceability

56

Exclusive latch wait; serviceability

57

Exclusive latch resume. serviceability

117

Begin thread wait time for log I/O

118

End thread wait time for log I/O

127

Agent ready to suspend page wait

128

Page requestor resumed by I/O initialization

170

Suspend for sync EXEC.N unit switch

171

Resume agent waiting DB2 service task

174

Begin archive log mode (QUIESCE)

175

End archive log mode (QUIESCE)

213

Beginning of wait for claim request

214

End of wait for claim request

215

Beginning of wait for drain request

216

End of wait for drain request

226

Beginning of suspend for page latch

227

End of suspend for page latch

242

Begin wait for scheduled stored procedure

243

End wait for scheduled stored procedure

313

Messages for long-running URs

4

151

User-defined accounting trace

5

187

Entry to and exit from IFI

7

232

DB2 thread entry/exit signal

232

For package-level or DBRM-level accounting

240

Event signal for package accounting

8

6

Beginning of a read I/O operation

7

CC after read I/O operation

8

Beginning of synchronous write I/O

9

CC of sync or async write I/O

32

Beginning of wait for log manager

33

End of wait for log manager

44

Lock suspend or identify call IRLM

45

Lock resume

51

Shared latch resume; serviceability

52

Shared latch wait; serviceability

56

Exclusive latch wait; serviceability

57

Exclusive latch resume; serviceability

117

Begin thread wait time for log I/O

118

End thread wait time for log I/O

127

Agent ready to suspend page wait

128

Page requestor resumed by I/O initialization

170

Suspend for sync EXEC.N unit switch

171

Resume agent waiting DB2 service task

174

Begin archive log mode(QUIESCE)

175

End archive log mode(QUIESCE)

213

Beginning of wait for claim request

214

End of wait for claim request

215

Beginning of wait for drain request

216

End of wait for drain request

226

Beginning of suspend for page latch

227

End of suspend for page latch

241

Begin/end suspension of package or DBRM

242

Begin wait for scheduled stored procedure

243

End wait for scheduled stored procedure

Table 17-6. Audit Trace

Class

IFCID

Description

1

140

Authorization failures

2

141

Explicit grants and revokes

3

142

Creates, alters, drops audit

4

143

First attempted write audited object

5

144

First attempted read audited object

6

145

Audit log record of some SQL statements

7

55

Issuance of set current SQLID

83

End identify request

87

Ending of sign-on request

169

Distributed authorization ID translation

312

DCE security

8

23

Utility start information

24

Utility object or phase change

25

Utility end information

9

146

User-defined audit trace

Table 17-7. Monitor Trace

Class

IFCID

Description

1

1

System services

2

Database services

106

System parameters in effect

124

Current SQL statement

129

Virtual storage access method (VSAM) CIsDB2 recover log

147

Summary thread status record

148

Detailed thread status record

149

Lock information for a resource

150

Lock information for an agent IFCID

202

System parameters

230

Data sharing global statistics

254

Group buffer pool usage

306

Log record retrieval

316

Prepared statement cache statistics

317

Prepared statement cache statement text

2

232

DB2 thread entry exit signal

3

6

Beginning of a read I/O operation

7

CC after read I/O operation

8

Beginning of synchronous write I/O

9

CC of sync or async write I/O

32

Beginning of wait for log manager

33

End of wait for log manager

44

Lock suspend or identify call IRLM

45

Lock resume

51

Shared latch resume; serviceability

52

Shared latch wait; serviceability

56

Exclusive latch wait; serviceability

57

Exclusive latch resume; serviceability

117

Begin thread wait time for log I/O

118

End thread wait time for log I/O

127

Agent ready to suspend page wait

128

Page requestor resumed by I/O initialization

170

Suspend for sync EXEC unit switch

171

Resume agent waiting DB2 service task

174

Begin archive log mode (QUIESCE)

175

End archive log mode (QUIESCE)

213

Beginning of wait for claim request

214

End of wait for claim request

215

Beginning of wait for drain request

216

End of wait for drain request

226

Beginning of suspend for page latch

227

End of suspend for page latch

242

Begin wait for scheduled stored procedure

243

End wait for scheduled stored procedure

4

155

User-defined monitor trace

5

187

Entry or exit to IFI

6

185

Data capture information

7

232

DB2 thread entry/exit signal

232

For package-level or DBRM-level accounting

240

Event signal for package accounting

8

6

Beginning of a read I/O operation

7

CC after read I/O operation

8

Beginning of synchronous write I/O

9

CC of sync or async write I/O

32

Begin of wait for log manager

33

End of wait for log manager

44

Lock suspend or identify call IRLM

45

Lock resume

51

Shared latch resume; serviceability

52

Shared latch wait; serviceability

56

Exclusive latch wait; serviceability

57

Exclusive latch resume; serviceability

117

Begin thread wait time for log I/O

118

End thread wait time for log I/O

127

Agent ready to suspend page wait

128

Page requestor resumed by I/O initialization

170

Suspend for sync EXEC unit switch

171

Resume agent waiting DB2 service task

174

Begin archive log mode (QUIESCE)

175

End archive log mode (QUIESCE)

213

Beginning of wait for claim request

214

End of wait for claim request

215

Beginning of wait for drain request

216

End of wait for drain request

226

Beginning of suspend for page latch

227

End of suspend for page latch

241

Begin/end suspension of pack/DBRM

242

Begin wait for scheduled stored procedure

243

End wait for scheduled stored procedure

Table 17-8. Performance Trace

Class

IFCID

Description

1

1

System services

2

Database services

31

EDM pool full condition

42

A checkpoint started

43

A checkpoint ended

76

Beginning of an end memory request

77

End of an end memory request

78

Beginning of an end task request

79

End of an end task request

102

Detection of short on storage

103

Setting off of short on storage

105

Internal DBID OBID to DB/TS

106

System parameters in effect

107

Dataset open/close information

153

User-defined except-condition trace

2

3

All accounting

68

Beginning of a rollback request

69

End of a rollback request

70

Begin commit phase 2 request

71

End commit phase 2 request

72

Beginning of create thread request

73

End of a create thread request

74

Beginning of terminate thread request

75

End of a terminate thread request

80

Beginning of an establish exit request

81

End of an establish exit request

82

Begin identify request

83

End identify request

84

Begin phase 1 commit request

85

End phase 1 commit request

86

Beginning of sign-on request

87

End of sign-on request

88

Beginning of sync request

89

Ending of sync request

106

System parameters in effect

174

Begin archive log mode (QUIESCE)

175

End archive log mode (QUIESCE)

3

22

Miniplans generated

53

End of descr, commit, rollback, or error

55

Issuance of set current SQLID

58

End of SQL statement execution

59

Start of FETCH SQL statement execution

60

Start of SELECT SQL statement execution

61

Start of INSERT, UPDATE, DELETE SQL

62

Start of DDL statement execution

63

SQL statement to be parsed

64

Start PREPARE SQL statement exec

65

Start open cursor static or dynamic SQL

66

Start close cursor static or dynamic SQL

92

Start access method services

95

Sort started

96

Sort ended

97

Access method services cmd compl

106

System parameters in effect

112

Attributes plan after thread allocation

177

Successful package allocation

233

Start/end call to user routine

237

Set current degree information

272

Associate locators information

273

Allocate cursor information

324

Function resolution information

325

Start/end trigger activation

4

6

Beginning of a read I/O operation

7

Completion code after read I/O

8

Beginning of synchronous write I/O

9

CC of sync or async write I/O

10

Beginning of async write I/O

29

Start EDM I/O request; load DBD or CT

30

End of EDM I/O request

105

Internal DBID OBID to DB/TS

106

System parameters in effect

107

Dataset open/close information

127

Agent ready to suspend page wait

128

Page requestor resumed by I/O initialization

226

Begin of suspend for page latch

227

End of suspend for page latch

5

32

Begin of wait for log manager

33

End of wait for log manager

34

Log manager wait for read I/O begin

35

Log manager wait for read I/O end

36

Log manager wait for non-I/O begin

37

Log manager wait for non-I/O end

38

Log manager wait act log write begin

39

Log mgr wait act log write I/O end

40

Log manager archive write I/O begin

41

Log manager archive write I/O end

104

Log dataset mapping

106

System parameters in effect

114

Start archive read I/O wait

115

End read archive I/O wait on DASD

116

End read archive I/O wait on tape

117

Begin archive read

118

End archive read

119

BSDS write I/O beginning

120

BSDS write I/O end

228

Start archive allocation wait

229

End archive allocation wait

6

20

Locking summary

44

Lock suspend or an ID; call to IRLM

45

Lock resume

105

Internal DBID OBID to DB/TS

106

System parameters in effect

107

Data set open/close information

172

Units of work involved in deadlock

196

Lock timeout details

213

Beginning of wait for drain lock

214

End of wait for drain lock

218

Summary of lock avoidance technique

7

21

Detail lock request on return from IRLM

105

Internal DBID OBID to DB/TS

106

System parameters in effect

107

Dataset open/close information

199

Buffer pool dataset statistics

223

Detail of lock avoidance technique

8

13

Input to hash scan

14

End of hash scan

15

Input matching or nonmatching index scan

16

Input to the first insert

17

Input to sequential scan

18

End index scan, insert, sequential scan

105

Internal DBID OBID to DB/TS

106

System parameters in effect

107

Dataset open/close information

125

Rid list processing usage

221

Parallel degree for parallel group

222

Parallel group elapsed time

231

Parallel group completion

305

Table check constraints

311

Temporary tables

9

26

Work file obtained for sort

27

Number of ordered records sort run

28

Detailed sort information

95

Sort started

96

Sort ended

106

System parameters in effect

10

23

Utility start information

24

Utility object or phase change

25

Utility end information

90

Command text of entered DB2 command

91

Completion status of a DB2 command

105

Internal DBID OBID to DB/TS

106

System parameters in effect

107

Dataset open/close information

108

Beginning of bind/rebind

109

End of bind/rebind

110

Beginning of free plan

111

End of free plan

201

Status BEF/aft alter buffer pool

256

Attributes BEF/aft alter buffer pool

11

46

Agent begin execution unit switch

47

New SRB execution unit started

48

New SRB execution unit completed

49

Begin new TCB

50

End new TCB

51

Shared latch resume

52

Shared latch wait

56

Exclusive latch wait

57

Exclusive latch resume

93

Suspend was called

94

Event resumed

106

System parameters in effect

113

Attributes plan after agent allocation

12

98

Begin getmain/freemain (nonpool)

99

End getmain/freemain (nonpool)

100

Begin getmain/freemain (pool)

101

End getmain/freemain (pool)

106

System parameters in effect

13

11

Results of a validation exit call

12

Results edit exit call encode record

19

Results edit exit call decode a row

105

Internal DBID OBID to DB/TS

106

System parameters in effect

107

Dataset open/close information

14

67

Start of accounting collection

106

System parameters in effect

121

Entry allocating DB2 connection

122

Exit allocating DB2 connection

15

154

User-defined routine cond perf

16

157

DRDS interface with RDS RDI call types

158

DRDS interface with conversation manager

159

DRDS requesting location data

160

Requesting agent data

161

Serving agent data

162

Distributed transaction manager request agent data

163

Distributed transaction manager response agent data

167

Conversation allocation request queued

183

DRDS RDS/SCC interface data

17

211

Information about claims

212

Information about drains

213

Beginning of wait for drain lock

214

End of wait for drain lock

215

Beginning of wait of claim count to 0

216

End of claim count to go to 0

20

249

EDM pool DBD invalidation

250

Group buffer pool continued/discontinued

251

P-lock operations

256

Alter buffer pool command

257

Details of IRLM notify request

261

Group buffer pool checkpoint

262

Group buffer pool cast-out threshold processing

267

Begin CF struct rebuild/expand/contract

268

End CF structure rebuild/expand/contract

21

255

Buffer refresh due to XI

259

P-lock request/negotiation request

263

Page set and partition cast-out data

314

Authorization exit parameters

327

Language environment runtime information

Table 17-9. Statistics Trace

Class

IFCID

Description

1

1

System services

2

Database services

105

Internal DBID OBID to DB/TS

106

System parameters in effect

202

Buffer pool attributes

2

152

User-defined statistics trace

3

172

Units of work involved in deadlock

196

Lock timeout details

250

Connect/disconnect from GBP

258

Dataset extend information

330

Active log shortage

4

191

Data capture for DDIS errors

192

DDM-level 6a header errors

193

UOW disposition/sqlcode mismatch

194

Invalid SNA FMH-5 received

195

First failure data capture for DRDS

203

Heuristic decision occurred

204

Partner cold start detected

205

Incorrect logname/sync parameters

206

SNA compare states protocol error

207

Heuristic damage occurred

208

SNA sync point protocol error

209

Sync point communication failure

210

Log name changed on warm start

235

Conditional restart data loss

236

Exchange log names protocol error

238

DB2 restart error

267

Start of CF structure rebuild

268

End of CF structure rebuild

5

230

Data sharing global statistics

7

326

Workload manager delay monitor support


153 - Using DISPLAY Commands

Chapter 17. Application Performance and Optimization

Using DISPLAY Commands

A lot of the information you can get via the Accounting and Statistics reports can also be obtained using the DISPLAY command. The DISPLAY command can show details about current activity in the subsystem. Following are the different types of DISPLAYs:

  • DISPLAY ARCHIVE

  • DISPLAY BUFFERPOOL

  • DISPLAY DATABASE

  • DISPLAY FUNCTION SPECIFIC

  • DISPLAY GROUP

  • DISPLAY GROUPBUFFERPOOL

  • DISPLAY LOCATION

  • DISPLAY LOG

  • DISPLAY PROCEDURE

  • DISPLAY RLIMIT

  • DISPLAY THREAD

  • DISPLAY TRACE

  • DISPLAY UTILITY

NOTE

This type of information can also be viewed in the DB2 Control Center

For more information on all of the options on the DISPLAY command, refer to the IBM DB2 UDB for OS/390 Command ReferenceSC26-9934.


154 - Summary

Chapter 17. Application Performance and Optimization

Summary

Understanding the DB2 database environment is an important part of any database administrator's job. To gain this understanding, there are various facilities that can be used. There are several ways to analyze the database activity. Graphical monitoring tools, such as DB2PM and Visual Explain, can be used with DB2 Universal Database.

The DB2 optimizer is one of the most advanced in the relational database industry. The optimizer generates an access plan during query compilation. Access paths are stored in the system catalog tables for static SQL applications. Access paths for dynamic SQL statements are generated at query execution time and stored in memory.

To gain an understanding of the access path (strategy) chosen by the DB2 optimizer, the explain utility may be used. Explain populates a PLAN_TABLE and optional DSN tables with detailed information for the SQL statements. These tables can then be queried to determine the plan information regarding index usage and other database resources. This graphical version of the access path can be examined using Visual Explain.

In this chapter, the performance topics such as buffer pool tuning, sorting, database parameter tuning, and query parallelism were also discussed. Diagnostics and problem determination information is provided in DB2. This information comes in the form of SQLCODE, SQLSTATE codes, and traces.


156 - Appendix A. IBM Certified Solutions ExpertDB2 UDB Family Application Development

Part 5. Advanced Programming Functions

Appendix A. IBM Certified Solutions ExpertDB2 UDB Family Application Development

    Certification Test Objectives

    Sample Test


157 - Certification Test Objectives

Appendix A. IBM Certified Solutions ExpertDB2 UDB Family Application Development

Certification Test Objectives

The IBM certified solutions expert for DB2 UDB in application development requires an in-depth knowledge of the difference between programming types (ODBC, JDBC, OLEDB, Embedded SQL) and when to use the different programming types:

  • The difference between embedded dynamic and static SQL

  • Basic and intermediate SQL

  • Concepts and usage of binding and prepping, isolation levels, basic database objects, and data types (schema, naming conventions)

  • Transaction concepts (commit scope, states) and cursor concepts

Furthermore, the solutions expert in application development should have a basic knowledge of

  • Diagnostic information

  • Advanced SQL (recursive, DDL, temporary tables, and compound)

  • Locking

  • Privileges and authorities

  • SQL routines and functions

  • Complex database objects (UDTs, UDFs, triggers)

  • SQLDA

  • SQLCA

  • Host variables

  • Parameter markers

  • Connection types

  • Transaction manager

The following are some of the topics covered on the exam.

I. Database Objects

  • Knowledge of naming conventions of DB2 objects (aliases, views, etc.)

  • Knowledge of the authorities needed to access data in an application

  • Knowledge of complex database objects (temporary tables, summary tables, triggers)

II. Data Manipulation

  • Ability to query database across multiple tables

  • Ability to query tables across multiple databases (federated databases)

  • Knowledge of changing data

  • Ability to use DB2 SQL functions

  • Ability to use common table expressions

  • Knowledge to identify when to use cursors in a SQL program

  • Knowledge to identify types of cursors

  • Knowledge to identify the scopes of cursors

  • Ability to manipulate cursors

  • Ability to manage a unit of work (transaction management)

III. DB2 Programming Methods

  • Knowledge to identify the differences between dynamic and static embedded SQL

  • Skill in determining when to use CLI/ODBC

  • Skill in determining when to use JDBC and SQLJ

  • Ability to determine when to use SQL routines and functions

  • Ability to determine when to use OLEDB

IV. Embedded SQL Programming

  • Knowledge of identifying steps and output involved in creating an embedded SQL programming application

  • Knowledge to identify when host variables are used begin-declare)

  • Skill in declaring host variables

  • Skill in utilizing host variable in queries

  • Ability to explain and analyze the content of the SQLCA

  • Knowledge of common errors, prep, and BIND database programs

  • Ability to connect to databases within an embedded SQL programming application

V. ODBC/CLI Programming

  • Knowledge of the different handle types

  • Knowledge of configuring DB2 ODBC driver

  • Knowledge of problem determination (diagnostic records)

  • Knowledge of the correct sequence for calling ODBC/CLI functions

  • Knowledge of various CLI cursor types and when to use them

  • Ability to connect to databases within an ODBC/CLI programming application

VI. JAVA Programming

  • Knowledge of various JDBC objects

  • Knowledge of the difference between SQLJ and JDBC

  • Knowledge of problem determination (JDBC trace, SQL exceptions, and JDBC error log)

  • Skill in performing the steps to build SQLJ applications

  • Ability to connect to databases within a JAVA programming application

  • Ability to manage transactions across multiple databases (JTA)

  • Ability to determine which connection types should be used to connect to the database

VII. Advanced Programming

  • Ability to utilize dynamic and static SQL within programs

  • Skill in casting UDTs within a program

  • Knowledge to identify when to use Compound SQL

  • Knowledge of concurrency considerations within an application

  • Knowledge of distributed unit of work

  • Knowledge of using parameter markers

  • Ability to determine the approaches to programming using Unicode

  • Ability to use performance enhancement features (CLI Load, buffered inserts)

VIII. Stored Procedures and User-Defined Routines

  • Knowledge to identify usage of UDFs

  • Knowledge to identify when to use stored procedures

  • Skill in using the DB2 Development Center

  • Knowledge of programming languages using the DB2 Development Center


158 - Sample Test

Appendix A. IBM Certified Solutions ExpertDB2 UDB Family Application Development

Sample Test

Below is a sample test that has questions very similar to those on the actual 514 exam.

1:

Given that the message "QUALIFY.X" is an undefined name is returned during a precompile, which of the following is true for QUALIFY.X?

  1. It is defined as a database object.

  2. It is defined as an "undefined" name.

  3. It is not defined as a host variable in the program.

  4. It is not defined as a database object in the database.
A1:

D

2:

Given a table created using the statement CREATE TABLE abc.stuff (i INT), a user called XYZ is to be enabled to access data from table ABC.STUFF using an implicit schema. Assuming the necessary privileges have been granted, which of the following statements issued by user ABC will provide this result?

  1. CREATE ALIAS xyz.stuff FOR abc.stuff

  2. CREATE VIEW abc.stuff FOR xyz.stuff

  3. CREATE ALIAS abc.stuff FOR xyz.stuff

  4. CREATE VIEW stuff AS SELECT i FROM abc.stuff
A2:

A

3:

The FINANCE application contains static SQL and issues the statements

SELECT name, id FROM prod.employee
UPDATE prod.dept SET dept=dept+1
INSERT INTO prod.dept VALUES(:id, :name)

Assuming a user can connect to the database, but has no other privileges or authorities, which of the following privileges must be granted to the user so that the application FINANCE can be run by a user?

  1. EXECUTE privilege on FINANCE

  2. RUN privilege on tables EMPLOYEE and DEPT

  3. EXECUTE privilege on tables EMPLOYEE and DEPT

  4. CONTROL privilege on tables EMPLOYEE and DEPT
A3:

A

4:

Which of the following privileges is required to successfully execute a DB2 Call Level Interface application?

  5. The user must have EXECUTE privilege on the application.

  6. The developer must have EXECUTE privilege on the application.

  7. The user must have sufficient privileges on referenced tables.

  8. The developer must have sufficient privileges on referenced tables.
A4:

C

5:

Assume that the following SQL statements have been successfully issued:

CONNECT TO db1 USER user1 USING pw1
DECLARE GLOBAL TEMPORARY TABLE temp1 (val INTEGER)

Which of the following statements will successfully insert a row into the temporary table TEMP1?

  1. INSERT INTO db1.temp1 VALUES (100)

  2. INSERT INTO user1.temp1 VALUES (100)

  3. INSERT INTO session.temp1 VALUES (100)

  4. INSERT INTO temporary.temp1 VALUES (100)
A5:

C

6:

Given the tables

EMPLOYEE                                DEPT
emp_num   emp_name  dept                dept_id      dept_name
  1         Adams     1                   1           Planning
  2         Jones     1                   2            Support
  3         Smith     2
  4         Williams  1

and the statement

ALTER TABLE employee
  ADD FOREIGN KEY (dept) REFERENCES dept (dept_id)
  ON DELETE CASCADE

how many rows will be deleted with the following statement?

EXEC SQL DELETE FROM dept WHERE dept_id=1

  1. 0

  2. 1

  3. 2

  4. 3

  5. 4

  6. 6
A6:

E

7:

Given the tables

COUNTRY                                      STAFF
  id  name       person cities               id   name
  1   Argentina  1      10                   1    Aaron
  2   Canada     2      20                   2    Adams
  3   Cuba       2      10
  4   Germany    1       0
  5   France     7       5

and the code

EXEC SQL DECLARE CURSOR C1 FOR
    SELECT b.name, cities
    FROM country a, staff b
    WHERE a.person=b.id
    ORDER BY 1,2;
EXEC SQL OPEN C1;
EXEC SQL FETCH C1 INTO :name1:n_ni, :city1:c_ni;
EXEC SQL FETCH C1 INTO :name1:n_ni, :city1:c_ni;
EXEC SQL FETCH C1 INTO :name1:n_ni, :city1:c_ni;

which of the following is the value of :city1 after the third FETCH?

  1. 0

  2. 1

  3. 2

  4. 10

  5. 20
A7:

D

8:

Given the tables

PRICE                               SALE
  item description cost code        sale_id    salefactor
  1    camera      10   2              1       2
  2    watch        5   1              2       3
  3    shirt       20   1

and the SQL statement

SELECT a.cost, (a.cost * b. salefactor) AS saleprice
  FROM sale b, price a
  WHERE a.code=b.sale_id
  ORDER BY a.cost

which of the following is the value of SALEPRICE in the second row of the result set returned by the above query?

  1. 10

  2. 15

  3. 20

  4. 30

  5. 40
A8:

D

9:

Given the tables:

ORG                                  STAFF
  id   name         person           id   name
  1    Programming    1              1    Aaron
  2    Testing        2              2    Adams
  2    Testing        3              3    Jones

and the code

stmt="DELETE FROM staff WHERE name='Adams' ";
EXEC SQL EXECUTE IMMEDIATE :stmt;

if a referential integrity constraint with the SET NULL option exists between person in ORG and id in STAFF, how many rows will be deleted?

  1. 0

  2. 1

  3. 2

  4. 3
A9:

B

10:

Which of the following CLI/ODBC functions will return the number of rows affected by an INSERT, UPDATE, or a DELETE statement?

  1. SQLNumRows()

  2. SQLRowCount()

  3. SQLNumParams()

  4. SQLUpdateCount()

  5. SQLNumResultCols()_
A10:

B

11:

Given the following code from a SQLJ source file,

Connection con = DriverManager.getConnection(url);
DefaultContext ctx = new DefaultContext(con);
DefaultContext.setDefaultContext(ctx);

an UPDATE statement is issued using the ctx context. Which of the following SQLJ methods must be used to obtain the number of rows modified by the UPDATE statement?

  1. ctx.rowsUpdated()

  2. ctx.SQLRowCount()

  3. ctx.getUpdateCount()

  4. con.getUpdateCount()
A11:

C

12:

In order to bind application variables to data in the result set, which two of the following CLI/ODBC functions are used?

  1. SQLFetch()

  2. SQLBindCol()

  3. SQLGetData()

  4. SQLBindResult()

  5. SQLBindParameter()
A12:

B & E

13:

Which of the following function types can only be specified in the FROM clause of a SELECT statement?

  1. TABLE function

  2. COLUMN function

  3. SCALAR function

  4. SELECT function
A13:

A

14:

Which of the following is similar to a common table expression?

  1. A temporary view

  2. A correlated query

  3. A qualified predicate

  4. An update statement
A14:

A

15:

Given the following statement,

DECLARE cursor1 CURSOR FOR
SELECT firstname, lastname, street, city FROM citytable

which of the following SQL statements will retrieve a row using the defined cursor?

  1. FETCH cursor1 INTO :hvfirst :hvlast :hvstreet :hvcity

  2. SELECT cursor1 INTO :hvfirst :hvlast :hvstreet :hvcity

  3. FETCH cursor1 INTO :hvfirst, :hvlast, :hvstreet, :hvcity

  4. SELECT cursor1 INTO :hvfirst, :hvlast, :hvstreet, :hvcity
A15:

C

16:

Given the code

EXEC SQL UPDATE t1 SET column1 = :col WHERE CURRENT OF C1;

which of the following indicates how the cursor C1 has been defined?

  1. As a normal cursor

  2. As a with hold cursor

  3. As a fetch only cursor

  4. As an updateable cursor
A16:

D

17:

Which of the following defines when a cursor is considered a deleteable cursor?

  1. When the DECLARE CURSOR includes a FOR FETCH ONLY clause

  2. When the DECLARE CURSOR select statement includes an ORDER BY

  3. When the DECLARE CURSOR select statement includes a HAVING clause

  4. When the DECLARE CURSOR select statement references one base table
A17:

D

18:

Given the pseudocode

DECLARE CURSOR C1
DECLARE CURSOR C2
OPEN C1
FETCH C1
OPEN C2
COMMIT
FETCH C2

which of the following changes will ensure that the FETCH C2 is successful?

  1. BLOCKING ALL during bind

  2. WITH HOLD on COMMIT statement

  3. WITH HOLD on DECLARE CURSOR C2

  4. WITH HOLD on OPEN C2 statement
A18:

C

19:

Which of the following is a characteristic of all cursors in embedded SQL?

  1. Cannot span units of work

  2. Can be reserved in the database

  3. Must be unique within a source module

  4. Must be unique for all applications against a database
A19:

C

20:

A cursor called c2 must be created to fetch rows from table t2 and update column c1 in table t2 for every row fetched. Which of the following cursor definitions will create this type of cursor?

  1. DECLARE c2 CURSOR WITH HOLD FOR SELECT * FROM t2;

  2. DECLARE c2 CURSOR FOR SELECT * FROM t2 FOR UPDATE OF t2;

  3. DECLARE c2 CURSOR FOR SELECT * FROM t2 FOR UPDATE OF c2;

  4. DECLARE c2 CURSOR FOR SELECT * FROM c1 FOR UPDATE OF c1;

  5. DECLARE c2 CURSOR FOR SELECT * FROM t2 FOR UPDATE OF c1;
A20:

E

21:

Given a cursor c1 on table t1, for every row fetched from t1, open a cursor c2 on table t2. For every row fetched from t2, update column c1 in table t2 and issue a COMMIT. Which of the following must define cursor c1?

  1. DECLARE c1 CURSOR FOR SELECT * FROM t1;

  2. DECLARE c1 CURSOR WITH HOLD FOR SELECT * FROM t1;

  3. DECLARE c1 CURSOR FOR SELECT * FROM t1 FOR UPDATE OF t2;

  4. DECLARE c1 CURSOR FOR SELECT * FROM t1 FOR UPDATE OF c1;
A21:

B

22:

Given a table that has columns defined,

SMALLINT_COLUMN SMALLINT NOT NULL
VARCHAR_COLUMN VARCHAR(20)

which of the following statements is used to retrieve rows from the table if the second column can contain null values?

  1. FETCH * INTO :hv1, :hv2;

  2. FETCH CURSOR1 INTO :hv1, :hv2;

  3. FETCH * INTO :hv1, :hv2:hv2ind;

  4. FETCH CURSOR1 INTO :hv1, :hv2:hv2ind;
A22:

D

23:

Which two of the following are required for the DB2 Optimizer to consider a star join?

  1. At least four tables must be joined.

  2. More than one table can be considered to be a fact table.

  3. The fact and dimension tables must contain the same columns.

  4. A single-column index must be defined on each join-column of the fact table.

  5. The fact table must be joined to at least three dimension tables.
A23:

D

24:

Which of the following DB2 application development methods/environments must not be used when enabling end users to choose which tables to select data from at application runtime?

  1. CLI

  2. ODBC

  3. Net.Data

  4. Embedded static SQL

  5. Embedded dynamic SQL
A24:

D

25:

During which of the following are SQL statements optimized when using DB2 CLI?

  1. precompile

  2. bind processing

  3. statement preparation

  4. the closing of each cursor
A25:

C

26:

In order to access a DB2 database from a workstation that does not have any DB2 code installed, which of the following must be used?

  1. Triggers

  2. Constraints

  3. Java Applet

  4. Java stored procedure
A26:

C

27:

Which of the following programming methods does NOT lend itself to accessing DB2 data over the Internet using Web browser based clients?

  1. Net.Data

  2. SQLJ Applets

  3. JDBC Applets

  4. SQLJ Applications
A27:

D

28:

Which of the following statements allows an SQL routine to be created?

  1. CREATE VIEW

  2. CREATE ROUTINE

  3. CREATE TRIGGER

  4. CREATE PROCEDURE
A28:

D

29:

In order to process an embedded SQL (non-REXX) program, which of the following database components is required?

  1. Binder

  2. Precompiler

  3. Control Center

  4. Visual Explain
A29:

B

30:

Which of the following static SQL statements can contain a host variable?

  1. FETCH

  2. ROLLBACK

  3. DROP INDEX

  4. ALTER TABLE
A30:

A

31:

Which of the following SQL statements require a host variable within the statement?

  1. DELETE

  2. DECLARE

  3. INSERT INTO

  4. SELECT INTO
A31:

D

32:

Which of the following data types must be used for a host variable that will be used to retrieve a TIMESTAMP from the database?

  1. A decimal

  2. An integer numeric

  3. A character string

  4. A float (scientific notation)
A32:

C

33:

Given the following,

EXEC SQL BEGIN DECLARE SECTION;
     char hv_name[20];
EXEC SQL END DECLARE SECTION;

which of the following examples correctly demonstrates the use of the host variable within a SQL statement?

  1. EXEC SQL name_column INTO :hv<name

  2. EXEC SQL SELECT name_column INTO :hv_name

  3. EXEC SQL SELECT name_column INTO^:hv_name

  4. SELECT firstnme FROM employee WHERE lastnme = :?
A33:

B

34:

Which of the following SQLCA elements contains the number of rows affected by the SQL statement?

  1. sqlcabc

  2. sqlcode

  3. sqlerrp

  4. sqlerrd

  5. sqlstate

  6. sqlerrml
A34:

D

35:

A package was created by DB2ADMIN, and the bind file or DBRM contains only dynamic SQL statements. Also, the package to be created already exists. Which of the following privileges does the user DB2USER require in order to perform the BIND command on this package?

  1. BINDADD

  2. DB2ADMIN

  3. ALTERIN on schema DB2USER

  4. CREATEIN on schema DB2ADMIN

  5. IMPLICIT_SCHEMA on schema DB2ADMIN
A35:

C

36:

Which of the following is required when using the REBIND command?

  1. The database

  2. The bind file

  3. The application source

  4. The application executable
A36:

A

37:

Given the following embedded SQL pseudocode,

Start Program
EXEC SQL BEGIN DECLARE SECTION
  USERA     CHARACTER (8)
  USERB     CHARACTER (8)
  PW        CHARACTER (8)
  COLVAL    CHARACTER (16)
EXEC SQL END DECLARE SECTION

EXEC SQL INCLUDE SQLCA
EXEC SQL WHENEVER SQLERROR GOTO ERRCHK

  (program logic)
  (:usera contains the string "usera")
  (:pwa contains a valid password)
  (:userb now contains the string "userb")
  (:pwb contains a valid password)

EXEC SQL CONNECT TO samplea USER :usera USING :pwa

EXEC SQL SELECT col1, col2 FROM tablea

  (program logic to retrieve results)

EXEC SQL COMMIT

  (more program logic)

EXEC SQL CONNECT TO sampleb USER :userb USING :pwb
EXEC SQL SELECT col1, col2 FROM tablex
EXEC SQL DELETE FROM tablea WHERE col1= :colval  //1st delete
EXEC SQL COMMIT

  (more program logic)

EXEC SQL CONNECT TO samplea
EXEC SQL DELETE from tablea where col1= :colval  //2nd delete
EXEC SQL COMMIT
EXEC SQL CONNECT RESET
ERRCHK

  (check error information in SQLCA)
  (Cleanup)

End Program

which of the following tables will be updated in "samplea" if the second DELETE completes sucessfully?

  1. usera.tablex

  2. userb.tablea

  3. usera.tablea

  4. userb.tablex
A37:

C

38:

Which of the following limits the number of concurrent CLI statement handles that can be in use on a given connection?

  1. Unlimited

  2. Limited to 10 statements

  3. The number of concurrent connections

  4. The number of sections in the CLI packages
A38:

D

39:

Which of the following describes where a DSN (data source name) can be registered prior to its use in connecting from a CLI/ODBC application?

  1. In the DCS directory

  2. In the node directory

  3. With the DB2 CLI/ODBC driver

  4. With the ODBC driver manager
A39:

D

40:

For which of the following handle types would you call SQLERROR after SQLExecDirect returns a SQLERROR.

  1. Exception

  2. Statement

  3. Connection

  4. Descriptor

  5. Environment
A40:

B

41:

Which of the following ODBC/CLI functions must be called before SQLExecDirect can be successfully executed if the SQL statement contains parameter markers?

  1. SQLColumns

  2. SQLParamData

  3. SQLBindParameter

  4. SQLExtendedPrepare
A41:

C

42:

Given the following table and SQL statement,

Table A
Column1
-------
R1
R2
R3
R4
R5
R6

SELECT * FROM tablea ORDER BY column1

using a keyset-driven cursor with a rowset size of 3, which of the following rows are returned when the following ODBC APIs are issued in the order below?

1) SQLFetchScroll with the SQL_FETCH_FIRST option
2) SQLFetchScroll with the SQL_FETCH_RELATIVE option, offset=1
3) SQLFetchScroll with the SQL_FETCH_ABSOLUTE option, offset=3

  1. R1,R2,R3,R2,R3,R4

  2. R1,R2,R3,R4,R5,R6

  3. R1,R2,R3,R2,R3,R4,R3,R4,R5

  4. R1,R2,R3,R4,R5,R6,R3,R4,R5
A42:

D

43:

Which SQLDriverConnect DriverCompletion option will result in the return code SQL_ERROR if a required field is not supplied in the connection string?

  1. SQL_DRIVER_PROMPT

  2. SQL_DRIVER_NOPROMPT

  3. SQL_DRIVER_COMPLETE

  4. SQL_DRIVER_COMPLETE_REQUIRED
A43:

B

44:

Which of the following JDBC objects are queried to determine the indexes defined on a given table?

  1. ResultSet

  2. Statement

  3. Connection

  4. DatabaseMetaData

  5. CallableStatement
A44:

D

45:

Which of the following JDBC objects must be queried to determine the SQLSTATE in the event an SQL operation fails?

  1. ResultSet

  2. Statement

  3. Exception

  4. Connection

  5. SQLException
A45:

E

46:

Which of the following is a required parameter for running db2profc?

  1. user ID

  2. password

  3. prep options

  4. profile name
A46:

D

47:

Which of the following can be used to specify a user ID and password when connecting to a remote database called sample from an SQLJ application?

  1. #sql con={CONNECT TO SAMPLE :userid :password}

  2. getConnection("jdbc:db2:sample",userid,password)

  3. getConnection("jdbc:db2:sample/userid:password")

  4. #sql con={CONNECT TO SAMPLE USER :userid USING :password}
A47:

B

48:

Which of the following code fragments correctly performs a static SELECT statement of the integer column C1 from table T1? (Assume that the host variable hv has the proper type.)

  1. EXEC SQL SELECT c1 FROM t1 USING cur
EXEC SQL FETCH cur INTO :hv
EXEC SQL CLOSE cur

  2. EXEC SQL OPEN cur FOR SELECT c1 FROM t1
EXEC SQL FETCH cur INTO :hv
EXEC SQL CLOSE cur

  3. EXEC SQL DECLARE cur CURSOR FOR SELECT c1 FROM t1
EXEC SQL OPEN cur
EXEC SQL FETCH cur INTO :hv
EXEC SQL CLOSE cur

  4. EXEC SQL PREPARE stmt FOR SELECT c1 FROM t1
        EXEC SQL DECLARE cur CURSOR FOR stmt
        EXEC SQL OPEN cur
        EXEC SQL FETCH cur INTO :hv
        EXEC SQL CLOSE cur_
A48:

C

49:

Which of the following statements uses dynamic SQL?

  1. EXEC SQL DECLARE c1 CURSOR FOR s1

  2. EXEC SQL UPDATE c1 SET name = :name

  3. EXEC SQL SELECT name INTO :name FROM t1

  4. EXEC SQL DECLARE c1 CURSOR FOR SELECT name FROM t1
A49:

A

50:

Which of the following is used to convert between a user-defined distinct type and its source type?

  1. CAST function

  2. COALESCE function

  3. BUILT- IN SQL function

  4. USER DEFINED function
A50:

A

51:

Which of the following is not a type of UDF?

  1. Table

  2. Column

  3. Scalar

  4. Summary
A51:

D

52:

An application needs to retrieve a large number of rows from a database across the network and compute a single value from the retrieved data. Which of the following methods will reduce the network traffic?

  1. Stored procedure

  2. Table constraints

  3. User-defined types

  4. Combine all rows into a LOB
A52:

A

53:

Given the code

BEGIN COMPOUND NOT ATOMIC STATIC
  UPDATE country SET cities = :count WHERE CURRENT OF C1;
  INSERT INTO country VALUES (:col1, :col2, :col3);
  INSERT INTO country VALUES (:col4, :col5, :col6);
  INSERT INTO country VALUES (:col7, :col8, :col9);
  INSERT INTO country VALUES (:col10, :col11, :col12);
  COMMIT;
END COMPOUND

if the fifth SQL statement in the block fails, how many rows will be affected in table country?

  1. 0

  2. 1

  3. 2

  4. 3

  5. 4

  6. 5
A53:

E

54:

Which of the following indicates when a table cannot be locked explicitly?

  1. When using DDL

  2. If it is a catalog table

  3. If it is from a specific application

  4. If other users must have access to the table
A54:

B

55:

Application A is bound using cursor stability, updates row X, and does not issue a COMMIT. Application B reads row X. Which of the following isolation levels must application B be using?

  1. Read stability

  2. Repeatable read

  3. Cursor stability

  4. Uncommitted read
A55:

D

56:

Which of the following operating systems can the Stored Procedure Builder run on?

  1. Windows, AIX, HP/UX

  2. Windows, AIX, Linux

  3. OS/2, Windows, Linux

  4. Windows, AIX, Solaris
A56:

D

57:

Which of the following is not available in a distributed unit of work?

  1. IMPORT

  2. UPDATE

  3. INSERT

  4. DELETE

  5. COMMIT
A57:

A

58:

Which of the following demonstrates a correct usage of parameter markers?

  1. CALL outsrv( ?, ? )

  2. SELECT col1, col2 FROM tab1 WHERE tab1.? = 15

  3. SELECT count(*) FROM foo.tab1 WHERE col1 = '?'

  4. SELECT firstnme FROM employee WHERE lastnme = :?
A58:

A


159 - Chapter B. Resources

Part 5. Advanced Programming Functions

Chapter B. Resources

    DB2 Universal Database Server for OS/390 v7 Product Libraries


004 - DB2 Universal Database Server for OS/390 v7 Product Libraries

Chapter B. Resources

DB2 Universal Database Server for OS/390 v7 Product Libraries

DB2 Universal Database for OS/390

  • DB2 Administration Guide, SC26-9931

  • DB2 Application Programming and SQL Guide, SC26-9933

  • DB2 Application Programming Guide and Reference for Java ™, SC26-9032

  • DB2 Command Reference, SC26-9934

  • DB2 Data Sharing: Planning and Administration, SC26-9935

  • DB2 Data Sharing Quick Reference Card, SX26-3846

  • DB2 Diagnosis Guide and Reference, LY37-3740

  • DB2 Diagnostic Quick Reference Card, LY37-3741

  • DB2 Image, Audio, and Video Extenders Administration and Programming, SC26-9947

  • DB2 Installation Guide, GC26-9936

  • DB2 Licensed Program Specifications, GC26-9938

  • DB2 Master Index, SC26-9939

  • DB2 Messages and Codes, GC26-9940

  • DB2 ODBC Guide and Reference, SC26-9941

  • DB2 Reference for Remote DRDA Requesters, and Servers, SC26-9942

  • DB2 Reference Summary, SX26-3847

  • DB2 Release Planning Guide, SC26-9943

  • DB2 SQL Reference, SC26-9944

  • DB2 Text Extender Administration and Programming, SC26-9948

  • DB2 Utility Guide and Reference, SC26-9945

  • DB2 What's New? GC26-9946

  • DB2 Universal Database for OS/390 XML Extender Administration and Programming SC27-9949

  • DB2 Program Directory, GI10-8182

DB2 Administration Tool

  • DB2 Administration Tool for OS/390 User's Guide, SC26-9847

DB2 Buffer Pool Tool

  • DB2 Buffer Pool Tool for OS/390 User's Guide and Reference, SC26-9306

DB2 DataPropagator

  • DB2 Replication Guide and Reference, SC26-9642

Net.Data for OS/390

The following books are available at http://www.ibm.com/software/net.data/library.html.

  • Net.Data Library: Administration and Programming Guide for OS/390

  • Net.Data Library: Language Environment Interface Reference

  • Net.Data Library: Messages and Codes Net.Data Library: Reference

DB2 PM for OS/390

  • DB2 PM for OS/390 Batch User's Guide, SC26-9167

  • DB2 PM for OS/390 Command Reference, SC26-9166

  • DB2 PM for OS/390 Data Collector Application Programming Interface Guide, SC27-0861-00

  • DB2 PM for OS/390 General Information, GC26-9172

  • DB2 PM for OS/390 Installation and Customization, SC26-9171

  • DB2 PM for OS/390 Messages, SC26-9169

  • DB2 PM for OS/390 Online Monitor User's Guide, SC26-9168

  • DB2 PM for OS/390 Report Reference Volume 1, SC26-9164

  • DB2 PM for OS/390 Report Reference Volume 2, SC26-9165

  • DB2 PM for OS/390 Using the Workstation Online Monitor, SC26-9170

  • DB2 PM for OS/390 Program Directory, GI10-8183

Query Management Facility

  • Query Management Facility: Developing QMF Applications, SC26-9579

  • Query Management Facility: Getting Started with QMF on Windows, SC26-9582

  • Query Management Facility: High Performance Option User's Guide for OS/390, SC26-9581

  • Query Management Facility: Installing and Managing QMF on OS/390, GC26-9575

  • Query Management Facility: Installing and Managing QMF on Windows, GC26-9583

  • Query Management Facility: Introducing QMF, GC26-9576

  • Query Management Facility: Messages and Codes, GC26-9580

  • Query Management Facility: Reference, SC26-9577

  • Query Management Facility: Using QMF, SC26-9578

Ada/370

  • IBM Ada/370 Language Reference, SC09-1297

  • IBM Ada/370 Programmer's Guide, SC09-1414

  • IBM Ada/370 SQL Module Processor for DB2 Database Manager User's Guide, SC09-1450

APL2

  • APL2 Programming Guide, SH21-1072

  • APL2 Programming: Language Reference, SH21-1061

  • APL2 Programming: Using Structured Query Language (SQL), SH21-1057

AS/400

  • DB2 for OS/400 SQL Programming, SC41-4611

  • DB2 for OS/400 SQL Reference, SC41-4612

BASIC

  • IBM BASIC/MVS Language Reference, GC26-4026

  • IBM BASIC/MVS Programming Guide, SC26-4027

BookManager READ/MVS

  • BookManager READ/MVS V1R3: Installation Planning & Customization, SC38-2035

C/370

  • IBM SAA AD/Cycle C/370 Programming Guide, SC09-1841

  • IBM SAA AD/Cycle C/370 Programming Guide for Language Environment/370, SC09-1840

  • IBM SAA AD/Cycle C/370 User's Guide, SC09-1763

  • SAA CPI C Reference, SC09-1308

Character Data Representation Architecture

  • Character Data Representation Architecture Overview, GC09-2207

  • Character Data Representation Architecture Reference and Registry, SC09-2190

CICS/ESA

  • CICS/ESA Application Programming Guide, SC33-1169

  • CICS for MVS/ESA Application Programming Reference, SC33-1170

  • CICS for MVS/ESA CICS-RACF Security Guide, SC33-1185

  • CICS for MVS/ESA CICS-Supplied Transactions, SC33-1168

  • CICS for MVS/ESA Customization Guide, SC33-1165

  • CICS for MVS/ESA Data Areas, LY33-6083

  • CICS for MVS/ESA Installation Guide, SC33-1163

  • CICS for MVS/ESA Intercommunication Guide, SC33-1181

  • CICS for MVS/ESA Messages and Codes, GC33-1177

  • CICS for MVS/ESA Operations and Utilities Guide, SC33-1167

  • CICS/ESA Performance Guide, SC33-1183

  • CICS/ESA Problem Determination Guide,SC33-1176

  • CICS for MVS/ESA Resource Definition Guide, SC33-1166

  • CICS for MVS/ESA System Definition Guide, SC33-1164

  • CICS for MVS/ESA System Programming Reference, GC33-1171

CICS/MVS

  • CICS/MVS Application Programmer's Reference, SC33-0512

  • CICS/MVS Facilities and Planning Guide, SC33-0504

  • CICS/MVS Installation Guide, SC33-0506

  • CICS/MVS Operations Guide, SC33-0510

  • CICS/MVS Problem Determination Guide, SC33-0516

  • CICS/MVS Resource Definition (Macro), SC33-0509

  • CICS/MVS Resource Definition (Online), SC33-0508

CICS Transaction Server for OS/390

  • CICS Application Programming Guide, SC33-1687

IBM C/C++ for MVS/ESA

  • IBM C/C++ for MVS/ESA Library Reference, SC09-1995

  • IBM C/C++ for MVS/ESA Programming Guide, SC09-1994

IBM COBOL

  • IBM COBOL Language Reference, SC26-4769

  • IBM COBOL for MVS & VM Programming Guide, SC26-4767

  • IBM COBOL for OS/390 & VM Programming Guide, SC26-9049

  • Conversion Guide IMS-DB and DB2 Migration and Coexistence Guide, GH21-1083

Cooperative Development Environment

  • Cooperative Development Environment/370: Debug Tool, SC09-1623

Data Extract (DXT)

  • Data Extract Version 2: General Information, GC26-4666

  • Data Extract Version 2: Planning and Administration Guide, SC26-4631

DataPropagator NonRelational

  • DataPropagator NonRelational MVS/ESA Administration Guide, SH19-5036

  • DataPropagator NonRelational MVS/ESA Reference, SH19-5039

Data Facility Data Set Services

  • Data Facility Data Set Services: User's Guide and Reference, SC26-4388

Database Design

  • Handbook of Relational Database Design, C. Fleming and B. Von Halle, Addison Wesley, ISBN 0-20111-434-8

  • DB2 High Performance Design, R. Yevich and S. Lawson, ISBN 0-13-203795-5

DataHub

  • IBM DataHub General Information, GC26-4874

DB2 Connect

  • DB2 Connect Enterprise Edition for OS/2 and Windows NT: Quick Beginnings, GC09-2828

  • DB2 Connect Personal Edition Quick Beginnings, GC09-2830

  • DB2 Connect User's Guide, SC09-2838

DB2 Red Books

  • DB2 UDB Server for OS/390 Version 6 Technical Update, SG24-6108-00

  • DB2 Server for VSE &VM

  • DB2 Server for VM: DBS Utility, SC09-2394

  • DB2 Server for VSE: DBS Utility, SC09-2395

DB2 Universal Database (DB2 UDB)

  • DB2 UDB Administration Guide Volume 1: Design and Implementation, SC09-2839

  • DB2 UDB Administration Guide Volume 2: Performance, SC09-2840

  • DB2 UDB Administrative API Reference, SC09-2841

  • DB2 UDB Application Building Guide, SC09-2842

  • DB2 UDB Application Development Guide, SC09-2845

  • DB2 UDB Call Level Interface Guide and Reference, SC09-2843

  • DB2 UDB SQL Getting Started, SC09-2856

  • DB2 UDB SQL Reference Volume 1, SC09-2847

  • DB2 UDB SQL Reference Volume 2, SC09-2848

Device Support Facilities

  • Device Support Facilities User's Guide and Reference, GC35-0033

DFSMS/MVS

  • DFSMS/MVS: Access Method Services for the Integrated Catalog, SC26-4906

  • DFSMS/MVS: Access Method Services for VSAM Catalogs, SC26-4905

  • DFSMS/MVS: Administration Reference for DFSMSdss, SC26-4929

  • DFSMS/MVS: DFSMShsm Managing Your Own Data, SH21-1077

  • DFSMS/MVS: Diagnosis Reference for DFSMSdfp, LY27-9606

  • DFSMS/MVS Storage Management Library: Implementing System-Managed Storage, SC263123

  • DFSMS/MVS: Macro Instructions for Data Sets, SC26-4913

  • DFSMS/MVS: Managing Catalogs, SC26-4914

  • DFSMS/MVS: Program Management, SC26-4916

  • DFSMS/MVS: Storage Administration Reference for DFSMSdfp, SC26-4920

  • DFSMS/MVS: Using Advanced Services, SC26-4921

  • DFSMS/MVS: Utilities, SC26-4926

  • MVS/DFP: Using Data Sets, SC26-4749

DFSORT

  • DFSORT Application Programming: Guide, SC33-4035

Distributed Relational Database Data

  • Stream and OPA Reference, SC31-6806

  • IBM SQL Reference, SC26-8416

  • Open Group Technical Standard (the Open Group presently makes the following books available through its Web site at http://www.opengroup.org):

    - DRDA Volume 1: Distributed Relational Database Architecture (DRDA), Document number C911

    - DRDA Volume 2: Formatted Data Object Content Architecture, Document number C912

    - DRDA Volume 3: Distributed Database Management (DDM) Architecture, Document number C913

Domain Name System

  • DNS and BIND, 3rd Edition, Paul Albitz and Cricket Liu, O'Reilly, ISBN 1-56592-512-2

Education

  • IBM Dictionary of Computing, McGraw-Hill, ISBN 0-07031-489-6

  • 1999 IBM All-in-One Education and Training Catalog, GR23-8105

Enterprise System/9000 and Enterprise System/3090

  • Enterprise System/9000 and Enterprise System/3090 Processor Resource/System Manager Planning Guide, GA22-7123

High Level Assembler

  • High Level Assembler for MVS and VM and VSE Language Reference, SC26-4940

  • High Level Assembler for MVS and VM

  • VSE Programmer's Guide, SC26-4941

Parallel Sysplex Library

  • OS/390 Parallel Sysplex Application Migration, GC28-1863

  • System/390 MVS Sysplex Hardware and Software Migration, GC28-1862

  • OS/390 Parallel Sysplex Overview: An Introduction to Data Sharing and Parallelism, GC28-1860

  • OS/390 Parallel Sysplex Systems Management, GC28-1861

  • OS/390 Parallel Sysplex Test Report, GC28-1963

  • System/390 9672/9674 System Overview, GA22-7148

ICSF/MVS

  • ICSF/MVS General Information, GC23-0093 IMS/ESA

  • IMS Batch Terminal Simulator General Information, GH20-5522

  • IMS/ESA Administration Guide: System, SC26-8013

  • IMS/ESA Administration Guide: Transaction Manager, SC26-8731

  • IMS/ESA Application Programming: Database Manager, SC26-8727

  • IMS/ESA Application Programming: Design Guide, SC26-8016

  • IMS/ESA Application Programming: Transaction Manager, SC26-8729

  • IMS/ESA Customization Guide, SC26-8020

  • IMS/ESA Installation Volume 1: Installation and Verification, SC26-8023

  • IMS/ESA Installation Volume 2: System Definition and Tailoring, SC26-8024

  • IMS/ESA Messages and Codes, SC26-8028

  • IMS/ESA Operator's Reference, SC26-8030

  • IMS/ESA Utilities Reference: System, SC26-8035

ISPF

  • ISPF V4 Dialog Developer's Guide and Reference, SC34-4486

  • ISPF V4 Messages and Codes, SC34-4450

  • ISPF V4 Planning and Customizing, SC34-4443

  • ISPF V4 User's Guide, SC34-4484

Language Environment

  • Debug Tool User's Guide and Reference, SC09-2137

National Language Support

  • National Language Support Reference, Volume 2, SE09-8002

NetView

  • NetView Installation and Administration Guide, SC31-8043

  • NetView User's Guide, SC31-8056

ODBC

  • Microsoft ODBC 3.0 Software Development Kit and Programmer's Reference, Microsoft Press, ISBN 1-57231-516-4

OS/390

  • OS/390 C/C++ Programming Guide, SC09-2362

  • OS/390 C/C++ Run-Time Library Reference, SC28-1663

  • OS/390 C/C++ User's Guide, SC09-2361

  • OS/390 eNetwork Communications Server: IP Configuration, SC31-8513

  • OS/390 Hardware Configuration Definition Planning, GC28-1750

  • OS/390 Information Roadmap, GC28-1727

  • OS/390 Introduction and Release Guide, GC28-1725

  • OS/390 JES2 Initialization and Tuning Guide, SC28-1791

  • OS/390 JES3 Initialization and Tuning Guide, SC28-1802

  • OS/390 Language Environment for OS/390 & VM Concepts Guide, GC28-1945

  • OS/390 Language Environment for OS/390 & VM Customization, SC28-1941

  • OS/390 Language Environment for OS/390 & VM Debugging Guide, SC28-1942

  • OS/390 Language Environment for OS/390 & VM Programming Guide, SC28-1939

  • OS/390 Language Environment for OS/390 & VM Programming Reference, SC28-1940

  • OS/390 MVS Diagnosis: Procedures, LY28-1082

  • OS/390 MVS Diagnosis: Reference, SY28-1084

  • OS/390 MVS Diagnosis: Tools and Service Aids, LY28-1085

  • OS/390 MVS Initialization and Tuning Guide, SC28-1751

  • OS/390 MVS Initialization and Tuning Reference, SC28-1752

  • OS/390 MVS Installation Exits, SC28-1753

  • OS/390 MVS JCL Reference, GC28-1757

  • OS/390 MVS JCL User's Guide, GC28-1758

  • OS/390 MVS Planning: Global Resource Serialization, GC28-1759

  • OS/390 MVS Planning: Operations, GC28-1760

  • OS/390 MVS Planning: Workload Management, GC28-1761

  • OS/390 MVS Programming: Assembler Services Guide, GC28-1762

  • OS/390 MVS Programming: Assembler Services Reference, GC28-1910

  • OS/390 MVS Programming: Authorized Assembler Services Guide, GC28-1763

  • OS/390 MVS Programming: Authorized Assembler Services Reference, Volumes 14, GC28-1764, GC28-1765, GC28-1766,GC28-1767

  • OS/390 MVS Programming: Callable Services for High-Level Languages, GC28-1768

  • OS/390 MVS Programming: Extended Addressability Guide, GC28-1769

  • OS/390 MVS Programming: Sysplex Services Guide, GC28-1771

  • OS/390 MVS Programming: Sysplex Services Reference, GC28-1772

  • OS/390 MVS Programming: Workload Management Services, GC28-1773

  • OS/390 MVS Routing and Descriptor Codes, GC28-1778

  • OS/390 MVS Setting Up a Sysplex, GC28-1779

  • OS/390 MVS System Codes, GC28-1780

  • OS/390 MVS System Commands, GC28-1781

  • OS/390 MVS System Messages Volume 1, GC28-1784

  • OS/390 MVS System Messages Volume 2, GC28-1785

  • OS/390 MVS System Messages Volume 3, GC28-1786

  • OS/390 MVS System Messages Volume 4, GC28-1787

  • OS/390 MVS System Messages Volume 5, GC28-1788

  • OS/390 MVS Using the Subsystem Interface, SC28-1789

  • OS/390 Security Server (RACF) Auditor's Guide, SC28-1916

  • OS/390 Security Server (RACF) Command Language Reference, SC28-1919

  • OS/390 Security Server (RACF) General User's Guide, SC28-1917

  • OS/390 Security Server (RACF) Introduction, GC28-1912

  • OS/390 Security Server (RACF) Macros and Interfaces, SK2T-6700 (OS/390 Collection Kit), SK27-2180 (OS/390 Security Server Information Package)

  • OS/390 Security Server (RACF) Security Administrator's Guide, SC28-1915

  • OS/390 Security Server (RACF) System Programmer's Guide, SC28-1913

  • OS/390 SMP/E Reference, SC28-1806

  • OS/390 SMP/E User's Guide, SC28-1740

  • OS/390 RMF User's Guide, SC28-1949

  • OS/390 TSO/E CLISTS, SC28-1973

  • OS/390 TSO/E Command Reference, SC28-1969

  • OS/390 TSO/E Customization, SC28-1965

  • OS/390 TSO/E Messages, GC28-1978

  • OS/390 TSO/E Programming Guide, SC28-1970

  • OS/390 TSO/E Programming Services,SC28-1971

  • OS/390 TSO/E REXX Reference, SC28-1975

  • OS/390 TSO/E User's Guide, SC28-1968

  • OS/390 DCE Administration Guide, SC28-1584

  • OS/390 DCE Introduction, GC28-1581

  • OS/390 DCE Messages and Codes, SC28-1591

  • OS/390 UNIX System Services Command Reference, SC28-1892

  • OS/390 UNIX System Services Messages and Codes, SC28-1908

  • OS/390 UNIX System Services Planning, SC28-1890

  • OS/390 UNIX System Services User's Guide, SC28-1891

  • OS/390 UNIX System Services Programming: Assembler Callable Services Reference, SC28-1899

PL/I for MVS &VM

  • IBM PL/I MVS & VM Language Reference, SC26-3114

  • IBM PL/I MVS & VM Programming Guide, SC26-3113

OS PL/I

  • OS PL/I Programming Language Reference, SC26-4308

  • OS PL/I Programming Guide, SC26-4307

Prolog

  • IBM SAA AD/Cycle Prolog/MVS & VM Programmer's Guide, SH19-6892

RAMAC

  • IBM RAMAC Virtual Array, SG24-4951

  • RAMAC Virtual Array: Implementing Peer-to-Peer Remote Copy, SG24-5338

  • Enterprise Storage Server Introduction and Planning, GC26-7294

Remote Recovery Data Facility

  • Remote Recovery Data Facility Program Description and Operations, LY37-3710

Storage Management

  • DFSMS/MVS Storage Management Library: Implementing System-Managed Storage, SC26-3123

  • MVS/ESA Storage Management Library: Leading a Storage Administration Group, SC26-3126

  • MVS/ESA Storage Management Library: Managing Data, SC26-3124

MVS/ESA Storage Management Library:

  • Managing Storage Groups, SC26-3125

  • MVS Storage Management Library: Storage Management Subsystem Migration Planning Guide, SC26-4659

System/370 and System/390

  • ESA/370 Principles of Operation, SA22-7200

  • ESA/390 Principles of Operation, SA22-7201

  • System/390 MVS Sysplex Hardware and Software Migration, GC28-1210

System Network Architecture (SNA)

  • SNA Formats, GA27-3136

  • SNA LU 6.2 Peer Protocols Reference, SC31-6808

  • SNA Transaction Programmer's Reference Manual for LU Type 6.2, GC30-3084

  • SNA/Management Services Alert Implementation Guide, GC31-6809

TCP/IP

  • IBM TCP/IP for MVS: Customization & Administration Guide, SC31-7134

  • IBM TCP/IP for MVS: Diagnosis Guide, LY43-0105

  • IBM TCP/IP for MVS: Messages and Codes, SC31-7132

  • IBM TCP/IP for MVS: Planning and Migration Guide, SC31-7189

VS COBOL II

  • VS COBOL II Application Programming Guide for MVS and CMS, SC26-4045

  • VS COBOL II Application Programming: Language Reference, GC26-4047

  • VS COBOL II Installation and Customization for MVS, SC26-4048

VS FORTRAN

  • VS FORTRAN Version 2: Language and Library Reference, SC26-4221

  • VS FORTRAN Version 2: Programming Guide for CMS and MVS, SC26-4222

VTAM

  • Planning for NetView, NCP, and VTAM, SC31-8063

  • VTAM for MVS/ESA Diagnosis, LY43-0069

  • VTAM for MVS/ESA Messages and Codes, SC31-6546

  • VTAM for MVS/ESA Network Implementation Guide, SC31-6548

  • VTAM for MVS/ESA Operation, SC31-6549

  • VTAM for MVS/ESA Programming, SC31-6550

  • VTAM for MVS/ESA Programming for LU 6.2, SC31-6551

  • VTAM for MVS/ESA Resource Definition Reference, SC31-6552


005 - Chapter C. DB2CERT Database DDLT

Part 5. Advanced Programming Functions

Chapter C. DB2CERT Database DDL

The following is the DDL that will create the following DB2 objects for the DB2CERT database:

  • Stogroup

  • Database

  • Segmented Tablespace

  • Partitioned Tablespace

  • LOB Tablespace

  • Tables

  • Indexes

  • Auxiliary Table

  • Auxiliary Index

  • User-Defined Types

-- Create Storage Group CERTSTG

CREATE STOGROUP CERTSTG
VOLUME(*) VCAT DB2USER1;

-- Create Database DB2CERT

CREATE DATABASE DB2CERT
STOGROUP CERTSTG
BUFFERPOOL BP7
INDEXBP BP8;

-- Create Segmented Table Space CERTTS

CREATE TABLESPACE CERTTS
IN DB2CERT
USING STOGROUP CERTSTG
   PRIQTY 52
   SECQTY 20
   ERASE NO
 LOCKSIZE PAGE
 BUFFERPOOL BP6
 CLOSE YES
 SEGSIZE 32;

-- Create Partitioned Table Space CERTTSPT

CREATE TABLESPACE CERTTSPT
IN DB2CERT
USING STOGROUP CERTSTG
   PRIQTY 100
   SECQTY 120
   ERASE NO
NUMPARTS 2
(PART 1
 COMPRESS YES,
 PART 2
 FREEPAGE 20)
ERASE NO
LOCKSIZE PAGE
CLOSE NO;

-- Create Auxiliary Table Space for LOB Column CAND_PHOTO

CREATE LOB TABLESPACE CERTPIC
  IN DB2CERT
  USING STOGROUP CERTSTG
      PRIQTY 3200
      SECQTY 1600
  LOCKSIZE LOB
  BUFFERPOOL BP16K1
  GBPCACHE SYSTEM
  LOG NO
  CLOSE NO;

-- Create User Defined Data Types

CREATE DISTINCT TYPE CANDIDATE_ID AS CHAR(9) WITH COMPARISONS;
CREATE DISTINCT TYPE TEST_ID AS CHAR(6) WITH COMPARISONS;
CREATE DISTINCT TYPE CENT AS CHAR(4) WITH COMPARISONS;
CREATE DISTINCT TYPE PHONE AS CHAR(10) WITH COMPARISONS;
CREATE DISTINCT TYPE SCORE AS DECIMAL(6,2) WITH COMPARISONS;
CREATE DISTINCT TYPE BITMAP AS BLOB(1M);
CREATE DISTINCT TYPE MINUTES AS SMALLINT WITH COMPARISONS;

-- Create CANDIDATE Table Using UDTs Previously Defined

CREATE TABLE DB2USER1.CANDIDATE
 (CID           CANDIDATE_ID    NOT NULL,
  LNAME         VARCHAR(30)     NOT NULL,
  FNAME         VARCHAR(30)     NOT NULL,
  INITIAL       CHAR(1),
  HPHONE        PHONE,
  WPHONE        PHONE,
  STREETNO      VARCHAR(8),
  STREETNAME    VARCHAR(20)     NOT NULL,
  CITY          VARCHAR(30)     NOT NULL,
  PROV_STATE    VARCHAR(30)     NOT NULL,
  CODE          CHAR(6)         NOT NULL,
  COUNTRY       VARCHAR(20)     NOT NULL,
  CERT_DBA      CHAR(1) NOT NULL WITH DEFAULT,
  CERT_APP      CHAR(1) NOT NULL WITH DEFAULT,
  PHOTO         BITMAP,
  PRIMARY KEY (CID)
  IN DB2CERT.CERTTS
 );

-- Create Table TEST with Primary Key and Check Constraint

CREATE TABLE DB2USER1.TEST
(NUMBER         TEST_ID         NOT NULL,
 NAME           VARCHAR(50)     NOT NULL,
 TYPE           CHAR(1)         NOT NULL,
 CUT_SCORE      SCORE,
 LENGTH         MINUTES         NOT NULL,
 TOTALTAKEN     SMALLINT        NOT NULL WITH DEFAULT,
 TOTALPASSED    SMALLINT        NOT NULL WITH DEFAULT,
 PRIMARY KEY (NUMBER),
 CONSTRAINT test_type CHECK (TYPE in ('P','B'))
 IN DB2CERT.CERTTS
 );

-- Create Unique Clustering Index

CREATE UNIQUE INDEX DB2USER1.TESTIX
  ON DB2USER1.TEST
   (NUMBER ASC)
  USING STOGROUP CERTSTG
  PRIQTY 512
  SECQTY 64
  ERASE NO
  CLUSTER

-- Create Table TEST_CENTER with Primary Key

CREATE TABLE DB2USER1.TEST_CENTER
 (TCID          CENTER_ID       NOT NULL,
  NAME          VARCHAR(40)     NOT NULL,
  STREETNO      VARCHAR(8)      NOT NULL,
  STREETNAME    VARCHAR(20)     NOT NULL,
  CITY          VARCHAR(30)     NOT NULL,
  PROV_STATE    VARCHAR(30)     NOT NULL,
  COUNTRY       VARCHAR(20)     NOT NULL,
  CODE          CHAR(6)         NOT NULL,
  TYPE          CHAR(1)         NOT NULL,
  PHONE         PHONE           NOT NULL,
  NOSEATS       SMALLINT        NOT NULL,
  PRIMARY KEY (TCID)
  IN DB2CERT.CERTTSPT
 );

-- Create Partitioning Index

CREATE UNIQUE INDEX DB2USER1.TESTCNTX
  ON DB2USER1.TEST_CENTER
   (TCID ASC)
  USING STOGROUP CERTSTG
  PRIQTY 512
  SECQTY 64
  ERASE NO
  CLUSTER
    (PART 1 VALUES (300),
     PART 2 VALUES (500))
  BUFFERPOOL BP3
  CLOSE YES;

-- Create NPI with pieces

CREATE UNIQUE INDEX DB2USER1.TESTCN2X
  ON DB2USER1.TEST_CENTER
   (CODE ASC)
  USING STOGROUP CERTSTG
  PIECESIZE 512K;

-- Create TEST_TAKEN Table With Primary and Foreign Keys

 CREATE TABLE DB2USER1.TEST_TAKEN
 (CID           CANDIDATE_ID    NOT NULL,
  TCID          CENTER_ID       NOT NULL,
  NUMBER        TEST_ID         NOT NULL,
  DATE_TAKEN    DATE            NOT NULL WITH DEFAULT,
  START_TIME    TIME            WITH DEFAULT,
  FINISH_TIME   TIME            WITH DEFAULT,
  SCORE         SCORE,
  PASS_FAIL     CHAR(1),
  SEAT_NO       CHAR(2)         NOT NULL,
  PRIMARY KEY (TCID, CID, DATE_TAKEN),
  FOREIGN KEY (CID)
        REFERENCES CANDIDATE ON DELETE CASCADE,
  FOREIGN KEY (TCID)
        REFERENCES TEST_CENTER ON DELETE CASCADE,
  FOREIGN KEY (NUMBER)
        REFERENCES TEST ON DELETE RESTRICT
  IN DB2CERT.CERTTS
);

-- Create Auxiliary Table for LOB Column CAND_PHOTO

CREATE AUX TABLE CAND_PHOTO
  IN DB2CERT.CERTPIC
  STORES DB2USER1.CANDIDATE
  COLUMN PHOTO;

-- Create Auxiliary Index for LOB Column CAND_PHOTO

CREATE UNIQUE INDEX DB2CERT.PHOTOIX
  ON DB2USER1.CAND_PHOTO
  USING VCAT DB2USER1
  COPY YES;