HP NonStop SQL Programming Manual for TAL



Similar documents
HP NonStop SQL/MP Programming Manual for C

HP NonStop SQL/MX Release 3.1 Database and Application Migration Guide

HP NonStop SQL/MP Query Guide

HP NonStop SQL/MX Data Mining Guide

ERserver. DB2 Universal Database for iseries SQL Programming with Host Languages. iseries. Version 5

NonStop Server for Java Message Service C++ API Programmer s Guide

HP NonStop SQL/MX Report Writer Guide

Embedded SQL programming

SNAX/XF LU Network Services Manual

KB_SQL SQL Reference Guide Version 4

Retrieving Data Using the SQL SELECT Statement. Copyright 2006, Oracle. All rights reserved.

HP NonStop SQL/MX Release Management Guide

Firebird. Embedded SQL Guide for RM/Cobol

Duration Vendor Audience 5 Days Oracle End Users, Developers, Technical Consultants and Support Staff

Oracle Database: SQL and PL/SQL Fundamentals

HP NonStop TS/MP Pathsend and Server Programming Manual

Database DB2 Universal Database for iseries Embedded SQL programming

Instant SQL Programming

Bachelors of Computer Application Programming Principle & Algorithm (BCA-S102T)

Intro to Embedded SQL Programming for ILE RPG Developers

Progress Embedded SQL-92 Guide and Reference

NonStop NET/MASTER D30. MS Operator's Guide. System Software Library

How To Create A Table In Sql (Ahem)

Oracle Database: SQL and PL/SQL Fundamentals NEW

InterBase 6. Embedded SQL Guide. Borland/INPRISE. 100 Enterprise Way, Scotts Valley, CA

itp Secure WebServer System Administrator s Guide

HP NonStop SQL DDL Replicator User s Guide

Oracle Database: SQL and PL/SQL Fundamentals

Using SQL in RPG Programs: An Introduction

Chapter 9, More SQL: Assertions, Views, and Programming Techniques

Database Programming with PL/SQL: Learning Objectives

Rational Rational ClearQuest

ERserver. iseries. DB2 Universal Database for iseries SQL Programming with Host Languages

Using SQL Server Management Studio

SQL Server Database Coding Standards and Guidelines

Choosing a Data Model for Your Database

3.GETTING STARTED WITH ORACLE8i

JavaScript: Introduction to Scripting Pearson Education, Inc. All rights reserved.

Oracle Database: SQL and PL/SQL Fundamentals NEW

Duration Vendor Audience 5 Days Oracle Developers, Technical Consultants, Database Administrators and System Analysts

Name: Class: Date: 9. The compiler ignores all comments they are there strictly for the convenience of anyone reading the program.

14 Triggers / Embedded SQL

sqlite driver manual

Mimer SQL. Programmer s Manual. Version 8.2 Copyright 2000 Mimer Information Technology AB

2874CD1EssentialSQL.qxd 6/25/01 3:06 PM Page 1 Essential SQL Copyright 2001 SYBEX, Inc., Alameda, CA

MyOra 3.0. User Guide. SQL Tool for Oracle. Jayam Systems, LLC

MS Access: Advanced Tables and Queries. Lesson Notes Author: Pamela Schmidt

Data Tool Platform SQL Development Tools

CA IDMS SQL. Programming Guide. Release

Apache Cassandra Query Language (CQL)

A Brief Introduction to MySQL

Language Reference Guide

Beginning C# 5.0. Databases. Vidya Vrat Agarwal. Second Edition

Heterogeneous Replication Guide. SAP Replication Server SP200

Introduction to Java Applications Pearson Education, Inc. All rights reserved.

Handling Exceptions. Copyright 2006, Oracle. All rights reserved. Oracle Database 10g: PL/SQL Fundamentals 8-1

Moving from CS 61A Scheme to CS 61B Java

MS ACCESS DATABASE DATA TYPES

Specifications of Paradox for Windows

SQL Server An Overview

The release notes provide details of enhancements and features in Cloudera ODBC Driver for Impala , as well as the version history.

Database Migration from MySQL to RDM Server

SQL and Programming Languages. SQL in Programming Languages. Applications. Approaches

Demystified CONTENTS Acknowledgments xvii Introduction xix CHAPTER 1 Database Fundamentals CHAPTER 2 Exploring Relational Database Components

Embedded Systems. Review of ANSI C Topics. A Review of ANSI C and Considerations for Embedded C Programming. Basic features of C

Oracle Database 12c: Introduction to SQL Ed 1.1

4 Simple Database Features

Topics. Parts of a Java Program. Topics (2) CS 146. Introduction To Computers And Java Chapter Objectives To understand:

Heterogeneous Replication Guide. Replication Server 15.5

Oracle SQL. Course Summary. Duration. Objectives

MYSQL DATABASE ACCESS WITH PHP

How Strings are Stored. Searching Text. Setting. ANSI_PADDING Setting

PL/SQL Overview. Basic Structure and Syntax of PL/SQL

Oracle 10g PL/SQL Training

Introduction This document s purpose is to define Microsoft SQL server database design standards.

Embedding SQL in High Level Language Programs

Teach Yourself InterBase

ACCELL/SQL: Creating Reports with RPT Report Writer

Access Queries (Office 2003)

java.util.scanner Here are some of the many features of Scanner objects. Some Features of java.util.scanner

Xcode User Default Reference. (Legacy)

CSC 443 Data Base Management Systems. Basic SQL

Oracle Database 10g: Program with PL/SQL

Programming Languages CIS 443

Oracle SQL, introduced in the previous chapter, is not a language that can be

In This Lecture. SQL Data Definition SQL SQL. Notes. Non-Procedural Programming. Database Systems Lecture 5 Natasha Alechina

Ohio University Computer Services Center August, 2002 Crystal Reports Introduction Quick Reference Guide

Maintaining Stored Procedures in Database Application

Database Query 1: SQL Basics

C++ Language Tutorial

SQL Server for developers. murach's TRAINING & REFERENCE. Bryan Syverson. Mike Murach & Associates, Inc. Joel Murach

Programming Database lectures for mathema

Heterogeneous Replication Guide. Replication Server SP100

Oracle Database 10g: Introduction to SQL

Handling Exceptions. Schedule: Timing Topic 45 minutes Lecture 20 minutes Practice 65 minutes Total

BIRT: A Field Guide to Reporting

Transcription:

HP NonStop SQL Programming Manual for TAL Abstract This manual describes the programmatic interface to HP NonStop SQL for the Transaction Application Language (TAL). The NonStop SQL relational database management system (RDBMS) uses the structured query language (SQL) to describe and manipulate data in NonStop SQL databases. This manual is intended for application programmers who are coding embedded SQL statements in a TAL program. Product Version NonStop SQL C30 Supported Release Version Updates (RVUs) This publication supports D40.00 and all subsequent D-series RVUs and G06.00 and all subsequent G-series RVUs until otherwise indicated by its replacement publication. Part Number Published 527887-001 March 2004

Document History Part Number Product Version Published N.A. NonStop SQL C30 September 1990 N.A. NonStop SQL C30 December 1991 527887-001 NonStop SQL C30 March 2004

HP NonStop SQL Programming Manual for TAL Index Figures Tables What s New in This Manual ix Manual Information ix New and Changed Information ix About This Manual xi Audience xi Organization xii Related Manuals xii Notation Conventions xv 1. Introduction Why Use Embedded SQL Statements? 1-1 Developing a Program 1-2 Embedding SQL Statements 1-2 Declaring Host Variables 1-3 Calling SQL System Procedures 1-3 Using Static SQL Statements 1-4 Using Dynamic SQL Operations 1-5 Compiling and Executing a Program 1-7 2. Host Variables and Parameters Host Variables 2-1 Declaring Host Variables 2-2 Using Corresponding SQL and TAL Data Types 2-2 Overriding Default Data Types 2-5 Using Host Variables 2-6 Using Indicator Variables for Null Values 2-17 Creating Host Variables With the INVOKE Directive 2-20 Parameters 2-23 Using a Parameter List 2-24 Using Parameters in Loops 2-25 Using Indicator Parameters 2-25 Using Default Parameter Data Types 2-26 Hewlett-Packard Company 527887-001 i

Contents 3. NonStop SQL Statements and Directives 3. NonStop SQL Statements and Directives Embedding SQL Statements and Directives 3-1 Coding Statements and Directives 3-2 Placing Statements and Directives in a Program 3-2 Locating Information About SQL Statements and Directives 3-4 BEGIN DECLARE SECTION and END DECLARE SECTION 3-6 CLOSE 3-7 CONTROL Directives 3-8 DECLARE CURSOR 3-11 DELETE 3-13 DESCRIBE and DESCRIBE INPUT 3-16 DROP 3-17 EXECUTE and EXECUTE IMMEDIATE 3-18 FETCH 3-18 INCLUDE SQLCA, INCLUDE SQLDA, and INCLUDE SQLSA 3-19 INSERT 3-19 INVOKE 3-22 OPEN 3-29 PREPARE 3-30 RELEASE 3-31 SELECT 3-31 SQL 3-35 SQLMEM 3-37 SYMBOLPAGES 3-42 UPDATE 3-42 WHENEVER 3-47 4. System Procedures Procedure Descriptions 4-2 SQLCADISPLAY 4-2 SQLCAFSCODE 4-7 SQLCAGETINFOLIST 4-8 SQLCATOBUFFER 4-13 SQLGETCATALOGVERSION 4-19 SQLGETOBJECTVERSION 4-19 SQLGETSYSTEMVERSION 4-21 SQLSADISPLAY 4-22 ii

Contents 5. Program Compilation and Execution 5. Program Compilation and Execution Compiling a TAL Program 5-2 Running the TAL Compiler 5-3 Using the Binder Program 5-4 Including the TALLIB Run-Time Library 5-4 Running the Accelerator 5-5 Running the SQL Compiler 5-5 Using the EXPLAIN Utility 5-17 Determining Program File Validity 5-22 Changes to a Program File 5-22 Changes to Database Objects 5-23 Other Changes 5-23 Understanding Automatic SQL Recompilation 5-24 Predicting Automatic SQL Recompilation 5-24 Understanding the Run-Time Timestamp Check 5-26 Understanding Run-Time Recompilation Errors 5-28 Maximizing Local Autonomy 5-28 Using a Local Partition 5-28 Using TACL DEFINEs 5-29 Using Current Statistics 5-29 Skipping Unavailable Partitions 5-30 Executing an SQL Program File 5-30 Using the RUN Command 5-30 Using TACL DEFINEs 5-31 Estimating Program Size 5-32 6. Error and Status Processing Getting Error and Warning Information 6-1 Using the SQLCODE Variable 6-1 Using the WHENEVER Directive 6-4 Getting Information From the SQLCA 6-9 Getting Performance and Statistics Information 6-10 Getting Information About Dynamic SQL Operations 6-13 Declaring the SQLDA and Names Buffer 6-14 Initializing the EYE^CATCHER Field 6-18 Using Literal Declarations for the SQLDA 6-18 Example of Using the SQLDA 6-21 iii

Contents 7. Dynamic NonStop SQL Operations 7. Dynamic NonStop SQL Operations Determining Uses for Dynamic SQL Operations 7-2 Developing a Dynamic SQL Application 7-2 Writing a Dynamic SQL Pathway Server 7-3 Specifying Input Parameters and Output Variables 7-4 Using the SQLDA and Names Buffer 7-5 Using Dynamic SQL Programming Techniques 7-7 Overview of a Dynamic SQL Program 7-7 Dynamically Allocating Memory 7-14 Using the Names Buffer 7-23 Allocating and Filling in Output Variables 7-27 Using Dynamic Cursors 7-31 Using Statement and Cursor Host Variables 7-33 Handling Null Values 7-36 A. Sample NonStop SQL Database B. Examples of Static NonStop SQL Programs Insertion Program B-1 Date-Time Program B-10 C. Examples of Dynamic NonStop SQL Programs Dynamic SQL Program C-1 Detailed Dynamic SQL Program C-9 D. NonStop SQL Version Issues Version 1 and Version 2 Definitions D-1 Summary of Incompatible Changes D-3 Migrating a C10 Program to Run on a C30 System D-4 Migrating a C10 Program to Access Version 2 Objects D-7 Dynamic SQL Operations D-7 Static SQL Operations D-8 Catalog Tables D-8 Summary D-8 Installing Migrated Programs D-8 SQL Component Compatibility D-9 Developing C10 Programs with C30 Software D-10 Binding C10 and C30 Object Files D-10 Mixed-Version Programmatic Features D-11 Release Specification Options D-11 iv

Contents D. NonStop SQL Version Issues (continued) D. NonStop SQL Version Issues (continued) System Procedures D-11 Techniques for Mixed-Version Programming D-12 Handling Mixed-Version-Objects D-12 Running on Multiple NonStop SQL Releases D-13 Using the Single-Code Thread Design D-14 E. Enforcing Data Integrity Index Figures Using Constraints E-1 Managing Referential Integrity E-2 Figure i. Related Manuals xiv Figure 1-1. Static SQL Statements in a TAL Program 1-5 Figure 1-2. Dynamic SQL Statements in a TAL Program 1-6 Figure 1-3. Compiling and Executing a Program 1-8 Figure 4-1. SQLSADISPLAY Display 4-24 Figure 5-1. Compiling and Executing a Program 5-2 Figure 5-2. NonStop SQL Program File Format 5-12 Figure 5-3. Sample SQL Compiler Listing 5-16 Figure 5-4. OBEY Command File Format of the EXPLAIN DEFINES Report 5-19 Figure 5-5. INFO DEFINE Format of the EXPLAIN DEFINES Report 5-20 Figure 5-6. EXPLAIN Utility Report 5-21 Figure 5-7. Run-Time Checks and Automatic SQL Recompilation 5-27 Figure 6-1. Checking the SQLCODE Variable 6-3 Figure 6-2. Enabling and Disabling the WHENEVER Directive 6-6 Figure 6-3. Using WHENEVER Directives 6-8 Figure 6-4. Calling an SQL System Procedure 6-10 Figure 6-5. SQLSA Structure Description 6-11 Figure 6-6. Release C30 SQLDA Template and Names Buffer 6-15 Figure 6-7. Release C10 SQLDA Template and Names Buffer 6-16 Figure 6-8. SQLDA Structure Template 6-22 Figure 7-1. Using a PREPARE Statement to Compile a Statement 7-16 Figure 7-2. Allocating the SQLDA Structure 7-19 Figure 7-3. Allocating Memory for Values 7-22 Figure 7-4. Getting Parameter Values 7-25 Figure 7-5. Displaying Output 7-29 Figure 7-6. Statement and Cursor Host Variables 7-34 v

Contents Figures (continued) Figures (continued) Tables Figure A-1. Sample NonStop SQL Database Relations A-2 Figure A-2. Sample Database Source File A-3 Figure B-1. Insertion Program Output B-2 Figure B-2. Date-Time Program Run B-12 Figure C-1. Output for the Dynamic SQL Program C-2 Figure C-2. Output for the Detailed Dynamic SQL Program C-11 Figure D-1. Developing a Program For Mixed-Version Nodes D-15 Table 1-1. NonStop SQL Statements 1-2 Table 1-2. NonStop SQL Directives 1-3 Table 2-1. Corresponding NonStop SQL and TAL Data Types 2-3 Table 2-2. Default and Override Data Type Mapping 2-6 Table 2-3. Date-Time and INTERVAL Data Types 2-16 Table 2-4. INVOKE Directive Override Data Type Mapping 2-20 Table 3-1. Summary of NonStop SQL Statements and Directives 3-4 Table 3-2. INVOKE Directive Override Data Type Mapping 3-23 Table 3-3. NonStop SQL Data Structures 3-38 Table 4-1. System Procedures for NonStop SQL Operations 4-1 Table 4-2. SQLCAGETINFOLIST Procedure Item Codes 4-11 Table 4-3. SQLCAGETINFOLIST Procedure Error Codes 4-12 Table 4-4. NonStop SQL Release C30 (Version 2) Features 4-20 Table 4-5. SQLSADISPLAY Procedure Display Elements 4-23 Table 5-1. Calculating Virtual Memory Requirements for Each SQL Statement or Directive 5-33 Table 6-1. TAL Compiler Pseudocode for Checking SQLCODE 6-4 Table 6-2. System Procedures for the SQLCA Structure 6-9 Table 6-3. SQLSA Fields 6-11 Table 6-4. SQLDA Fields 6-17 Table 6-5. Literal Declarations for Character, Numeric, and Decimal Values 6-19 Table 6-6. Literal Declarations for Date-Time and INTERVAL Values 6-19 Table 6-7. Literal Declarations for Ranges of Date-Time Fields 6-20 Table 7-1. Literal Declarations for Data Types 7-21 Table D-1. Version 2 Items and Descriptions D-2 Table D-2. Version 1 Items and Descriptions D-2 Table D-3. Summary of New Columns in Version 2 Catalogs D-3 Table D-4. Incompatible NonStop SQL Release C30 Features D-4 vi

Contents Tables (continued) Tables (continued) Table D-5. Accessing Version 2 Objects from a C10 Program D-8 Table D-6. Release C10 Versioning IPM Summary D-9 vii

Contents viii

What s New in This Manual Manual Information Abstract HP NonStop SQL Programming Manual for TAL This manual describes the programmatic interface to HP NonStop SQL for the Transaction Application Language (TAL). The NonStop SQL relational database management system (RDBMS) uses the structured query language (SQL) to describe and manipulate data in NonStop SQL databases. This manual is intended for application programmers who are coding embedded SQL statements in a TAL program. Product Version NonStop SQL C30 Supported Release Version Updates (RVUs) This publication supports D40.00 and all subsequent D-series RVUs and G06.00 and all subsequent G-series RVUs until otherwise indicated by its replacement publication. Part Number Published 527887-001 March 2004 Document History Part Number Product Version Published N.A. NonStop SQL C30 September 1990 N.A. NonStop SQL C30 December 1991 527887-001 NonStop SQL C30 March 2004 New and Changed Information This publication has been updated to reflect new product names: Since product names are changing over time, this publication might contain both HP and Compaq product names. Product names in graphic representations are consistent with the current product interface. The technical content of this publication has not been updated and reflects the state of the product at the G06.22 release version update (RVU). ix

What s New in This Manual New and Changed Information x

About This Manual This manual describes the programmatic interface to NonStop SQL for the Transaction Application Language (TAL). The NonStop SQL relational database management system (RDBMS) uses the structured query language (SQL) to define and manipulate data in NonStop SQL databases. NonStop SQL provides both a conversational and a programmatic interface. Using the programmatic interface, a C, COBOL85, Pascal, or TAL programmer can use embedded SQL statements to access a NonStop SQL database. Audience This manual is intended for TAL programmers who are coding embedded SQL statements in a TAL program. A reader should be familiar with: TAL NonStop SQL terms and concepts (as described in the Introduction to NonStop SQL) The HP NonStop Kernel operating system Organization Section 1 Section 2 Section 3 Section 4 Section 5 Section 6 Section 7 Appendix A Appendix B Appendix C Appendix D Appendix E Provides an overview of the TAL programmatic interface to NonStop SQL. Describes how to declare and use host variables and parameters in a TAL program. Describes the statements and directives that have unique TAL considerations, data structures, or examples. Describes the SQL system library procedures and shows how to call them from a TAL program. Describes how to compile and execute a TAL program that contains embedded SQL statements. Describes how to process error and status messages and statistics information using the SQLCODE variable and the SQLCA, SQLDA, and SQLSA data structures. Describes how to use dynamic SQL operations. Describes the sample NonStop SQL database that is used by the programming examples. Includes two programming examples that use static SQL operations. Includes two programming examples that use dynamic SQL operations. Describes version issues for NonStop SQL release C10 and release C30 software. Describes how to use constraints and to check for referential integrity. xi

About This Manual Related Manuals Related Manuals You will probably want to use other books from the SQL/MP library set, shown in Figure i, in conjunction with this reference manual. The complete library includes: The SQL/MP Reference Manual describes the SQL/MP language elements, expressions, predicates, functions, and SQL statements that can be run in SQLCI. The manual also describes SQLCI commands and utilities. Optional NonStop SQL/MP Library Manuals Introduction to SQL/MP provides an overview of the SQL/MP relational database management system. The SQL/MP Messages Manual describes NonStop SQL messages. The SQL/MP Installation and Management Guide explains how to plan, install, create, and manage a SQL database. The SQL/MP Programming Manual for C and SQL/MP Programming Manual for COBOL85 describe the SQL/MP programmatic interfaces for C and COBOL85, respectively. The SQL/MP Programming Manual for Pascal and SQL/MP Programming Manual for TAL are the equivalent manuals for Pascal and TAL. Program Development Manuals The TAL Reference Manual describes TAL. The Inspect Manual describes the Inspect program, an interactive source-level or machine-level debugger that enables you to interrupt and resume program execution and to display and modify variables. The Guardian Programmer s Guide describes the programmatic interface between user programs and the operating system. The Binder Manual describes the Binder program, an interactive linker that enables you to examine, modify, and combine object files and to generate load maps and cross-reference listings. If plan to run your object file on a TNS/R system and you use the Accelerator to optimize the object code, see the Accelerator Manual. xii

About This Manual Related Manuals Figure i. Related Manuals Related Manuals Introduction to SQL/MP Prerequisite Manual SQL Programming Manual for TAL Companion Manual SQL/MP Reference Manual Program Development Manuals Optional NonStop SQL Manuals TAL Reference Manual Inspect Manual SQL /MP Messages Manual SQL /MP Installation and Management Guide Guardian' Programmer's Guide Binder Manual SQL/MP Version Management Guide SQL/MP Reference Summary Other NonStop SQL Programming Manuals SQL/MP Programming Manual for C SQL/MP Programming Manual for COBOL85 SQL/MP Programming Manual for Pascal VSTAB01.vsd xiii

About This Manual Notation Conventions Notation Conventions The list summarizes the conventions used for syntax and programming examples in this manual. Notation UPPERCASE LETTERS lowercase italic letters Brackets [ ] Braces { } Vertical line Ellipsis... Spaces i and o Punctuation Meaning Uppercase letters represent keywords and reserved words; enter these items exactly as shown. Uppercase letters in text also represent variable names that are used in programming examples. Lowercase letters in italics represent information you supply. Brackets enclose optional syntax items. A group of vertically aligned items enclosed in brackets represents a list of selections from which you can choose one or none. Braces enclose required syntax items. A group of vertically aligned items enclosed in braces represents a list of selections from which you must choose one. A vertical line separates alternative syntax items in a horizontal list. Such a list, enclosed in either brackets or braces, is an alternative to a vertical list for presenting selections. An ellipsis immediately following a pair of brackets or braces indicates that you can repeat the enclosed syntax items any number of times. An ellipsis in a programming example indicates that one or more lines of source code have been omitted. If a space separates two items, that space is required. If one of the items is a punctuation symbol, such as a parenthesis or a comma, spaces are optional. In the syntax for SQL system procedure calls, i and o are used as follows: i Input parameters (parameters that pass data to the called procedure) o Output parameters (parameters that return data to the calling program) i:o Input and output parameters (parameters that both pass and return data) Parentheses, commas, semicolons, and other symbols not described above must be entered precisely as shown. xiv

About This Manual Hypertext Links Hypertext Links Blue underline is used to indicate a hypertext link within text. By clicking a passage of text with a blue underline, you are taken to the location described. For example: This requirement is described under Backup DAM Volumes and Physical Disk Drives on page 3-2. General Syntax Notation This list summarizes the notation conventions for syntax presentation in this manual. UPPERCASE LETTERS. Uppercase letters indicate keywords and reserved words. Type these items exactly as shown. Items not enclosed in brackets are required. For example: MAXATTACH lowercase italic letters. Lowercase italic letters indicate variable items that you supply. Items not enclosed in brackets are required. For example: file-name computer type. Computer type letters within text indicate C and Open System Services (OSS) keywords and reserved words. Type these items exactly as shown. Items not enclosed in brackets are required. For example: myfile.c italic computer type. Italic computer type letters within text indicate C and Open System Services (OSS) variable items that you supply. Items not enclosed in brackets are required. For example: pathname [ ] Brackets. Brackets enclose optional syntax items. For example: TERM [\system-name.]$terminal-name INT[ERRUPTS] A group of items enclosed in brackets is a list from which you can choose one item or none. The items in the list can be arranged either vertically, with aligned brackets on each side of the list, or horizontally, enclosed in a pair of brackets and separated by vertical lines. For example: FC [ num ] [ -num ] [ text ] K [ X D ] address { } Braces. A group of items enclosed in braces is a list from which you are required to choose one item. The items in the list can be arranged either vertically, with aligned xv

About This Manual General Syntax Notation braces on each side of the list, or horizontally, enclosed in a pair of braces and separated by vertical lines. For example: LISTOPENS PROCESS { $appl-mgr-name } { $process-name } ALLOWSU { ON OFF } Vertical Line. A vertical line separates alternatives in a horizontal list that is enclosed in brackets or braces. For example: INSPECT { OFF ON SAVEABEND } Ellipsis. An ellipsis immediately following a pair of brackets or braces indicates that you can repeat the enclosed sequence of syntax items any number of times. For example: M address [, new-value ] [ - ] {0 1 2 3 4 5 6 7 8 9} An ellipsis immediately following a single syntax item indicates that you can repeat that syntax item any number of times. For example: "s-char " Punctuation. Parentheses, commas, semicolons, and other symbols not previously described must be typed as shown. For example: error := NEXTFILENAME ( file-name ) ; LISTOPENS SU $process-name.#su-name Quotation marks around a symbol such as a bracket or brace indicate the symbol is a required character that you must type as shown. For example: "[" repetition-constant-list "]" Item Spacing. Spaces shown between items are required unless one of the items is a punctuation symbol such as a parenthesis or a comma. For example: CALL STEPMOM ( process-id ) ; If there is no space between two items, spaces are not permitted. In this example, no spaces are permitted between the period and any other items: $process-name.#su-name Line Spacing. If the syntax of a command is too long to fit on a single line, each continuation line is indented three spaces and is separated from the preceding line by a blank line. This spacing distinguishes items in a continuation line from items in a vertical list of selections. For example: ALTER [ / OUT file-spec / ] LINE [, attribute-spec ] xvi

About This Manual Notation for Messages!i and!o. In procedure calls, the!i notation follows an input parameter (one that passes data to the called procedure); the!o notation follows an output parameter (one that returns data to the calling program). For example: CALL CHECKRESIZESEGMENT ( segment-id!i, error ) ;!o!i,o. In procedure calls, the!i,o notation follows an input/output parameter (one that both passes data to the called procedure and returns data to the calling program). For example: error := COMPRESSEDIT ( filenum ) ;!i,o!i:i. In procedure calls, the!i:i notation follows an input string parameter that has a corresponding parameter specifying the length of the string in bytes. For example: error := FILENAME_COMPARE_ ( filename1:length!i:i, filename2:length ) ;!i:i!o:i. In procedure calls, the!o:i notation follows an output buffer parameter that has a corresponding input parameter specifying the maximum length of the output buffer in bytes. For example: error := FILE_GETINFO_ ( filenum!i, [ filename:maxlen ] ) ;!o:i Notation for Messages This list summarizes the notation conventions for the presentation of displayed messages in this manual. Bold Text. Bold text in an example indicates user input typed at the terminal. For example: ENTER RUN CODE?123 CODE RECEIVED: 123.00 The user must press the Return key after typing the input. Nonitalic text. Nonitalic letters, numbers, and punctuation indicate text that is displayed or returned exactly as shown. For example: Backup Up. lowercase italic letters. Lowercase italic letters indicate variable items whose values are displayed or returned. For example: p-register process-name xvii

About This Manual Notation for Management Programming Interfaces [ ] Brackets. Brackets enclose items that are sometimes, but not always, displayed. For example: Event number = number [ Subject = first-subject-value ] A group of items enclosed in brackets is a list of all possible items that can be displayed, of which one or none might actually be displayed. The items in the list can be arranged either vertically, with aligned brackets on each side of the list, or horizontally, enclosed in a pair of brackets and separated by vertical lines. For example: proc-name trapped [ in SQL in SQL file system ] { } Braces. A group of items enclosed in braces is a list of all possible items that can be displayed, of which one is actually displayed. The items in the list can be arranged either vertically, with aligned braces on each side of the list, or horizontally, enclosed in a pair of braces and separated by vertical lines. For example: obj-type obj-name state changed to state, caused by { Object Operator Service } process-name State changed from old-objstate to objstate { Operator Request. } { Unknown. } Vertical Line. A vertical line separates alternatives in a horizontal list that is enclosed in brackets or braces. For example: Transfer status: { OK Failed } % Percent Sign. A percent sign precedes a number that is not in decimal notation. The % notation precedes an octal number. The %B notation precedes a binary number. The %H notation precedes a hexadecimal number. For example: %005400 %B101111 %H2F P=%p-register E=%e-register Notation for Management Programming Interfaces This list summarizes the notation conventions used in the boxed descriptions of programmatic commands, event messages, and error lists in this manual. UPPERCASE LETTERS. Uppercase letters indicate names from definition files. Type these names exactly as shown. For example: ZCOM-TKN-SUBJ-SERV xviii

About This Manual Change Bar Notation lowercase letters. Words in lowercase letters are words that are part of the notation, including Data Definition Language (DDL) keywords. For example: token-type!r.!o. The!r notation following a token or field name indicates that the token or field is required. For example: ZCOM-TKN-OBJNAME token-type ZSPI-TYP-STRING.!r The!o notation following a token or field name indicates that the token or field is optional. For example: ZSPI-TKN-MANAGER token-type ZSPI-TYP-FNAME32.!o Change Bar Notation Change bars are used to indicate substantive differences between this edition of the manual and the preceding edition. Change bars are vertical rules placed in the right margin of changed portions of text, figures, tables, examples, and so on. Change bars highlight new or revised information. For example: The message types specified in the REPORT clause are different in the COBOL85 environment and the Common Run-Time Environment (CRE). The CRE has many new message types and some new message type codes for old message types. In the CRE, the message type SYSTEM includes all messages except LOGICAL-CLOSE and LOGICAL-OPEN. xix

About This Manual Change Bar Notation xx

1 Introduction The NonStop SQL relational database management system (RDBMS) uses the structured query language (SQL) to define and manipulate data in a NonStop SQL database. Because NonStop SQL is integrated with other HP NonStop software products, you can execute SQL statements interactively or programmatically. Using the SQL conversational interface (SQLCI), you can enter SQL statements and directives interactively from a terminal or an OBEY command file. NonStop SQL compiles and executes the statement immediately and then issues a response at your terminal. Using SQLCI, you can also test programmatic SQL statements before you embed and compile them in a program. Using the programmatic interface, you can embed SQL statements and directives in a C, COBOL85, Pascal, or TAL program. You compile the host language statements using the host language compiler and the embedded SQL statements using the SQL compiler. The SQL statements execute when the object file runs. NonStop SQL also provides system library procedures you can call from a program to perform various SQL functions (for example, to get error and statistics information after executing an SQL statement). This manual describes the TAL programmatic interface to NonStop SQL. It shows you how to embed SQL statements and directives in a TAL program and how to call the SQL system library procedures from a TAL program. Why Use Embedded SQL Statements? Using embedded SQL statements in a TAL program to access a NonStop SQL database has these advantages: High-level language for accessing a database. Using SQL statements, you code a request to access a database, and NonStop SQL determines the most efficient method to perform the request. Insulation against database changes. If a database administrator modifies a database (for example, adds columns to a table), the logic of your program is not affected. Use of TAL for processing data. You can use SQL statements to retrieve data from a database or insert data into a database, and you can use TAL statements to process and manipulate the data. System support for data consistency. When you use audited tables and views, the system maintains data consistency with the locking facility and the HP NonStop Transaction Manangement Facility (TMF). 1-1

Introduction Developing a Program Developing a Program A TAL program that contains embedded SQL statements can use both static and dynamic SQL operations. A static SQL operation processes SQL statements that you embed and compile in the TAL source code. A dynamic SQL operation enables a program to construct, compile, and execute an SQL statement at run time. Embedding SQL Statements You embed SQL statements by preceding each SQL statement with the keywords EXEC SQL and terminating the statement with either a semicolon (;) or an END, ELSE, or UNTIL keyword if it is appropriate for the statement. This example shows a TAL source file that contains embedded SQL statements.! TAL source file... EXEC SQL BEGIN DECLARE SECTION;... ;! SQL host variable declarations EXEC SQL END DECLARE SECTION;...! TAL procedure... EXEC SQL... ;! SQL statement... Table 1-1 shows the NonStop SQL statements you can embed in a TAL program. Table 1-1. NonStop SQL Statements Type Data Control Language (DCL) Data Definition Language (DDL) Data Manipulation Language (DML) Dynamic SQL Transaction Control Statement FREE RESOURCES, LOCK TABLE, UNLOCK TABLE ALTER, COMMENT, CREATE, DROP, HELP TEXT, UPDATE STATISTICS CLOSE, DECLARE CURSOR, DELETE, FETCH, INSERT, OPEN, SELECT, UPDATE DECLARE CURSOR, DESCRIBE, DESCRIBE INPUT, EXECUTE, EXECUTE IMMEDIATE, PREPARE, RELEASE BEGIN WORK, COMMIT WORK, ROLLBACK WORK 1-2

Introduction Declaring Host Variables Table 1-2 shows the NonStop SQL directives you can embed in a TAL program. Table 1-2. NonStop SQL Directives Type Data Declaration Data Control Error Checking Directive BEGIN DECLARE SECTION, END DECLARE SECTION, INCLUDE SQLCA, INCLUDE SQLDA, INCLUDE SQLSA CONTROL EXECUTOR, CONTROL QUERY, CONTROL TABLE WHENEVER For more information, see Section 3, NonStop SQL Statements and Directives Declaring Host Variables A host variable provides communication between TAL statements and SQL statements in a program. A host variable is a TAL variable with a data type that corresponds to an SQL data type. You use host variables in SQL statements to receive data from a database and to insert data into a database. When you use a host variable with an SQL statement, you precede the host variable name with a colon (:). You declare host variables in a Declare Section with the TAL variable declarations. A Declare Section begins with the BEGIN DECLARE SECTION directive and ends with the END DECLARE SECTION directive. In this example, FILE^NUMBER and MESSAGE are host variables.! TAL declarations... EXEC SQL BEGIN DECLARE SECTION; INT file^number;! SQL host variables STRING.message[80] ; EXEC SQL END DECLARE SECTION;...! More TAL declarations... For more information, see Section 2, Host Variables and Parameters. Calling SQL System Procedures Use the provided TAL system library procedures to perform various SQL operations and functions. For example, the SQLCADISPLAY procedure returns error and statistics information after an SQL statement executes. A TAL program can call SQL system procedures in the same manner that it might call other system procedures such as OPEN, READ, WRITEREAD, and CLOSE. The $SYSTEM.SYSTEM.EXTDECS file contains source declarations of these procedures 1-3

Introduction Using Static SQL Statements that you can include in your program. This example shows a call to the SQLCADISPLAY procedure using all default parameters.?source $SYSTEM.SYSTEM.EXTDECS (SQLCADISPLAY)... CALL SQLCADISPLAY (SQLCA);! Process errors or statistics from the SQLCA structure... For more information, see Section 4, System Procedures. Using Static SQL Statements You can embed static SQL statements in both TAL data declarations and TAL executable statements. Figure 1-1 on page 1-5 shows an example of static SQL statements embedded in a TAL program. In this example, the program inserts a row in the PARTS table, which has the columns PARTNUM, PRICE, and PARTDESC. This example also declares data items as host variables so that they can contain input values for the columns of the row. 1-4

Introduction Using Dynamic SQL Operations Figure 1-1. Static SQL Statements in a TAL Program! TAL variable declarations: EXEC SQL BEGIN DECLARE SECTION;! SQL host variable declarations STRUCT.in^parts^rec; BEGIN INT in^partnum; FIXED(2) in^price; STRING in^partdesc[0:17]; END; EXEC SQL END DECLARE SECTION;...! Procedure Code: in^parts^rec.in^partnum := 4120; in^parts^rec.in^price := 60000.00F;! Blank fill in^partdesc: in^parts^rec.in^partdesc ':=' [ $OCCURS(in^parts^rec.in^partdesc) * [" "] ]; in^parts^rec.in^partdesc ':=' "V8 DISK OPTION"; EXEC SQL INSERT INTO SALES.PARTS ( PARTNUM, PRICE, PARTDESC) VALUES (:in^parts^rec.in^partnum, :in^parts^rec.in^price, :in^parts^rec.in^partdesc);... VST0101.vsd For other examples of static SQL programming, see Section B, Examples of Static NonStop SQL Programs. Using Dynamic SQL Operations A dynamic SQL operation enables a TAL program to construct, compile, and execute an SQL statement at run time. With a static SQL operation, you code the SQL statement to be executed in the source file; however, with a dynamic SQL operation, you code only the host variable that will contain the SQL statement. A dynamic SQL operation requires some input, usually from a user at a terminal, to construct the final statement. The SQL statement is constructed from the user s input, compiled by the SQL compiler, and then executed using an EXECUTE or EXECUTE IMMEDIATE statement. 1-5

Introduction Using Dynamic SQL Operations Figure 1-2 shows a dynamic SQL operation that uses an INSERT statement similar to the static INSERT statement in Figure 1-1 on page 1-5. In Figure 1-1 on page 1-5, the static INSERT statement is embedded in the source program code; however, in Figure 1-2, the program dynamically builds the INSERT statement from information entered by a user. The program in Figure 1-2 accesses the PARTS table, which has the same file name, but resides on a different subvolume. When this program runs, it prompts a user for information to build the INSERT statement. The user enters this information in the INTEXT variable to specify the specific PARTS table and other values needed to construct the INSERT statement: INSERT INTO $vol5.sales.parts partnum, price, partdesc) VALUES (4120, 60000.00, "V8 DISK OPTION") The program builds the INSERT statement from the information in INTEXT and moves the statement to the host variable OPERATION. The program has declared OPERATION as a host variable, so that it is available to both TAL and SQL statements. The program then uses the EXECUTE IMMEDIATE to execute the INSERT statement in OPERATION. Figure 1-2. Dynamic SQL Statements in a TAL Program! TAL data declarations EXEC SQL BEGIN DECLARE SECTION; STRING operation[0:199];! Host variable EXEC SQL END DECLARE SECTION;! TAL procedure! Copy intext into :operation host variable...! Execute the SQL statement: EXEC SQL EXECUTE IMMEDIATE :operation;... VST0102.vsd For more information, see Section 7, Dynamic NonStop SQL Operations and Section C, Examples of Dynamic NonStop SQL Programs. 1-6

Introduction Compiling and Executing a Program Compiling and Executing a Program Compiling and executing a TAL program that contains embedded SQL statements is similar to the steps you use for a TAL program that does not contain embedded SQL statements. You must perform only one extra step: you compile the SQL statements using the SQL compiler. These steps are shown in Figure 1-3. 1. Compile your source file (or files) using the TAL compiler. The TAL compiler generates an object file for each compilation. Each object file contains TAL object code and SQL source statements. 2. Use the Binder program, if necessary, to combine multiple object files into one object file or to specify the TALLIB run-time library if you did not include it during the TAL compilation in Step 1. 3. Optionally, run the Accelerator on the object file generated from Step 1 or 2 if you plan to run the object file on a TNS/R system. 4. Compile the SQL statements in the TAL object file using the SQL compiler. 5. Run the object file from a terminal using the TACL RUN (or RUND) command or from a process using a system procedure such as NEWPROCESS. 1-7

Introduction Compiling and Executing a Program Figure 1-3. Compiling and Executing a Program TAL/SQL Source File (s) 1 Run the TAL compiler for each source file TAL Compiler 2 Run the Binder program (if necessary) Binder Process 3 Run the Accelerator (optional step for TNS/R systems only) Accelerator 4 Run the SQL compiler 5 Run the object file SQL Compiler TAL/SQL Object File VST0103.vsd For more information, see Section 5, Program Compilation and Execution. 1-8

2 Host Variables and Parameters This section describes the data items that you use to provide for communication between TAL and SQL statements in a TAL program. Host Variables A host variable is a data item you can use in both TAL and SQL statements to provide for communication between the two types of statements. For static SQL operations, a host variable can be an input or output variable (or both in some cases) in SQL statements. An input variable transfers data from the program to the database, while an output variable transfers data from the database to the program. (For dynamic SQL operations, input parameters and output variables fulfill the same function as input and output host variables in static SQL statements.) A host variable can be a: Simple variable Whole STRING array (SQL type DECIMAL or CHAR) Element in an array Indirect array or structure (including standard and extended indirection) Structure that conforms to SQL data type VARCHAR Field in a structure SQLDA structure However, a host variable cannot be a: Constant TAL DEFINE identifier Variable of TAL data type UNSIGNED Pointer TAL array of type other than STRING Structure except VARCHAR and SQLDA structures A host variable can be any TAL data item that has a corresponding SQL data type as shown in Table 2-1 on page 2-3. NonStop SQL must be able to convert the data between the two data types. If your program returns a TAL assignment expression to a host variable, the TAL compiler must be able to convert the value of the expression to the data type of the host variable. 2-1

Host Variables and Parameters Declaring Host Variables Declaring Host Variables You declare host variables in a Declare Section in the variable declarations of your program. You can use multiple Declare Sections in a TAL program, but you cannot nest the sections. The SQL directives that delimit a Declare Section are BEGIN DECLARE SECTION and END DECLARE SECTION. Use TAL naming conventions for your host variables. Host variable names (and indicator variable names): Can contain from 1 to 31 alphanumeric characters including the circumflex (^) and the underscore (_) Must begin with a letter, circumflex, or underscore To prevent naming conflicts, avoid ending your names with an underscore. Examples of host variable declarations are: EXEC SQL BEGIN DECLARE SECTION;! host variables STRING.buffer[0:length]; INT number[0:9]; STRUCT.s^buffer; BEGIN INT buffer_length; STRING text[0:2046]; END; EXEC SQL END DECLARE SECTION; For information about using the INVOKE directive to create host variables, see Section 3, NonStop SQL Statements and Directives Using Corresponding SQL and TAL Data Types Table 2-1 on page 2-3 shows the corresponding NonStop SQL and TAL data types. If you have an SQL data type shown in the left column and you want to send data to a variable with that data type or receive data from a variable with that data type, declare a TAL host variable as shown in the right column. 2-2

Host Variables and Parameters Using Corresponding SQL and TAL Data Types Table 2-1. Corresponding NonStop SQL and TAL Data Types SQL Data Type Character Data CHAR(n), PIC X(n) VARCHAR(n) TAL Data Type STRING [0: n - 1] STRUCT identifier; BEGIN INT length; STRING value[0: n-1]; END; Numeric Data NUMERIC (1 to 4, s) SIGNED INT NUMERIC (1 to 4, s) UNSIGNED INT / SMALLINT UNSIGNED / 1 NUMERIC (5 to 9, s) SIGNED INT(32) NUMERIC (5 to 9, s) UNSIGNED INT(32) / INTEGER UNSIGNED/ 1 NUMERIC (10 to 18, s) SIGNED FIXED(s) PIC [s]9(n- s)v9(s) [COMP] Same as TAL data types for NUMERIC DECIMAL(n, s) STRING[0: n-1] / DECIMAL / 1 DECIMAL(n, s) UNSIGNED STRING[0: n-1] /DECIMAL UNSIGNED/ 1 PIC[s] 9(n- s)v9(s) SMALLINT INT SMALLINT UNSIGNED INT / SMALLINT UNSIGNED / 1 INTEGER INT(32) INTEGER UNSIGNED INT(32) / INTEGER UNSIGNED / 1 LARGEINT SIGNED FIXED(0) FLOAT (1 to 22), REAL REAL Date-Time Data DATETIME, TIMESTAMP, DATE, TIME STRING [0: n-1] INTERVAL Data INTERVAL STRING[0: n] 2 n is a positive integer that represents the length. For DECIMAL, n must range from 1 through 18. s is a positive integer that represents the scale of the number. 1 SQL data types between slashes specify override data type mapping (on page 2-4). 2 A host variable for an INTERVAL value has an extra byte to hold a sign. 2-3

Host Variables and Parameters Using Corresponding SQL and TAL Data Types Data Conversion NonStop SQL performs the conversion from SQL data types to TAL data types and from TAL data types to SQL data types as follows: When a host variable serves as an input variable (supplies a value to the database), the system first converts the value that the variable contains to a compatible SQL data type and then uses the value in the SQL operation. When a host variable serves as an output variable (receives a value from a database), the system converts the value to the data type of the host variable. NonStop SQL supports conversion within character types and numeric types, but it does not support conversion between character and numeric types. The SQL date-time and INTERVAL types are compatible only with TAL STRING types (and the STRING host variable used to store the date-time or INTERVAL value must have a TYPE AS clause). For more information, see Using Date-Time and INTERVAL Data Types as Host Variables on page 2-15. For conversion between character strings of different lengths, NonStop SQL pads the receiving string on the right with blanks as necessary. If the receiving string is too short, NonStop SQL truncates the right part of the longer string and returns a warning code in the SQLCODE variable. If an input value is too large for an SQL column, NonStop SQL returns error 8300 (filesystem error encountered). If you are using the SQLCADISPLAY procedure to obtain an error message, SQLCADISPLAY also returns file-system error number 1031. For conversion between numeric types, NonStop SQL converts data between signed and unsigned types and between types with different precisions. You can use the SETSCALE function to communicate a number s scale to and from a database. Examples of host variable declarations using the default data types are: EXEC SQL BEGIN DECLARE SECTION;! SQL recognizes address as a SMALLINT host variable INT address;! SQL recognizes name as a CHAR(20) host variable STRING.name[0:19];!SQL recognizes message as a VARCHAR(200) host variable STRUCT.message; BEGIN INT msg^length; STRING text[0:199]; END; EXEC SQL END DECLARE SECTION; 2-4

Host Variables and Parameters Overriding Default Data Types Overriding Default Data Types Each TAL data type has a default SQL data type used by the SQL compiler. In most cases, you can define your host variables to match the SQL data types shown in Table 2-1 on page 2-3. Sometimes, however, you might want to use another data type. Some TAL data types allow you to override the default type by specifying an override SQL data type as an attribute of the host variable. The syntax to override a data type is: TAL-type hostvar-name [array-bounds] [/ override-sql-type/] TAL-type is the TAL data type plus any indirection symbol. For example: INT INT(32) INT. INT.EXT hostvar-name is the name of the host variable. array-bounds is the bounds of an array. For example, in the declaration: INT numbers[0:19]; [0:19] is the bounds. override-sql-type is the SQL data type that will override the default type that NonStop SQL normally uses for TAL-type. Specify override-sql-type after the host variable and any array bounds but before initialization or address equivalence takes place. Also, when you use a host variable in an SQL statement, you can override character data types by using the: TYPE AS clause to specify that the character string should be interpreted as a date-time value. The TYPE AS clause is described under Using Date-Time and INTERVAL Data Types as Host Variables on page 2-15. SETSCALE function to indicate that an integer host variable is to be interpreted as having scale. SETSCALE is described under Using Scaled Numeric Data Items as Host Variables on page 2-12. Table 2-2 shows how NonStop SQL interprets TAL data types, and the override data types you can specify. 2-5

Host Variables and Parameters Using Host Variables Table 2-2. Default and Override Data Type Mapping TAL Data Type Default SQL Data Type Override SQL Data Type STRING CHAR(1) / DECIMAL(1) / / DECIMAL(1) UNSIGNED / STRING[0: n-1] CHAR(n) / DECIMAL(n) / * / DECIMAL(n) UNSIGNED / * INT SMALLINT / SMALLINT UNSIGNED / INT(32) INTEGER / INTEGER UNSIGNED / FIXED(0) LARGEINT - FIXED(s) LARGEINT(s) ** - REAL REAL - REAL(64) DOUBLE PRECISION - STRUCT SQLDA VARCHAR(n) *** - n is a positive integer that represents the length. s is a positive integer that represents the scale of the number. * For DECIMAL types, n must be in the range 1 through 18. ** LARGEINT(s) type is used internally to SQL, but it is not an SQL type. *** The default is the SQLDA unless the structure conforms to type VARCHAR (see Table 2-1 on page 2-3). Examples of overriding default data type mapping are: EXEC SQL BEGIN DECLARE SECTION;! SQL recognizes empid as a DECIMAL(10) host variable STRING.empid[0:9]/DECIMAL(10)/;! SQL recognizes partnum as a SMALLINT UNSIGNED host variable INT partnum /SMALLINT UNSIGNED/;! SQL recognizes size as an INTEGER UNSIGNED host variable INT(32) size /INTEGER UNSIGNED/; EXEC SQL END DECLARE SECTION; Using Host Variables After you declare a host variable, you can use the variable in an SQL statement just as you would in a TAL statement, except that you must precede the host variable name with a colon(:). The colon causes the TAL compiler to treat the name as a host 2-6

Host Variables and Parameters Using Host Variables variable. The syntax for using a host variable in an SQL statement is shown below. For a complete description of this syntax, see the SQL/MP Reference Manual. :host-identifier[[ INDICATOR ]: indicator-host-identifier ] [ TYPE AS {DATETIME [start-date-time TO] end-date-time } ] [ { } ] [ {DATE } ] [ { } ] [ {TIME } ] [ { } ] [ {TIMESTAMP } ] [ { } ] [ {INTERVAL start-date-time } ] [ { [ ( start-field-precision ) ] } ] [ { [ TO end-date-time ] } ] :host-identifier is a TAL data item. Use :host-identifier in DML statements where a literal can be used (except in the INVOKE and INCLUDE directives). INDICATOR is a keyword that allows for: Handling null values that might be returned to the host variable Inserting null values into the database through the host variable :indicator-host-identifier is an indicator variable with type INT. For values returned to a host variable, : indicator-host-identifier is: -1 if the value is null 0 if the value is not null To insert t null values into the database, set : indicator-host-identifier to a value less than zero. TYPE AS directs NonStop SQL to treat the variable as a date-time (DATETIME, DATE, TIME, or TIMESTAMP) or INTERVAL value. To direct NonStop SQL to treat the host variable as a scaled value, either define the variable as TAL data type FIXED or use the SETSCALE function, which is described under Using Scaled Numeric Data Items as Host Variables on page 2-12. 2-7

Host Variables and Parameters Using Host Variables Using Structures as Host Variables Follow the guidelines below when you declare and use structures or fields within structures as host variables. INVOKE Directive. Use the INVOKE directive to declare structure descriptions corresponding to SQL tables and views. The structure fields (which correspond to the columns in the table or view) become host variables. For information about using the INVOKE directive to create host variables, see Creating Host Variables With the INVOKE Directive on page 2-20. VARCHAR Type. Declare host variables that correspond to the SQL VARCHAR type as TAL structures. See Table 2-1 on page 2-3 for an example of the TAL structure. For these structures, you can refer to both the TAL structure name and the individual fields; however, only the structure name is recognized as a host variable of SQL type VARCHAR. Structure Name References. You can refer to a structure name as a host variable only if the structure: Represents an item of SQL type VARCHAR Is an SQLDA Has an array of type STRING as its only field For other TAL structures, you can refer to only the individual fields in the structure as host variables, but you cannot refer to the structure name. Except for the above cases, you must use the structure name with the field name to reference a host variable that is a field within a structure. For example, the structure named EMPLOYEE^INFO contains the EMPID, EMPNAME, and SALARY host variables. EXEC SQL BEGIN DECLARE SECTION; STRUCT.employee^info; BEGIN STRING empid[0:9]; STRING empname[0:19]; FIXED(2) salary; END; EXEC SQL END DECLARE SECTION; When you use these host variables in an SQL statement, refer to them by the structure and field names. For example: EXEC SQL SELECT empid, empname, salary INTO :employee^info.empid, :employee^info.empname, :employee^info.salary FROM =employee WHERE empid = 12345; 2-8

Host Variables and Parameters Using Host Variables Structure Pointers. Although you cannot use a pointer by itself as a host variable, you can refer to a field in a structure by using a structure pointer. For example, you can use this host variable declaration and reference:! Declaration: EXEC SQL BEGIN DECLARE SECTION; STRUCT s^template(*); BEGIN INT field1;! Fields cannot be pointers in SQL INT field2; END; STRING.EXT s^ptr (s^template);! Structure pointer EXEC SQL END DECLARE SECTION;! Reference: EXEC SQL SELECT col1 INTO :s^ptr.field1 FROM tbl1; You can also use a structure as a host variable by: Using array indexing within the structure Allowing a field in the structure to be a substructure or an array These examples show TAL structures that you can use as host variables:! Substructures and array within a structure: STRUCT.outer^struct;! Structure BEGIN INT int^array[0:4];! Array STRUCT sub^struct^1;! Substructure BEGIN STRUCT sub^struct^2;! Substructure BEGIN INT int^1; INT int^2; END; END; END;! A three-dimensional structure of VARCHAR items: STRUCT.first^dim[0:3]; BEGIN; STRUCT second^dim[0:3]; BEGIN STRUCT third^dim[0:3]; BEGIN INT len; STRING name[0:19]; END; END; END; 2-9

Host Variables and Parameters Using Host Variables! Reference to an integer within an array! of integers in a structure: EXEC SQL SELECT integer^value INTO :outer^struct.int^array[1] FROM table1;! A reference to an integer within nested structures: EXEC SQL SELECT integer^value INTO :outer^struct.nested^struct^1.nested^struct^2.int^1 FROM table1;! A reference to a VARCHAR item: EXEC SQL SELECT character^string INTO :first^dim.second^dim.third^dim FROM table1; In this example, after the VARCHAR item is accessed, NonStop SQL sets: FIRST^DIM.SECOND^DIM.THIRD.DIM.NAME to CHARACTER^STRING FIRST^DIM.SECOND^DIM.THIRD.DIM.LEN to the byte length of CHARACTER^STRING Structures as Character Host Variables. A value from an SQL column of SQL data type CHAR can be stored into a host variable that is a structure containing a single array of TAL type STRING. Reference the structure either directly through the structure name, or indirectly through a structure pointer. In this example, PEOPLE is an SQL table that contains the 10-character column EMPNAME. You can use the names DIRECT^STRUCT, INDIRECT^STRUCT, and STRUCT^POINTER as host variables to store EMPNAME.! Host variable declarations: EXEC SQL BEGIN DECLARE SECTION; STRUCT direct^struct; BEGIN STRING name [0:9]; END; INT.struct^pointer(direct^struct); STRUCT.indirect^struct; BEGIN STRING name [0:9]; END; EXEC SQL END DECLARE SECTION; To use the host variable DIRECT^STRUCT, specify: EXEC SQL SELECT empname INTO :direct^struct FROM people; If you make STRUCT^POINTER point to DIRECT^STRUCT, you can also specify: EXEC SQL SELECT empname INTO :struct^pointer FROM people; 2-10

Host Variables and Parameters Using Host Variables To use the host variable INDIRECT^STRUCT, specify: EXEC SQL SELECT empname INTO :indirect^struct FROM people; If you make STRUCT^POINTER point to INDIRECT^STRUCT, you can also specify: EXEC SQL SELECT empname INTO :struct^pointer FROM people; Using Arrays as Host Variables Follow these guidelines when you declare and use arrays as host variables. The TAL compiler interprets STRING arrays of length [0: size - 1] as one of these SQL data types: CHAR(size) DECIMAL(size), if you specified overriding the default data type Date-time or INTERVAL, if you used the TYPE AS clause The size of a STRING array does not have to match the size of the character field in the VARCHAR column, CHAR column, or the date-time or INTERVAL column. NonStop SQL pads or truncates the value to fit the host variable. For arrays of a data type other than STRING, the size of an array element must be compatible with the size of the SQL column. Using STRING Parameters as Host Variables Host variables that are passed as TAL STRING parameters require special consideration because TAL does not allow you to specify bounds on a parameter declaration. Use either of these two methods to handle this type of parameter: Declare the parameter as a structure. Declare an equivalenced local structure. Declaring the Parameter as a Structure. Declare the STRING parameter as a field in a structure. In SQL statements, always refer to the parameter as: structure-name.field-name However, when you pass the parameter, use the structure name (and not the field name). For example: STRUCT.struc; BEGIN STRING val [0:maxsize-1]; END; 2-11

Host Variables and Parameters Using Host Variables The declaration for the called procedure is: PROC process^cmd(struc); STRUCT.struc; BEGIN STRING val [0:maxsize-1]; END;... BEGIN EXEC SQL PREPARE dyn^cmd FROM :struc.val;... END; Declaring an Equivalenced Local Structure. Declare the parameter as a STRING array. In SQL statements that are within the scope of the STRING array's declaration, refer to the parameter using the STRING array name. Before the STRING array is passed to a procedure as a parameter, declare a local structure template with a STRING array as the only field, declare a pointer to that structure template, and equivalence the pointer to the STRING array that was passed as the parameter. In SQL statements local to the procedure, refer to the parameter as: structure-name. field-name For example, you might make these declarations and references: STRING.strng[0:maxsize-1];... PROC process^cmd(s); STRING.strng; BEGIN STRUCT strng^equiv(*); BEGIN; STRING val[0:maxsize-1]; END; STRING.new^strng(strng^equiv) = strng;.. ĖXEC SQL PREPARE new^cmd FROM :new^strng.val; END; Using Scaled Numeric Data Items as Host Variables Use one of these two methods to declare a host variable with scale: Declare the host variable using FIXED(n) data type, where n is the number of decimal places to the right of the decimal point. Declare the host variable with a numeric data type that is compatible with the SQL column, and then use the SETSCALE function to communicate the scale. 2-12

Host Variables and Parameters Using Host Variables Using the FIXED Data Type. This method is the simplest method to handle scale; follow these guidelines when you use it: The value stored in the FIXED host variable must fit into the database column. FIXED variables are stored in 64 bits and can hold 19 digits. You must ensure that the host variable never contains a value greater than will fit in the column; otherwise, NonStop SQL reports an error. For example, if the SQL column is defined as type NUMERIC (7,3), ensure that values in the corresponding host variable of type FIXED(3) are never greater than 9999.999 or smaller than -9999.999. If you use FIXED host variables, the SQL executor must use quadrupleword arithmetic to evaluate expressions. Using the SETSCALE Function. If you must ensure that a database column size matches the host variable size (for example, you might be transferring data between a NonStop SQL database and an Enscribe file), use a TAL numeric data type that corresponds to the data type of the SQL column. You can use the INVOKE directive and then use the SETSCALE function to communicate the scale between the TAL and SQL statements. If you use the SETSCALE function and your program must also use the host variables in calculations, include the necessary code to scale the values in the host variables. The SETSCALE function has this syntax: SETSCALE (: host-variable [ [INDICATOR] : indicator-variable ], scale ) : host-variable is a numeric host variable. INDICATOR : indicator-variable is an indicator variable associated with the host variable. For more information about using indicator variables to specify or read null values, see Using Date-Time and INTERVAL Data Types as Host Variables on page 2-15. scale is an integer that designates the scale of :host-variable. The values allowed for scale depend on the size of :host-variable as follows: Size TAL Type Values Allowed 2-byte integer INT 0 through 5 decimal digits 4-byte integer INT (32) 0 through 10 decimal digits 8-byte integer FIXED 0 through 18 decimal digits 2-13

Host Variables and Parameters Using Host Variables The SETSCALE function causes NonStop SQL to use :host-variable in the context of SQL statements as if :host-variable were declared with a scale of scale. For example, the sequence SETSCALE (hostvar, n) causes NonStop SQL to interpret the host variable hostvar as: hostvar * 10 - n If the value in :host-variable is to be entered into a database using an INSERT or UPDATE statement, the program must assign a value to :host-variable that allows for the scale. For example, if the program is representing a price of $123.45, then the program should assign 12345 to :host-variable and use SETSCALE to specify a scale of 2. If the value is retrieved from the database using a SELECT statement, NonStop SQL assigns a value to :host-variable that allows for the scale. For example, if the value 123.45 is stored in the database, then the value 12345 is returned to :host-variable when the program specifies SETSCALE with a scale of 2 in the SELECT statement. If the value 123 is stored in the database and the program specifies SETSCALE with a scale of 2, the value 12300 is returned to :host-variable. Caution. Consider these points when you use the SETSCALE function: At the upper boundary scale for each data type, you must ensure that the value returned from the database fits into the host variable. For example, if the host variable is specified to SETSCALE with a scale of 5 (the upper boundary on scale for a 2-byte integer) and the value 0.70000 is stored in the database, NonStop SQL sends a value of 70000, which does not fit in a variable of type INT. To use SETSCALE in an expression, you must apply SETSCALE to each host variable individually rather than to the result of the expression. For example, this expression adds two prices with a scale of 2 decimal places: SETSCALE (:price1, 2) + SETSCALE (:price2, 2) Remember to allow room in host variables for digits to the left of the decimal point. For example, if the value in the database is 12.345, and you specify a scale of 5, the output value, 1234500, will not fit in an INT host variable. These examples use a TACL DEFINE named =PARTS for the PARTS table. Using SETSCALE with the INSERT statement A program creates a new row with the value 98.34 in the PARTS.PRICE column after storing the value in the host variable :HOSTVAR1. The value is multiplied by 100 and stored in :HOSTVAR1.! Assign 9834 to :hostvar1 EXEC SQL INSERT INTO =parts (price) VALUES ( SETSCALE (:hostvar1, 2) ) ; 2-14

Host Variables and Parameters Using Host Variables Using SETSCALE with the UPDATE statement A program updates the PARTS.PRICE column for a disk controller to $158.34. The value is multiplied by 100 and stored in the host variable :HOSTVAR2.! Assign 15834 to :hostvar2 EXEC SQL UPDATE =parts SET parts.price = SETSCALE (:hostvar2, 2) WHERE parts.partdesc = "disk controller" ; Using SETSCALE with the SELECT statement for retrieving a value A program retrieves the value in the PARTS.PRICE column for a disk controller and stores the value in the host variable :HOSTVAR3. The value has a scale of 2. EXEC SQL SELECT parts.price INTO SETSCALE ( :hostvar3, 2 ) FROM =parts WHERE parts.partdesc = "disk controller" ; IF hostvar3/100 > 50000 THEN! (print message that manager approval! is required for purchase ) If the price of the disk controller is $60,000.00 in the database, :HOSTVAR3 has the value 6,000,000 on output. Using SETSCALE with the SELECT statement for comparisons A program retrieves the part description for the part with a price of $999.50. The price value is stored in the host variable :HOSTVAR4 and supplied to SQL in the search condition. The retrieved value is stored in the host variable :HVSTORE.! Assign 99950 to :hostvar4 EXEC SQL SELECT parts.partdesc INTO :hvstore FROM =parts WHERE parts.price = SETSCALE ( :hostvar4, 2 ); Using Date-Time and INTERVAL Data Types as Host Variables NonStop SQL provides a set of special data types for specifying: Date-time values including separate date and time values Intervals or durations of time Table 2-3 shows the date-time and INTERVAL data types. For more information on the complete syntax, see the SQL/MP Reference Manual. 2-15

Host Variables and Parameters Using Host Variables Table 2-3. Date-Time and INTERVAL Data Types Data Type DATETIME DATE TIME TIMESTAMP INTERVAL Description Represents a date, time, or date and time, from year to microsecond (logical subsets, such as MONTH TO DAY, are allowed) Represents a date and is a synonym for DATETIME YEAR TO DAY Represents a time and is a synonym for DATETIME HOUR TO SECOND Represents a date and time and is a synonym for DATETIME YEAR TO FRACTION(6) Represents a duration of time as a year-month or day-time interval To communicate date-time values between TAL and SQL statements, you declare a TAL STRING array as a host variable. Then you use the TYPE AS clause to cause NonStop SQL to interpret the value in the STRING host variable as a date-time or INTERVAL value. Some sample TYPE AS clauses are: TYPE AS DATETIME YEAR TO HOUR TYPE AS DATE TYPE AS TIME TYPE AS TIMESTAMP TYPE AS INTERVAL YEAR You can also use date-time and INTERVAL literals. For example, to insert a date-time or INTERVAL value using a literal into TABLE: EXEC SQL INSERT INTO table (START_DATE ) VALUES DATE "1990-03-21"; Or, to insert the value using a host variable:! Variable declarations: EXEC SQL BEGIN DECLARE SECTION; STRING datevar[o:9]; EXEC SQL END DECLARE SECTION;...! Procedure! Copy "1990-03-21" into datevar... EXEC SQL INSERT INTO table (START_DATE) VALUES :datevar TYPE AS DATE; You can insert or retrieve date-time values in any of three formats, independently of the SQL column definition. For example, you can specify formats such as 02/15/2004, 2004-02-15, or 15.02.2004. You control the display format by inserting the value in the 2-16

Host Variables and Parameters Using Indicator Variables for Null Values format you want and retrieving the value using the DATEFORMAT function. You should declare the host variable size to be consistent with the format you will use. If you use the INVOKE directive to generate host variables from an SQL table definition, you can specify the DATEFORMAT clause to create host variables of the appropriate size. For more examples of the INVOKE directive, see Section 3, NonStop SQL Statements and Directives. Using Indicator Variables for Null Values An indicator variable is a 2-byte integer variable defined in the Declare Section. An indicator variable is always associated with a host variable and is used to indicate whether a column can (or does) contain a null value. A null value in a column means that a value is either unknown for the row or does not apply to the row. When sending a value to NonStop SQL, a program sets the indicator variable to: Less than zero (0) for a null value Zero (0) for a nonnull value When returning a value to a program, NonStop SQL sets the indicator variable to: Less than zero (0) for a null value Zero (0) for a nonnull value The INVOKE directive automatically declares indicator variables for columns that allow null values. If SQL columns can contain null values, a program should use indicator variables when referring to those columns. For example, a program might: Insert null values into the database with an INSERT or UPDATE statement Retrieve null values from the database with a SELECT statement Specify null values in an INSERT, UPDATE, DELETE, or SELECT statement You can also use indicator variables with the INSERT, UPDATE, DELETE, and SELECT statements. You can use the keyword NULL, as shown in the subsequent examples in this section. 2-17

Host Variables and Parameters Using Indicator Variables for Null Values Inserting a Null Value These examples use indicator variables to insert a null value and to select from a column that can return a null value. the TACL DEFINEs =RETIREES and =SHIPMENTS are in effect for the respective tables. This example uses an indicator variable to insert a null value:! Variable declarations: EXEC SQL BEGIN DECLARE SECTION; INT empnum; STRING retire^date[0:9]; INT retire^ind;! indicator variable EXEC SQL END DECLARE SECTION;... PROC insert^data; BEGIN empnum := 22346; retire^ind := -1;... EXEC SQL INSERT INTO =retirees (empnum, retire_date) VALUES (:empnum, :retire^date INDICATOR :retire^ind);! It is not necessary to assign a value to! retire^date in order to specify a null value.... END; You can also use the NULL keyword instead of an indicator variable to insert a null value: PROC insert^data; BEGIN empnum := 22346; EXEC SQL INSERT INTO =retirees (empnum, retire_date) VALUES (:empnum, NULL );... END; 2-18

Host Variables and Parameters Using Indicator Variables for Null Values Selecting a Null Value This example selects data from the SHIPMENTS table and tests for null values using the indicator variable named PROD^REC.SHIP^IND:! Variable declarations: EXEC SQL BEGIN DECLARE SECTION; STRUCT.prod^rec; BEGIN INT prodnum; INT ship^ind; STRING date^shipped[0:9]; END; EXEC SQL END DECLARE SECTION;... EXEC SQL DECLARE c1 CURSOR FOR SELECT prodnum, date^shipped FROM =SHIPMENTS WHERE prodnum > 7999;...! Procedure code: WHILE sqlcode = 0 DO BEGIN EXEC SQL FETCH c1 INTO :prod^rec.prodnum, :prod^rec.date^shipped INDICATOR :prod^rec.ship^ind; IF prod^rec.ship^ind < 0 THEN...! display "?", "NULL", or other symbol to! indicate a null value. END; 2-19

Host Variables and Parameters Creating Host Variables With the INVOKE Directive Creating Host Variables With the INVOKE Directive You can use the INVOKE directive in a Declare Section to create host variables that correspond to the columns in an SQL table. INVOKE converts the column names to TAL identifiers and writes a TAL data description for each column. If a column allows a null value, INVOKE also generates an indicator variable for the column. Caution. If you use INVOKE and later change data types in your SQL tables, you must ensure that numeric constants in the TAL program also change to reflect the new data types; otherwise, the program will not compile. For example, if host variable :PARTNUM is originally defined as an integer (INT), the test:: IF partnum > 1000 is valid. However, if the :PARTNUM column is changed to INVOKE statement with the data type INT(32), the test must be: IF partnum > 1000D Table 2-4 shows the override data type mapping used by the INVOKE directive. Table 2-4. INVOKE Directive Override Data Type Mapping SQL Data Type Host Variable Description Generated by the INVOKE Directive SMALLINT INT name / SMALLINT UNSIGNED / UNSIGNED INTEGER INT(32) name / INTEGER UNSIGNED / UNSIGNED NUMERIC (1-4, UNSIGNED INT name / SMALLINT UNSIGNED / s) NUMERIC (5-9, UNSIGNED INT(32) name / INTEGER UNSIGNED / s)6 DECIMAL(1) STRING name / DECIMAL(1) / DECIMAL(1) UNSIGNED STRING name / DECIMAL(1) UNSIGNED / DECIMAL (n) STRING name [0 : n - 1] / DECIMAL(n) / DECIMAL (n) UNSIGNED STRING name [0 : n - 1] / DECIMAL (n) UNSIGNED / name is the name of the host variable. n is a positive integer that represents the length. s is a positive integer that represents the scale of the number. This example shows the TAL compiler output for a table that contains columns of the TAL data types. This example includes the INVOKE directive as it appears in the source program, the CREATE TABLE statement that defines the table, and the generated structure type. The table contains columns of all SQL data types. INVOKE generates override data type mapping for some data types. 2-20

Host Variables and Parameters Creating Host Variables With the INVOKE Directive The INVOKE directive as it appears in the source program is: EXEC SQL BEGIN DECLARE SECTION; EXEC SQL INVOKE typestbl AS types^rec; EXEC SQL END DECLARE SECTION; The CREATE TABLE statement that defines the table is: CREATE TABLE $vol.sales.typestbl ( a_char CHAR (10) NOT NULL, b_varchar VARCHAR (10) NOT NULL, c_num4_s NUMERIC (4) SIGNED NOT NULL, d_num4_u NUMERIC (4) UNSIGNED NOT NULL, e_num9_s NUMERIC (9,2) SIGNED NOT NULL, f_num9_u NUMERIC (9,2) UNSIGNED NOT NULL, g_num18_s NUMERIC (18,2) SIGNED NOT NULL, h_small_s SMALLINT SIGNED NOT NULL, j_small_u SMALLINT UNSIGNED NOT NULL, k_int_s INTEGER SIGNED NOT NULL, l_int_u INTEGER UNSIGNED NOT NULL, m_large_s LARGEINT SIGNED NOT NULL, n_dec_s DECIMAL (18,2) SIGNED NOT NULL, o_dec_u DECIMAL (9,2) UNSIGNED NOT NULL, p_cob_p9 PIC 9(9) COMP NOT NULL, q_cob_px PIC X(10) NOT NULL, z_long PIC X(20) NOT NULL, a_dbl FLOAT (15) NOT NULL, b_dbl FLOAT (30) NOT NULL, c_dbl REAL NOT NULL, d_dbl DOUBLE PRECISION NOT NULL, a_dt_time DATETIME YEAR TO DAY NOT NULL, b_dt_time DATE NOT NULL, c_dt_time TIME NOT NULL, d_dt_time TIMESTAMP NOT NULL, e_dt_time INTERVAL MONTH(6) NOT NULL ) CATALOG $vol1.sales ; 2-21

Host Variables and Parameters Creating Host Variables With the INVOKE Directive The generated structure template is: struct types^rec(*); BEGIN string a^char[0:9]; struct b^varchar; begin int len; string val [0:9]; end; int c^num4^s; int d^num4^u /SMALLINT UNSIGNED/; int(32) e^num9^s;!scale is 2 int(32) f^num9^u /INTEGER UNSIGNED/;!scale is 2 fixed(2) g^num18^s;!scale is 2 int h^small^s; int j^small^u /SMALLINT UNSIGNED/; int(32) k^int^s; int(32) l^int^u /INTEGER UNSIGNED/; fixed(0) m^large^s; string n^dec^s [0:17] /DECIMAL(18)/;!scale is 2 string o^dec^u [0:8] /DECIMAL(9)UNSIGNED/;!scale is 2 int(32) p^cob^p9 /INTEGER UNSIGNED/; string q^cob^px [0:9]; string z^long [0:19]; real a^dbl; real(64) b^dbl; real c^dbl; real(64) d^dbl; string a^dt^time [0:9]; string b^dt^time [0:9]; string c^dt^time [0:7]; string d^dt^time [0:25]; string e^dt^time [0:6]; END; To use the table in your program, declare a structure as: STRUCT.tbl(types^rec);! Declare an instance, tbl, of! the template, types^rec 2-22

Host Variables and Parameters Parameters Your program can now read the values stored in the columns of the SQL table into the host variables. For example: EXEC SQL SELECT typestbl.a_char, typestbl.a_dbl INTO :tbl.a^char, :tbl.a^dbl; Parameters A parameter is a place holder variable in an SQL statement that enables you to specify run-time input in a dynamic SQL statement. You compile the SQL statement without the input values and then supply the values when the statement is executed. The syntax for a parameter is shown below. For a complete description of the parameter syntax elements, see the SQL/MP Reference Manual.?[ identifier] [ [ INDICATOR ]?[indicator-parameter] ] [ TYPE AS {DATETIME [ start-date-time TO] end-date-time} ] [ { } ] [ {DATE } ] [ { } ] [ {TIME } ] [ { } ] [ {TIMESTAMP } ] [ { } ] [ {INTERVAL start-date-time } ] [ { [ ( start-field-precision ) ] } ] [ { [ TO end-date-time ] } ] identifier is an SQL identifier that is the name of the parameter. Follow these guidelines when you declare and use parameter names: You cannot qualify a parameter name. An unnamed parameter, which is a question mark (?) by itself, is always a distinct parameter even with multiple occurrences in a statement. You can use a parameter name in any SQL statement (except a DDL statement) where a numeric or string literal is allowed. indicator-parameter is the indicator parameter name. The indicator parameter has the same format as the parameter name with which it is associated. You use an indicator parameter to handle null values that might be returned to the parameter or to insert null values into a database through the parameter. For handling a null value returned to the parameter, the value of identifier can be 1 if the value is null or 0 if the value is not null. For inserting a value into a database, set indicator-param to 1 (null) or 0 (not null) before executing the INSERT or UPDATE statement. 2-23

Host Variables and Parameters Using a Parameter List TYPE AS... indicates that NonStop SQL should treat the value entered for the parameter as a date-time or INTERVAL value. A parameter that represents a date-time or INTERVAL value must have a character data type. Using a Parameter List To ensure a one-to-one correspondence between a parameter list and the host variables that you use to supply values for the parameters, use unnamed parameters. If duplicate parameter names appear in a statement, the names require a value for only the first occurrence, and the duplicate occurrences receive the same value. Suppose that the following UPDATE statement is stored in the host variable :UPDATE^STMT: UPDATE table SET col1 =?a, col2=?a, col3 =?b A PREPARE statement prepares the statement in the host variable :UPDATE^STMT: PREPARE exec^stmt FROM :update^stmt To supply values for the UPDATE statement at run time, the program uses the two host variables :HOST^VAR1 and :HOST^VAR2 : EXECUTE exec^stmt USING :host^var1, :host^var2 The value stored in HOST^VAR1 is used for both instances of the parameter named?a. The value stored in :HOST^VAR2 is used for the parameter named?b. If you use three host variables, NonStop SQL uses the value in the first host variable for both occurrences of parameter?a. The value in the second host variable is used for parameter?b, and the value in the third host variable remains unused. For example, in this statement: EXECUTE exec^stmt USING :host^var1, :host^var2, :host^var3; NonStop SQL uses the value in :HOST^VAR1 for both occurrences of parameter?a and the value in :HOST^VAR2 for parameter?b. The value in :HOST^VAR3 is ignored. Caution. If you use the same parameter name more than once in a statement, NonStop SQL gives each duplicate occurrence of the parameter the same data type, length, and other attributes as the first occurrence.thus, data can be lost in some cases. For example, during the execution of an INSERT statement, a parameter gets the same data type and attributes as the column into which the parameter s value is first inserted. If the parameter value is truncated to fit into the column, the values of any duplicate occurrences of the parameter are also truncated, even if a column is large enough to hold the complete value. 2-24

Host Variables and Parameters Using Parameters in Loops Using Parameters in Loops Parameters are often used when a dynamic SQL statement is executed repeatedly with different input values. In this example, a dynamic SQL statement uses a parameter. Because the user of this program can enter any SQL statement, the program does not have compile-time information about the statement. The TACL DEFINE named =PARTS represents the PARTS table. 1. A user enters this SQL statement from a terminal: UPDATE =parts SET price =?p 2. The program copies the statement into the host variable named :INTEXT. 3. The program uses the PREPARE and DESCRIBE INPUT statements to get a description of the parameter in the input SQLDA (IN^SQLDA) and to get the name of the parameter in the input names buffer (I^NAMESBUF). The prepared statement is named EXEC^STMT. EXEC SQL PREPARE exec^stmt FROM :intext; EXEC SQL DESCRIBE INPUT s1 INTO :in^sqlda NAMES INTO :i^namesbuf; 4. The program enters a loop to prompt the user to supply values for successive execution of the statement:! Beginning of loop! Prompt the user for a value using the parameter! name from the names buffer...! Store the value in a value buffer pointed to by in^sqlda! Execute the statement using each successive value: EXEC SQL EXECUTE s1 USING DESCRIPTOR :in^sqlda;! End of loop Using Indicator Parameters A program uses an indicator parameter to show that a null value was entered for a parameter. The indicator parameter follows the parameter in the SQL statement. For example: INSERT INTO =employee VALUES (1000,?p INDICATOR?i ); If a user enters a null value for?p, the program should set?i to a value less than zero. If a user enters a nonnull value, the program should set?i to 0. Both?P and?i are in the names buffer to allow prompting the user for a null value. For more information and examples for using parameters in dynamic SQL statements, see Section 7, Dynamic NonStop SQL Operations 2-25

Host Variables and Parameters Using Default Parameter Data Types Using Default Parameter Data Types If the TYPE AS clause is omitted from a dynamic SQL statement that uses date-time or INTERVAL data types with parameters, NonStop SQL assigns a default data type to a parameter as follows: INTERVAL DATETIME DATETIME NUMERIC The parameter name is followed by a range of fields and startfield-precision is specified. The parameter name is followed by a range of fields and startfield-precision is not specified The expression takes any of these forms: parameter-name { + - } interval-term interval-expression + parameter-name date-time-expression - parameter-name The expression takes any of these forms: parameter-name { + - } scalar-value { + - } parameter-name For more information about parameters in dynamic SQL statements, see Section 7, Dynamic NonStop SQL Operations. For examples that use parameters in dynamic SQL statements, see Appendix C, Examples of Dynamic NonStop SQL Programs. 2-26

3 NonStop SQL Statements and Directives This section describes: NonStop SQL statements and directives that you can embed in a TAL program SQL, SQLMEM, and SYMBOLPAGES TAL compiler directives The NonStop SQL statements and directives that are described in this section have specific TAL data structures, considerations, and examples. For the complete description and syntax of all NonStop SQL statements and directives, see the SQL/MP Reference Manual. For a description of all TAL compiler directives, see the TAL Reference Manual. Embedding SQL Statements and Directives An SQL statement or directive embedded in a TAL program must begin with the keywords EXEC SQL and end with a semicolon (;) or an END, ELSE, or UNTIL keyword according to TAL statement separator conventions. The syntax is: EXEC SQL sql-statement-or-directive [;] sql-statement-or-directive is an SQL statement or directive that is allowed in a TAL program as shown in Table 3-1 on page 3-4. You terminate an embedded SQL statement or directive as follows: In the data declarations, terminate an SQL statement or directive with a semicolon: EXEC SQL BEGIN DECLARE SECTION;! SQL directive INT.name ;! Host variable EXEC SQL END DECLARE SECTION;! SQL directive In the executable statements, terminate an SQL statement with a semicolon except before an END, ELSE, or UNTIL keyword as appropriate for the TAL statement: IF in^numvars > 0 THEN EXEC SQL EXECUTE state^ment^1 USING DESCRIPTOR :sdao ELSE EXEC SQL EXECUTE state^ment^2; 3-1

NonStop SQL Statements and Directives Coding Statements and Directives Coding Statements and Directives In general, consider embedded SQL statements and directives as if they are TAL statements. Follow the same formatting and line continuation conventions for SQL statements as you use for TAL statements. Here are a few specific guidelines to follow when you embed SQL statements and directives in a TAL program: You can code longer statements or directives on more than one line. For example: EXEC SQL SELECT customer.custname INTO :customer.custname FROM sales.customer WHERE custnum = :find^this^customer; Use either SQL or TAL comments in statements and directives. An SQL comment statement begins with a double hyphen (--) and ends with the end of the line. A TAL comment statement can also begin with a double hyphen (--) and end with the end of the line, or it can begin with an exclamation point (!) and end with another exclamation point or the end of the line. Use either a single quotation mark (') or double quotation marks (") to delimit string literal statements; however, you must use the same character at both ends of the string. Do not use an SQL statement as part of a compound TAL statement. Do not use a TAL DEFINE declaration in an SQL statement. Placing Statements and Directives in a Program Place SQL statements and directives in a TAL source file as described next: SQL Directive To embed SQL statements and directives in a TAL program, specify the SQL directive before any SQL or TAL declarations and source code statements (including comment statements). The SQL directive enables the TAL compiler to process subsequent SQL statements and directives. Specify the SQL directive either in your source code file or as a compiler option in the implicit TACL RUN command for the TAL compiler. An example of the SQL directive in a source code file is:?sql An example of the SQL directive as a compiler option is: TAL /IN tsrc, OUT $s.#tlst, NOWAIT/ tobj; SQL 3-2

NonStop SQL Statements and Directives Placing Statements and Directives in a Program SYMBOLPAGES Directive To use the SYMBOLPAGES directive, specify it as a compiler option in the RUN command line for the TAL compiler when you compile the program: TAL /IN tsrc, OUT $s.#tlst, NOWAIT / tobj; SYMBOLPAGES 2048 Data Declarations With TAL variable declarations, you can use the: BEGIN DECLARE SECTION and END DECLARE SECTION directives DECLARE CURSOR statement (static cursor only, global declarations only) INCLUDE SQLCA, INCLUDE SQLSA, and INCLUDE SQLDA directives INVOKE directive CONTROL directives Executable Statements With TAL executable statements, you can use the: Data Control Language (DCL) statements and CONTROL directives Data definition language (DDL) statements Data manipulation language (DML) statements Dynamic SQL statements (including DECLARE CURSOR) Transaction control statements Data Declarations and Executable Statements Use these directives anywhere in a TAL program: TAL SOURCE and SEARCH directives SQL SQLMEM directive (however, you cannot use SQLMEM with the STACK option in a subprocedure) SQL WHENEVER directive 3-3

NonStop SQL Statements and Directives Locating Information About SQL Statements and Directives Locating Information About SQL Statements and Directives Table 3-1 summarizes the NonStop SQL statements and directives by type and the manual that documents each statement or directive. The remainder of this section describes the NonStop SQL statements and directives in alphabetic order. Only the SQL, SQLMEM, and SYMBOLPAGES directive descriptions show the complete syntax. For the syntax, general description, and guidelines for other SQL statements and directives, see the SQL/MP Reference Manual. Table 3-1. Summary of NonStop SQL Statements and Directives (page 1 of 3) Statement or Directive Manual * Description Data Control Language (DCL) Statements FREE RESOURCES SQLRM Closes cursors and releases locks held by the program. LOCK TABLE SQLRM Locks a table or underlying tables of a view and associated indexes. UNLOCK TABLE SQLRM Releases locks held on nonaudited tables or views. Data Definition Language (DDL) Statements ALTER SQLRM Alters the definition of a table; changes attributes of an index or table; alters security attributes of a catalog, index, program, table, or view; renames a table, index, program, or view; or adds, drops, or moves a partition of a table or index. COMMENT SQLRM Adds comments to an object definition. CREATE SQLRM Creates a constraint, catalog, index, table, or view. DROP SQLRM Drops a constraint, catalog, index, program, table, or view. HELP TEXT SQLRM Specifies help text for a column of a table or view. UPDATE STATISTICS SQLRM Updates information about the contents of a table and its indexes. Data Manipulation Language (DML) Statements CLOSE SQLRM+SQL/TAL Terminates a cursor. DECLARE CURSOR SQLRM+SQL/TAL Defines a cursor (static) DELETE SQLRM+SQL/TAL Deletes rows from a table or view. FETCH SQLRM+SQL/TAL Retrieves a row from a cursor. 3-4

NonStop SQL Statements and Directives Locating Information About SQL Statements and Directives Table 3-1. Summary of NonStop SQL Statements and Directives (page 2 of 3) Statement or Directive Manual * Description INSERT SQLRM+SQL/TAL Inserts rows into a table or view. OPEN SQLRM+SQL/TAL Opens a cursor. SELECT SQLRM+SQL/TAL Retrieves data from tables and views. UPDATE SQLRM+SQL/TAL Updates values in columns of a table or view. Dynamic NonStop SQLRM Statements DECLARE CURSOR SQLRM+TAL Defines a cursor. DESCRIBE SQLRM+TAL Returns information about output variables for a prepared statement. DESCRIBE INPUT SQLRM+TAL Returns information about input variables for a prepared statement. EXECUTE SQLRM+TAL Executes a prepared SQL statement. EXECUTE IMMEDIATE SQLRM+TAL Executes an SQL statement contained in a host variable. PREPARE SQLRM+TAL Compiles a DDL, DML, or DCL statement. RELEASE SQLRM+TAL Deallocates memory for a dynamic SQL statement referred to through a host variable. * SQLRM Described only in the SQL/MP Reference Manual SQL/TAL Described only in this manual SQLRM+SQL/TAL Described in both, this manual and the SQL/MP Reference Manual Transaction Control Statements BEGIN WORK SQLRM Starts a TMF transaction. COMMIT WORK SQLRM Commits all database changes made during the current TMF transaction and frees resources. ROLLBACK WORK SQLRM Backs out the current TMF transaction and frees resources. Data Declaration Directives BEGIN DECLARE SECTION END DECLARE SECTION SQLRM+TAL SQLRM+TAL Designates the beginning of host variable declarations. Designates the end of host variable declarations. INCLUDE SQLCA SQLRM+TAL= Declares the SQLRM communication area to receive run-time status information. INCLUDE SQLDA SQLRM+TAL= Declares the SQL descriptor area to hold information about input and output variables for dynamic SQL statements. 3-5

NonStop SQL Statements and Directives BEGIN DECLARE SECTION and END DECLARE SECTION Table 3-1. Summary of NonStop SQL Statements and Directives (page 3 of 3) Statement or Directive Manual * Description INCLUDE SQLSA SQLRM+TAL= Declares the SQL statistics area to receive execution statistics on DML or PREPARE statements. INVOKE SQLRM+TAL Generates a TAL structure description of a table or view. Data Control Directives CONTROL EXECUTOR SQLRM+TAL Specifies whether to process data using a single executor or multiple executors working in parallel. CONTROL QUERY SQLRM+TAL Specifies whether to optimize queries for time to return first row or for total query execution time. CONTROL TABLE SQLRM+TAL Specifies parameters that control locks on tables and how tables are opened. Error Checking Directives WHENEVER SQLRM+TAL= Generates code that checks SQL statement execution for errors, warnings, and no-row-found condition. TAL Compiler Directives SQL TAL Directs the TAL compiler to prepare for processing SQL statements. SQLMEM TAL Controls the placement of internal SQL structures in run-time memory. SYMBOLPAGES TAL Controls the size of the symbol table. * SQLRM Described only in the SQL/MP Reference Manual SQL/TAL Described only in this manual SQLRM+SQL/TAL Described in both manuals = Described in Section 6, Error and Status Processing of this manual. BEGIN DECLARE SECTION and END DECLARE SECTION The BEGIN DECLARE SECTION and END DECLARE SECTION directives designate the beginning and ending of a Declare Section that contains host variable declarations. A Declare Section is a part of a program that contains host variable declarations. Follow these guidelines when you use the BEGIN DECLARE SECTION and END DECLARE SECTION directives: You can use any variable declared in the Declare Section as a host variable. For more information see Section 2, Host Variables and Parameters Do not put a Declare Section in a structure declaration. 3-6

NonStop SQL Statements and Directives CLOSE CLOSE A program or compilation unit can contain several Declare Sections; however, you cannot nest Declare Sections (that is, put a Declare Section in another Declare Section). The TAL compiler does not recognize the SQL SOURCE directive. Use the TAL SOURCE directive instead. You can use TAL comment lines in a Declare Section. The following declarations contain a Declare Section. You can use the variables custnum and city as host variables in SQL statements; however, you cannot use the variables SUPPLIER, ORDERS, ORDERNUM, DATE, or PARTCOST as host variables because they are not declared in the Declare Section. INT supplier; STRUCT.orders; BEGIN INT ordernum; STRING date[0:5]; END; EXEC SQL BEGIN DECLARE SECTION; INT custnum; STRING city[0:14]; EXEC SQL END DECLARE SECTION; INT partcost;... The CLOSE statement closes a cursor. After the CLOSE statement executes, the result table established by the cursor no longer exists. At run time, the OPEN statement for a cursor must execute before the CLOSE statement (and all FETCH statements) for the cursor. Determining the Scope of a Cursor for a CLOSE Statement A static SQL cursor can only be used in the procedures in the compilation unit where the cursor is declared. Thus, for static SQL operations, the DECLARE CURSOR, OPEN, FETCH, DELETE, UPDATE, and CLOSE statements that refer to the cursor must be in the same compilation unit. If the program exits a procedure with an open cursor, procedures that execute later can still refer to the cursor, provided the procedures are in the same compilation unit. For a dynamic SQL cursor, all statements referring to the cursor must appear in the procedure where the cursor is declared; however, if you open the cursor and use it in one call to the procedure where it is declared, you can still use the cursor in subsequent calls without opening the cursor again. 3-7

NonStop SQL Statements and Directives CONTROL Directives This example shows the CLOSE statement in a typical sequence of statements that use a cursor. EXEC SQL DECLARE check_emp CURSOR FOR! Declare the cursor. SELECT deptnum FROM employee WHERE deptnum = :deptnum^del FOR UPDATE OF deptnum ;...! get a value for :deptnum^del. EXEC SQL OPEN check_emp ;! Open the cursor.! FETCH rows until the NOT FOUND condition is met. WHILE SQLCODE >= 100 DO BEGIN EXEC SQL FETCH check_emp! FETCH a value. INTO :deptnum ;! Delete a row that matches the criteria.... END EXEC SQL CLOSE check_emp ;! Close the cursor. CONTROL Directives The CONTROL directives and their functions are: CONTROL EXECUTOR Allows or prohibits parallel evaluation of a query by multiple SQL executors CONTROL QUERY Specifies whether NonStop SQL should optimize the query time for either returning the first few rows found or for returning all the rows found CONTROL TABLE Specifies options that control locks and opens on tables and views, and whether to buffer INSERT and UPDATE operations You can use CONTROL directives with either static SQL or dynamic SQL statements. CONTROL directives do not affect SQL DDL statements. The SQL/MP Reference Manual contains general information and syntax for the CONTROL directives. The following paragraphs provide information for using the directives in a TAL program. 3-8

NonStop SQL Statements and Directives CONTROL Directives Using the CONTROL EXECUTOR Directive Follow these guidelines when you use the CONTROL EXECUTOR directive: Execution Plan. The CONTROL EXECUTOR directive affects the execution plan for subsequent DML statements in the source program in listing order (rather than execution order) until: Another CONTROL EXECUTOR directive resets the option. The end of the procedure occurs. Scope. The scope of a CONTROL EXECUTOR directive is as follows. A directive affects SQL statements in the program's listing order, regardless of the execution order. If a CONTROL EXECUTOR directive coded with the global declarations, it affects only global cursors. If a CONTROL EXECUTOR directive coded in a procedure, it affects only the DML statements in the procedure. A CONTROL directive coded in a subprocedure affects all static SQL statements that follow in listing order until the end of the procedure in which the subprocedure is embedded. Flow-Control Statements. A CONTROL EXECUTOR directive coded within flowcontrol statements (for example, IF, THEN, and ELSE) applies to static SQL statements in the program's listing order, regardless of the execution order. Dynamic SQL Statements. A static CONTROL EXECUTOR directive has no effect on dynamic SQL statements. To use a CONTROL EXECUTOR directive with dynamic SQL statements, specify a dynamic CONTROL directive using the PREPARE and EXECUTE (or EXECUTE IMMEDIATE) statements. For dynamic SQL cursors, the CONTROL EXECUTOR directive and the DECLARE CURSOR statement must appear in the same procedure. In this example, the cursor definition undergoes parallel evaluation as an equijoin operation when the program issues the first fetch operation on the cursor. The common column is CUSTNUM. The TACL DEFINEs =CUSTOMER and =ORDERS refer to the CUSTOMER and ORDERS tables. EXEC SQL CONTROL EXECUTOR PARALLEL EXECUTION ON ; EXEC SQL DECLARE list_customers_with_orders CURSOR FOR SELECT customer.custnum, customer.custname FROM =customer, =orders WHERE customer.custnum = orders.custnum STABLE ACCESS ; 3-9

NonStop SQL Statements and Directives CONTROL Directives Using the CONTROL QUERY Directive Follow these guidelines when you use the CONTROL QUERY directive: Optimization. The CONTROL QUERY directive affects the optimization for subsequent DML statements in listing order (rather than execution order) until: Another CONTROL QUERY directive resets the option. The end of the procedure occurs. Scope. The scope of a CONTROL QUERY directive is as follows. A directive affects SQL statements in the program's listing order, regardless of the execution order. A directive coded with the global declarations affects only global cursors. A directive coded in a procedure affects only the DML statements in the procedure. A directive coded in a subprocedure affects all statements that follow in listing order until the end of the procedure in which the subprocedure is embedded. Flow-Control Statements. A CONTROL QUERY directive coded within flow-control statements (for example, IF, THEN, and ELSE) applies to static SQL statements in the program's listing order regardless of the execution order. This example shows two CONTROL directives with dynamic SQL statements. The EXECUTE statement is affected by the CONTROL TABLE directive with the TIMEOUT option but not by the CONTROL QUERY directive. The TACL DEFINE =EMPLOYEE refers to the employee table. EXEC SQL PREPARE statement FROM "SELECT * FROM =EMPLOYEE"; EXEC SQL CONTROL QUERY INTERACTIVE ACCESS ON; EXEC SQL CONTROL TABLE =employee TIMEOUT 120 SECONDS; EXEC SQL EXECUTE statement; Dynamic SQL Statements. A static CONTROL QUERY directive has no effect on dynamic SQL statements. To use a CONTROL QUERY directive with dynamic SQL statements, specify a dynamic CONTROL directive using the PREPARE and EXECUTE (or EXECUTE IMMEDIATE) statements. For dynamic SQL cursors, the CONTROL QUERY directive and the DECLARE CURSOR statement must be in the same procedure. Using the CONTROL TABLE Directive Follow these guidelines when you use the CONTROL TABLE directive: Access to Tables and Views. The CONTROL TABLE directive affects access to tables and views referenced by SQL statements until: Another CONTROL TABLE directive resets the options. The end of the procedure occurs. 3-10

NonStop SQL Statements and Directives DECLARE CURSOR Scope. The scope of a CONTROL TABLE directive is as follows. A directive affects SQL statements in the program's listing order, regardless of the execution order. A directive with the global declarations affects only statements at the global level (statements that are outside of procedures). A directive in a procedure affects only the statements in the procedure. A directive in a subprocedure affects all statements that follow in listing order until the end of the procedure in which the subprocedure is embedded. To affect tables or views referenced in a cursor, the CONTROL TABLE directive must precede the DECLARE CURSOR statement. For static SQL cursors, the CONTROL TABLE directive and the DECLARE CURSOR statement must be with the global declarations. For dynamic SQL cursors, the statements must be in the same procedure. Flow-Control Statements. A CONTROL TABLE directive coded within flow-control statements (for example, IF, THEN, and ELSE) applies to static SQL statements in the program's listing order, regardless of the execution order. Dynamic SQL Statements. A static CONTROL TABLE directive does not affect dynamic SQL statements. To use a CONTROL TABLE directive with dynamic SQL statements, specify a dynamic CONTROL TABLE directive using the PREPARE and EXECUTE (or EXECUTE IMMEDIATE) statements. A dynamic CONTROL TABLE directive does not affect static SQL statements, unless you specify the TIMEOUT option. In this case, the CONTROL TABLE directive affects all static and dynamic SQL statements that follow in execution order (rather than listing order), until another CONTROL TABLE directive resets the option or the end of the procedure occurs. DECLARE CURSOR The DECLARE CURSOR statement defines a cursor and associates the cursor with a SELECT statement. Using the cursor, TAL program can process, one by one, the rows retrieved by the SELECT statement. Follow these guidelines when you use the DECLARE CURSOR statement: Static SQL Cursors A static DECLARE CURSOR statement can appear only in the global declarations part of a TAL compilation unit. All host variables referenced by the DECLARE CURSOR statement in the static SQL program must have global scope and must be declared in listing order before the DECLARE CURSOR statement that references them. 3-11

NonStop SQL Statements and Directives DECLARE CURSOR A static SQL cursor can be accessed only from the compilation unit in which its DECLARE CURSOR statement occurs. This means that for static SQL programs, the DECLARE CURSOR, OPEN, FETCH, DELETE WHERE CURRENT, UPDATE WHERE CURRENT, and CLOSE statements must be in the same compilation unit. If the program exits a procedure with an open cursor, procedures that execute later and are in the same compilation unit can still reference the cursor. Dynamic SQL Cursors For dynamic SQL cursors, all statements referencing the cursor must appear in the procedure where the cursor is defined; however, if you open the cursor and use it in one call to the procedure where it is defined, you can still use the cursor in subsequent calls, without opening the cursor again. All Cursors At run time, the OPEN statement must execute before all FETCH statements. Any FETCH statements must execute before the CLOSE statement executes. In this example, the DECLARE CURSOR statement uses a cursor that initiates a SELECT operation from the PARTS table by the part name (PARTDESC) and by part number (PARTNUM) within the part name. The TACL DEFINE =PARTS refers to the parts table.! Host variable declaration. INVOKE produces a! structure template named parts^type, which is! then used to declare a structure named parts^rec: EXEC SQL INVOKE =parts; STRUCT.parts^rec(parts^type);! DECLARE CURSOR statement: EXEC SQL DECLARE order_by_partdesc_cursor CURSOR FOR SELECT partnum, partdesc, price, qty_available FROM =parts WHERE (partdesc, partnum) > ( :parts^rec.partdesc, :parts^rec.partnum ) ORDER BY partdesc, partnum BROWSE ACCESS ;! Procedure code: EXEC SQL OPEN order_by_partdesc_cursor; WHILE SQLCODE >= 100 DO! FETCH rows into host variables created with INVOKE! until NOT FOUND condition is met: BEGIN EXEC SQL FETCH order_by_partdesc_cursor INTO :parts^rec.partnum, 3-12

NonStop SQL Statements and Directives DELETE DELETE :parts^rec.partdesc, :parts^rec.price, :parts^rec.qty^available; END; EXEC SQL CLOSE order_by_partdesc_cursor; The DELETE statement deletes one or more rows from a table or protection view. The number of rows deleted is determined by the WHERE clause. A DELETE statement can delete: A single row A set of rows A set of rows, one row at a time using a cursor (a mechanism for dealing with a set of rows returned in sequence to a program) To execute a DELETE statement, a TAL program's process accessor ID (PAID) must have read and write access to the table or view and any table or view in subqueries of the search condition. In general, specifying a delete operation programmatically in a TAL program is the same as specifying a delete operation using SQLCI commands. With SQLCI, you specify the new values in an DELETE statement, while in a program, you set one or more host variables to the new values and then use the host variables in the DELETE statement. This table shows the SQLCODE values that NonStop SQL returns after a DELETE statement: SQLCODE Value Description 0 The DELETE statement was successful. 100 No rows were found on a search condition. < 0 An error occurred; SQLCODE contains the error number. > 0 (not 100) A warning occurred; SQLCODE contains the first warning number. After a successful delete operation, the SQLCA structure contains the exact number of rows deleted. After an error on a delete operation, the SQLCA contains an approximate number of rows deleted. To obtain the contents of the SQLCA, use the SQLCADISPLAY or SQLCATOBUFFER procedure. If you delete all rows from a table, the table still exists until it is deleted from the catalog with a DROP TABLE statement. 3-13

NonStop SQL Statements and Directives DELETE Executing a Single-Row DELETE Statement To delete a single row, you move a key value to a host variable and then use the host variable in the WHERE clause of the DELETE statement. The following DELETE statement deletes only one row of the EMPLOYEE table because each value in EMPNUM is unique. EMPNUM is the primary key of the EMPLOYEE table. A user enter a value for the :HOSTVAR^KEY host variable. EXEC SQL DELETE FROM =employee WHERE empnum = :hostvar^key ; Executing a Multi-Row DELETE Statement Multi-row operations (sometimes called set operations) are performed on one or more rows by a single SQL statement. Set operations provide maximum efficiency in both coding and execution. Use set operations wherever possible for deleting sets of rows. However, sometimes, you must check a row before deleting it. In this case, you must use cursors as described under Using a Cursor to Delete Rows on page 3-15. In these examples, a user enters the values for all host variables. The following DELETE statement deletes all rows from the EMPLOYEE table that contain information for employees in the department identified by the host variable :HOSTVAR^DEPTNUM. EXEC SQL DELETE FROM =employee WHERE deptnum = hostvar^deptnum ; The following DELETE statement deletes all rows that contain a department number matching the DEPTNUM value that is assigned to the host variable :HOSTVAR^DEPT (for example, all employees working in department 100). DEPTNUM is not a primary key; therefore, more than one row for each value of DEPTNUM can exist EXEC SQL DELETE FROM =employee WHERE deptnum = :hostvar^dept ; The following DELETE statement deletes from the ORDERS table all orders that were placed with the sales representative identified by the host variable :HOSTVAR^REP by any customer except the customer whose number is identified by the host variable :HOSTVAR^CUSTNUM. EXEC SQL DELETE FROM sales.orders WHERE salesrep = hostvar^rep AND custnum <> hostvar^custnum; 3-14

NonStop SQL Statements and Directives DELETE This DELETE statement deletes from the PARTSUPP table all suppliers who charge more than the host variable :HOSTVAR^MAX^COST for terminals. Terminals have part numbers in the range of the host variables :HOSTVAR^MIN to :HOSTVAR^MAX. EXEC SQL DELETE FROM invent.partsupp WHERE partnum BETWEEN :hostvar^min AND :hostvar^max AND partcost > hostvar^max^cost ;. Using a Cursor to Delete Rows To read and test a value before you delete a row, you must use a cursor. A cursor allows you to delete a set of rows one row at a time. You specify the set of rows with the SELECT clause in the DECLARE CURSOR statement. You read each row using a FETCH statement, test the data, and then ignore or delete the row depending on your test logic. If you determine that you want to delete the data from the table, you use a DELETE WHERE CURRENT OF statement. Note. Do not use a stand-alone DELETE operation to delete a row that has been retrieved using a cursor FETCH operation. This can invalidate the cursor's buffering for the table and might degrade performance. For audited tables and views, a TMF transaction must be in progress. The same TMF transaction must include both fetching and deleting the row. If you want to ensure that a lock is held on the row you are deleting until the transaction completes, you can declare the cursor with a DELETE WHERE CURRENT OF statement that specifies a column in the rows to be deleted. This example declares a cursor, fetches and tests the data, and then deletes the row: EXEC SQL DECLARE check_emp CURSOR FOR SELECT deptnum FROM employee WHERE deptnum = :deptnum^del OR deptnum = :deptnum^upd FOR UPDATE OF deptnum ; EXEC SQL OPEN check_emp ; EXEC SQL FETCH check_emp INTO :deptnum ;! Program logic to test the data... EXEC SQL DELETE FROM employee WHERE CURRENT OF check_emp ; EXEC SQL CLOSE check_emp ;! Delete the current row 3-15

NonStop SQL Statements and Directives DESCRIBE and DESCRIBE INPUT You can refer to a static SQL cursor only in the compilation unit where the cursor is declared. Thus, for static SQL programs, the DELETE WHERE CURRENT, DECLARE CURSOR, OPEN, FETCH, and CLOSE statements that refer to the cursor must be in the same compilation unit. If a program exits a procedure with an open cursor, procedures that execute later can still refer to the cursor, provided the procedures are in the same compilation unit. For a dynamic SQL cursor, all statements referring to the cursor must appear in the procedure where the cursor is defined. However, if you open the cursor and use it in a call to the procedure where it is defined, you can still use the cursor in subsequent calls without opening the cursor again. DESCRIBE and DESCRIBE INPUT The DESCRIBE statement returns information about output variables (usually SELECT columns) associated with a previously prepared dynamic SQL statement. DESCRIBE fills in an SQLDA structure and the names buffer with the descriptions and names of the columns. The DESCRIBE INPUT statement returns information about the input parameters associated with a previously prepared SQL statement. Follow these guidelines when you use a DESCRIBE or DESCRIBE INPUT statement: A DESCRIBE or DESCRIBE INPUT statement must appear in the same procedure as the PREPARE, EXECUTE, or cursor SQL statements (DECLARE CURSOR, OPEN, FETCH, CLOSE) that process the dynamic SQL input statement. Both DESCRIBE and DESCRIBE INPUT set the SQLDA NULL^INFO field depending on whether the prepared SQL statement includes a null indicator and not whether the column actually allows a null value. To determine whether a column allows a null value, check the NULLALLOWED column in the COLUMNS table for the catalog where the particular table is registered. To determine the catalog for a table, use the FILEINQUIRE procedure. If a program declares an SQLSA structure, the DESCRIBE and DESCRIBE INPUT statements return the same compilation statistics that PREPARE returns for the OUTPUT^NUM, OUTPUT^NAMES^LEN, INPUT^NUM, and INPUT^NAMES^LEN fields. For more information see the description of the SQLSA structure in Section 6, Error and Status Processing. The following example dynamically executes a SELECT statement, but it does not know the actual text of the statement. The example uses a SELECT statement in the host variable :INTEXT and prepares the statement in DYNASTATEMENT. The DESCRIBE statement uses the SQLDA structure and the names buffer generated by the INCLUDE SQLDA directive. 3-16

NonStop SQL Statements and Directives DROP DROP The size depends on the expected size and number of columns in the SELECT statement. This example uses the arbitrary values 5 and 39; you can use different values, or you can declare a template and dynamically allocate the memory.! Global declarations EXEC SQL INCLUDE SQLDA (sqlda1, 5, namebuf, 39); EXEC SQL BEGIN DECLARE SECTION; STRING intext [0:200]; EXEC SQL END DECLARE SECTION;... EXEC SQL PREPARE dynstatement FROM :intext; EXEC SQL DESCRIBE dynstatement INTO :sqlda1 NAMES INTO :namebuf;... The DROP statement deletes a catalog, constraint, index, program, table, or view. To drop an object, a program's process accessor ID (PAID) must have read and write access to all catalogs that describe the objects affected by the drop. For specific SQL objects, a program's PAID must have access as follows: Table, view, or program Index or constraint Catalog SQL.CATALOGS Purge access Must be the local or remote owner of the underlying table with purge access (or the local super ID user) Read and purge access for the catalog tables Read and write access Examples In this example, the statements drop an index for the PARTS table before dropping the table. The last statement drops a program. EXEC SQL DROP INDEX $vol1.sales.xpartdes; EXEC SQL DROP TABLE $vol1.sales.parts; EXEC SQL DROP PROGRAM $vol3.subvol3.proga; 3-17

NonStop SQL Statements and Directives EXECUTE and EXECUTE IMMEDIATE EXECUTE and EXECUTE IMMEDIATE FETCH The EXECUTE statement executes a previously prepared dynamic SQL statement. The EXECUTE IMMEDIATE statement compiles and executes an SQL statement that is represented as text in a host variable. Use an EXECUTE statement for any DDL, DML, or DCL statement except the SELECT statement. Use an EXECUTE IMMEDIATE statement for any DDL, DML, or DCL statement except the OPEN, CLOSE, and SELECT statements. Use a cursor to process a SELECT statement. The EXECUTE statement must appear in the same procedure as the PREPARE, DESCRIBE INPUT, and DESCRIBE statements that are used to process the dynamic SQL input statement. The FETCH statement positions a cursor at the next row of the result table defined by the cursor and retrieves the column values. This statement returns each column value in the row into the corresponding host variable. To execute a FETCH statement, a program's process accessor ID (PAID) must have read access to any tables or views associated with the cursor. At run time, the OPEN statement must execute before all FETCH statements, and the CLOSE statement must execute after all FETCH statements for the cursor. Any host variable used in a DECLARE CURSOR statement must be in the same scope for each OPEN or FETCH statement for the cursor. This table shows the SQLCODE values that NonStop SQL returns after a FETCH statement: SQLCODE Value Description 0 The FETCH statement was successful. 100 The end of a table was encountered. < 0 An error occurred; SQLCODE contains the error number. > 0 (not 100) A warning occurred; SQLCODE contains the first warning number. Determining the Scope of a Cursor for a FETCH Statement A static SQL cursor can only be used in the procedures in the compilation unit where the cursor is declared. Thus, for static SQL operations, the DECLARE CURSOR, OPEN, FETCH, DELETE WHERE CURRENT, UPDATE WHERE CURRENT, and CLOSE statements that refer to the cursor must be in the same compilation unit. If the program exits a procedure with an open cursor, procedures that execute later can still refer to the cursor, provided the procedures are in the same compilation unit. 3-18

NonStop SQL Statements and Directives INCLUDE SQLCA, INCLUDE SQLDA, and INCLUDE SQLSA For a dynamic SQL cursor, all statements referring to the cursor must appear in the procedure where the cursor is declared; however, if you open the cursor and use it in one call to the procedure where it is declared, you can still use the cursor in subsequent calls without opening the cursor again. INCLUDE SQLCA, INCLUDE SQLDA, and INCLUDE SQLSA The INCLUDE SQLCA, INCLUDE SQLDA, and INCLUDE SQLSA directives declare the following data structures: INCLUDE SQLCA Declares the SQL communications area (SQLCA), which contains run-time information including errors and warnings generated by the most recently executed SQL statement INCLUDE SQLDA Declares the SQL descriptor area (SQLDA), which contains run-time information about input parameters and output variables in dynamic SQL statements INCLUDE SQLSA Declares the SQL statistics area (SQLSA), which contains run-time information about the statistics and performance of SQL statements For more information on the description of each directive, see Section 6, Error and Status Processing. INSERT The INSERT statement inserts one or more rows into a table or protection view. To execute an INSERT statement, a program's process accessor ID (PAID) must have read and write access to the table or view receiving the data and read access to tables and views if you use a SELECT statement parameter. In general, specifying an insert operation programmatically in a TAL program is the same as specifying an insert operation using SQLCI commands. With SQLCI, you specify the new values in an INSERT statement, while in a program, you set one or more host variables to the new values and then use the host variables in the INSERT statement. In a program, you move the row data to a series of host variables and then use an INSERT statement that specifies these host variables to write the row to the table. For example, the following statement inserts a row into the table named TABLE1: 3-19

NonStop SQL Statements and Directives INSERT EXEC SQL INSERT INTO table1 (column1, column2, column3, column4) VALUES (:host^var1, :host^var2, :host^var3, :host^var4) ANYWHERE ; The previous example assumes that the organization of the table is relative. The INSERT statement supplies values for the four named columns. The system supplies the value for the system key (SYSKEY). Any other columns in the table receive default values (either specified defaults or the system default). If any columns are defined as NO DEFAULT, the insert operation fails because the values were not supplied. The INSERT statement contains the ANYWHERE clause because the table organization is relative. ANYWHERE causes the row to be inserted wherever space is available. If you specify APPEND instead of ANYWHERE, the row is added to the end of the table. For a dynamic SQL program, the INSERT statement must be in the same procedure as all other dynamic SQL statements that refer to the SQL statement being processed. This table shows s the SQLCODE values that NonStop SQL returns after an INSERT statement: SQLCODE Value Description 0 The INSERT statement was successful. 100 No rows qualified for an INSERT through a SELECT specification. < 0 An error occurred; SQLCODE contains the error number. > 0 (not 100) A warning occurred; SQLCODE contains the first warning number. After a successful insert operation, the SQLCA structure contains the exact number of rows inserted. To obtain the contents of the SQLCA, use the SQLCADISPLAY or SQLCATOBUFFER procedure. Inserting Null Values This example inserts an employee record into the EMPLOYEE table and sets the SALARY column to a null value using an indicator variable. This example uses the TACL DEFINE name =EMPLOYEE for the EMPLOYEE table. 3-20

NonStop SQL Statements and Directives INSERT! Variable declarations: EXEC SQL BEGIN DECLARE SECTION; STRUCT employee^type(*); BEGIN INT empnum /SMALLINT UNSIGNED/; STRING first^name[0:14]; STRING last^name[0:19]; INT deptnum /SMALLINT UNSIGNED/; INT jobcode /SMALLINT UNSIGNED/; INT(32) salary /INTEGER UNSIGNED/;! scale is 2... END; STRUCT.emp(employee^type); INT ind^1; EXEC SQL END DECLARE SECTION;...! Executable statements: ind^1 := -1;! Set indicator variable EXEC SQL INSERT INTO =employee (first^name, last^name, salary) VALUES (:emp.first^name, :emp.last^name, :emp.salary INDICATOR :ind^1); To insert a value with scale (for example, a price or salary) into a database, use a host variable of TAL FIXED or INT (32) data type and then use the SQL SETSCALE function to specify the scale. In this example uses the NULL keyword instead of an indicator variable: EXEC SQL INSERT INTO =employee (first^name, last^name, salary) VALUES (:emp.first^name, :emp.last^name, NULL); Inserting a Timestamp Value This example inserts a timestamp value into COLUMN^A of TABLE^T. The COLUMN^A definition specifies the data type TIMESTAMP DEFAULT CURRENT. When the example inserts a row, NonStop SQL inserts the current timestamp but does not know the timestamp value inserted. 3-21

NonStop SQL Statements and Directives INVOKE The example uses the JULIANTIMESTAMP and CONVERTTIMESTAMP Guardian procedures and the CONVERTTIMESTAMP SQL function. To call Guardian procedures, include the declarations from the EXTDECS file. INVOKE?SOURCE $SYSTEM.SYSTEM.EXTDECS ( JULIANTIMESTAMP, CONVERTTIMESTAMP) EXEC SQL BEGIN DECLARE SECTION; FIXED dtvar;! Variable for storing the timestamp value EXEC SQL END DECLARE SECTION; INT SQLCODE;... PROC driver MAIN ; BEGIN! Get current Julian timestamp in Greenwich mean time: dtvar := JULIANTIMESTAMP();! Convert timestamp to local time: dtvar := CONVERTTIMESTAMP(dtvar);! Insert value into table using SQL CONVERTTIMESTAMP: EXEC SQL BEGIN WORK; EXEC SQL INSERT INTO table^t (column^a) VALUES ( CONVERTTIMESTAMP (:dtvar) ); EXEC SQL COMMIT WORK; END; The INVOKE directive defines a TAL structure template with fields and data types that correspond one to one with the columns in an SQL table or view. INVOKE writes a TAL data description for each column in the table or view. Use INVOKE to create: Host variables in a Declare Section that correspond to the columns in a table Indicator variables that indicate whether a column value contains (or can contain) a null value Follow these guidelines when you use the INVOKE directive: Use the INVOKE directive only in the variable declarations; do not use it with executable statements. To use the INVOKE directive on a table or view, you must have read access to the table or view when you compile your program. For the best performance, use INVOKE to define host variables that serve as input or output variables for database columns. INVOKE defines the host variables so that data conversion is not required at run time. For more information see Creating Host Variables With the INVOKE Directive on page 2-20, in Section 2, Host Variables and Parameters. 3-22

NonStop SQL Statements and Directives INVOKE Use TACL DEFINEs only for table or view names; do not use them for structure names. Table 3-2 shows the override data type mapping generated by the INVOKE directive. Table 3-2. INVOKE Directive Override Data Type Mapping Host Variable Description Generated by the INVOKE SQL Data Type Directive SMALLINT UNSIGNED INT name / SMALLINT UNSIGNED / INTEGER UNSIGNED INT(32) name / INTEGER UNSIGNED / NUMERIC (1-4, s) UNSIGNED INT name / SMALLINT UNSIGNED / NUMERIC (5-9, s) UNSIGNED INT(32) name / INTEGER UNSIGNED / DECIMAL(1) STRING name / DECIMAL(1) / DECIMAL(1) UNSIGNED STRING name / DECIMAL(1) UNSIGNED / DECIMAL (n) STRING name [0 : n - 1] / DECIMAL(n) / DECIMAL (n) UNSIGNED STRING name [0 : n - 1] / DECIMAL (n) UNSIGNED / name is the name of the host variable. n is a positive integer that represents the length. s is a positive integer that represents the scale of the number. Defining the Structure Template The INVOKE directive defines a structure template with a default name as the table name plus the suffix ^TYPE. For example, the following INVOKE directive defines a structure template for the EMPLOYEE table: EXEC SQL INVOKE employee; The CREATE TABLE statement that defines the table is: CREATE TABLE employee (emp_id NUMERIC(4) NOT NULL, dept_num NUMERIC(6) NOT NULL ); The INVOKE directive causes the TAL compiler to generate the following structure template:! Record Definition for table \SYS.$DB.PERSNL.EMPLOYEE! Definition current at 14:54:18-09/27/89 STRUCT employee^type (*); BEGIN INT emp^id; INT(32) dept^num; END; 3-23

NonStop SQL Statements and Directives INVOKE To use the structure template in your program, declare an instance of the structure. This example declares a structure named EMPLOYEE that has the layout of the structure template EMPLOYEE^TYPE: STRUCT.employee (employee^type); You must qualify the host variables defined by INVOKE (for example, EMPLOYEE.EMP^ID). You cannot reference a structure name by itself as a host identifier. The only exceptions are structures that conform to the definition of SQL type VARCHAR, and the SQLDA structure. Using VARCHAR Data Types An SQL VARCHAR column corresponds to a single logical data element; however, for TAL correspondence, a VARCHAR column is converted to a structure with two elementary data items. The group item name is derived from the VARCHAR column name. The data names of the subordinate data items are LEN, a numeric field for the current length, and VAL, a fixed-length character field for the string. For example, a column CUSTNAME defined as VARCHAR(26) is described with this structure template: STRUCT custname(*); BEGIN INT len; STRING val[0:25]; END; Using Scaled Data Types When you invoke a column with a scaled numeric type, the SQL compiler generates a comment that gives the scale of the column being declared. For example, if PRICE with data type NUMERIC (8,2) is invoked in TAL, INVOKE generates this: INT(32) price;! scale is 2 To communicate a scale factor to SQL, either change the host variable price to TAL data type FIXED(2), which is a larger number but allows you to represent the scale, or use the SQL SETSCALE function. Using Date-Time and INTERVAL Data Types When you invoke a column with a date-time (DATETIME, DATE, TIME, or TIMESTAMP) or INTERVAL data type, the data is represented as a character field. The size of the field is determined by the range of the date-time or INTERVAL column. You control the display format by inserting the value in the format you want and retrieving the value using the DATEFORMAT function. If you use INVOKE to generate host variables from an SQL table definition, you can specify the DATEFORMAT clause to determine the size. 3-24

NonStop SQL Statements and Directives INVOKE INTERVAL values are represented as character strings with a separator between the values of the fields (year-month or day-time). An extra byte is generated at the beginning of the INTERVAL string for a sign. The default representations for date-time and INTERVAL values are shown in these subsections. Date-Time Representation. The column definitions in the SQL table are: name CHAR(18) birth_date DATETIME The date represented is May 28, 1952: Year Separator Month Separator Day Null 1 9 5 2-0 5-2 8 The structure definition in the TAL program is: STRUCT employee^rec; BEGIN STRING name[0:17]; STRING birth^date[0:9]; END; The host variable reference is: :age TYPE AS INTERVAL YEAR(2) TO MONTH These examples use host variables with date-time and INTERVAL values. Appendix B also includes a program that uses date-time and INTERVAL values. Selecting Date-Time and INTERVAL Values. In this example, a table named PROJECTS is invoked from a database. The table has this SQL definition: PROJECT_NAME PIC X(10) START_DATE DATETIME YEAR TO MINUTE END_DATE DATETIME YEAR TO MINUTE WAIT_TIME INTERVAL DAY(2) This example uses a TACL DEFINE named =PROJECTS for the table. The structure that appears in the program is shown after the INVOKE directive. EXEC SQL BEGIN DECLARE SECTION;... EXEC SQL INVOKE =projects;! The following template is inserted at compile time:! STRUCT projects^type(*);! BEGIN! STRING project^name[0:9];! STRING start^date[0:15];! STRING end^date[0:15]; 3-25

NonStop SQL Statements and Directives INVOKE! STRING wait^time[0:2];! An extra byte is generated! for a possible sign! END;! Declare storage for the table: STRUCT.projects^rec(projects^type);! Procedure code: EXEC SQL SELECT project^name, start^date, end^date, wait^time INTO :projects^rec.project^name, :projects^rec.start^date TYPE AS DATETIME YEAR TO MINUTE, :projects^rec.end^date TYPE AS DATETIME YEAR TO MINUTE, :projects^rec.wait^time TYPE AS INTERVAL DAY(2) FROM =projects WHERE project^name = "995";... Inserting Date-Time and INTERVAL Values. In this example, date-time (DATE) and INTERVAL values are inserted into the BILLINGS table. The SQL definition is shown at the beginning of the example. The SQL definition for the billings table is:! CUSTNUM CHAR (4) NOT NULL! START_DATE DATE NOT NULL! BILLING_DATE DATE NOT NULL! TIME_BEFORE_PMT INTERVAL DAY(3) NOT NULL! Variable declarations: EXEC SQL BEGIN DECLARE SECTION;... STRUCT.billings; BEGIN STRING custnum[0:3]; STRING start^date[0:9]; STRING billing^date[0:9]; STRING time^before^pmt[0:3];! An extra byte is used! for a possible sign END; EXEC SQL END DECLARE SECTION;... 3-26

NonStop SQL Statements and Directives INVOKE The statements to supply values for the columns are: billings.billing^date ':='"1988-10-20"; billings.time^before^pmt ':=' "120";... EXEC SQL INSERT INTO billings VALUES ("923", DATE "1985-10-15", :billing^date TYPE AS DATE, :time^before^pmt TYPE AS INTERVAL DAY(3) );... Using Indicator Variables for Null Values INVOKE generates indicator variables of TAL type INT for each host variable that corresponds to a column that can be null. The format of the indicator variable is the name of the corresponding column, plus a prefix and or suffix, if you specify one. For example, if the column name is RETIRE^DATE, the format of the indicator variable is RETIRE^DATE^I. You can specify a suffix other than the ^I provided by SQL by supplying a SUFFIX clause with the INVOKE statement. You can replace the suffix with a prefix of your choosing by specifying the PREFIX clause. Examples appear on page 3-29. If you specify NULL STRUCTURE, INVOKE produces a substructure that contains the indicator variable and the column. For more information about the NULL STRUCTURE clause, see Using the NULL STRUCTURE Clause on page 3-28. Note. If a column name is 30 or 31 characters long and the default indicator suffix ^I is used, the ^I is truncated, and the indicator variable name is identical to the corresponding host variable name. To prevent this error, specify the PREFIX or NULL STRUCTURE clause when column names are 30 or 31 characters long. For a column allows a null value, the INVOKE directive generates an indicator variable that your program can use to specify whether or not a column value is null. In this example, INVOKE generates a structure for a table definition that allows null values in the FIRST^NAME and RETIRE^DATE columns. The generated structure type includes indicator variables with the default suffix ^I for FIRST^NAME and RETIRE^DATE. The INVOKE directive as it appears in the TAL source program is: EXEC SQL BEGIN DECLARE SECTION; EXEC SQL INVOKE emptbl AS emptbl^rec; EXEC SQL END DECLARE SECTION; The CREATE TABLE statement that defines the table is: CREATE TABLE emptbl ( empnum NUMERIC (4) UNSIGNED NO DEFAULT NOT NULL, first^name CHARACTER(15), 3-27

NonStop SQL Statements and Directives INVOKE last^name CHARACTER(20) NO DEFAULT NOT NULL, retire^date DATETIME YEAR TO DAY, PRIMARY KEY empnum ) CATALOG \sys.$vol.testcat ; The compiler generates this structure template:! Record Definition for table \SYS.$VOL.SUBVOL.EMPTBL! Definition current at 16:06:49-05/17/90 STRUCT emptbl^rec (*); BEGIN INT empnum /SMALLINT UNSIGNED/; INT first^name^i; STRING first^name[0:14]; STRING last^name[0:19]; INT retire^date^i; STRING retire^date[0:9]; END; Using the NULL STRUCTURE Clause This example uses the NULL STRUCTURE clause, which causes columns that contain null values to be defined as structures. The NULL STRUCTURE clause assigns the name INDICATOR to all indicator variables in the structure template. The INVOKE directive with the NULL STRUCTURE clause: EXEC SQL BEGIN DECLARE SECTION; EXEC SQL INVOKE emptbl AS emptbl^rec NULL STRUCTURE; EXEC SQL END DECLARE SECTION; NonStop SQL generates this structure template:! Record Definition for table \SYS.$VOL.SUBVOL.EMPTBL! Definition current at 16:07:00-05/17/90 STRUCT emptbl^rec (*); BEGIN INT empnum /SMALLINT UNSIGNED/; STRUCT first^name; BEGIN INT indicator; STRING valu[0:14]; END; STRING last^name[0:19]; STRUCT retire^date; BEGIN INT indicator; STRING valu[0:9]; END; END; 3-28

NonStop SQL Statements and Directives OPEN OPEN Using the PREFIX and SUFFIX Clauses This example specifies both a prefix and a suffix for indicator variables. The indicator variables generated are X^ZNUM^2 and X^ZCHAR^2. The CREATE TABLE statement that defines table TAB is: CREATE TABLE tab ( znum NUMERIC (6), zchar CHARACTER(16), PRIMARY KEY znum ) CATALOG \sys.$vol.testcat ; The INVOKE directive with the PREFIX and SUFFIX clauses is: EXEC SQL BEGIN DECLARE SECTION; EXEC SQL INVOKE tab PREFIX x^ SUFFIX ^2; EXEC SQL END DECLARE SECTION; NonStop SQL generates this structure template:! Record Definition for table \SYS.$DB.XPERSNL.TAB! Definition current at 15:32:39-09/22/89 STRUCT tab^type (*); BEGIN INT x^znum^2;! indicator variable name INT(32) znum; INT x^zchar^2;! indicator variable name STRING zchar[0:15]; END; The OPEN statement opens a cursor. At run time, the OPEN statement for a cursor must execute before all FETCH statements for the cursor. Any host variables used in a DECLARE CURSOR statement must be in the same scope for each OPEN statement for the cursor. Determining the Scope of a Cursor After an OPEN Statement A static SQL cursor can only be used in the procedures in the compilation unit where the cursor is declared. Thus, for static SQL operations, the DECLARE CURSOR, OPEN, FETCH, DELETE WHERE CURRENT, UPDATE WHERE CURRENT, and CLOSE statements that refer to the cursor must be in the same compilation unit. If the program exits a procedure with an open cursor, procedures that execute later can still refer to the cursor, provided the procedures are in the same compilation unit. For a dynamic SQL cursor, all statements referring to the cursor must appear in the procedure where the cursor is declared; however, if you open the cursor and use it in 3-29

NonStop SQL Statements and Directives PREPARE one call to the procedure where it is declared, you can still use the cursor in subsequent calls without opening the cursor again. This example shows the OPEN statement in a typical sequence of statements that use a cursor. PREPARE EXEC SQL DECLARE check_emp CURSOR FOR! Declare the cursor. SELECT deptnum FROM employee WHERE deptnum = :deptnum^del FOR UPDATE OF deptnum ;...! get a value for :deptnum^del. EXEC SQL OPEN check_emp ;! Open the cursor.! FETCH rows until the NOT FOUND condition is met. WHILE SQLCODE >= 100 DO BEGIN EXEC SQL FETCH check_emp! FETCH a value. INTO :deptnum ;! Delete a row that matches the criteria.... END EXEC SQL CLOSE check_emp ;! Close the cursor. The PREPARE statement dynamically compiles an SQL statement. PREPARE associates a statement name or host variable name with an SQL statement, which resides as a string literal in the host variable. If the PREPARE statement completes without an error, you can execute the statement by specifying the statement or host variable name in an EXECUTE (or EXECUTE IMMEDIATE) statement. After a successful completion, the SQL statement is called a prepared statement. If the PREPARE statement fails, an attempt to execute the statement fails. For a prepared SELECT statement, a program defines a cursor with a dynamic DECLARE CURSOR statement, and then uses dynamic OPEN, FETCH, and CLOSE statements to retrieve rows. 3-30

NonStop SQL Statements and Directives RELEASE Follow these guidelines when you use the PREPARE statement: A prepared statement is associated only with the program that executes the PREPARE statement. Only that program can execute the prepared statement. The prepared statement remains available for execution until one of the following events occur: The current process terminates A statement with the same name (either specified as a literal or with a statement host variable) is prepared again The statement name is successfully released with a RELEASE statement If a statement is prepared again, the previously compiled statement is released at the beginning of the second prepare operation and the original statement is not available if the second prepare operation fails. The PREPARE statement must appear in the same procedure as the DESCRIBE INPUT and DESCRIBE statements, the RELEASE statement, and the EXECUTE or cursor statements (DECLARE CURSOR, OPEN, FETCH, DELETE WHERE CURRENT, UPDATE WHERE CURRENT, and CLOSE) that are used to execute the SQL input statement. Using Statistics Information If a program declares an SQLSA structure and the PREPARE statement completes without any errors, NonStop SQL returns compilation statistics to the SQLSA structure. These statistics include information needed by the program to build the SQLDA structures for subsequent DESCRIBE and EXECUTE statements. For more information about the SQLSA and SQLDA structures, see Section 6, Error and Status Processing. RELEASE The RELEASE statement deallocates space for a dynamic SQL statement that is prepared from a host variable. The RELEASE statement must appear in the same procedure as the PREPARE statement, the DESCRIBE INPUT and DESCRIBE statements, and the EXECUTE or cursor statements (DECLARE CURSOR, OPEN, FETCH, CLOSE) that are used to execute the SQL statement. SELECT The SELECT statement typically retrieves data from one or more tables and views into host variables. There are two types of SELECT statements that you can use in a program: 3-31

NonStop SQL Statements and Directives SELECT A single-row SELECT returns a single row or value. A multi-row SELECT returns multiple rows one row at a time. To execute a SELECT statement, a TAL program's process accessor ID (PAID) must have read access to all protection views, tables, and underlying tables of all shorthand views referred to in the statement. In general, specifying a select operation programmatically in a TAL program is the same as specifying an select operation using SQLCI commands. With SQLCI, you specify the desired values in an SELECT statement, while in a program, you set one or more host variables to the desired values and then use the host variables in the SELECT statement. Executing a Single-Row SELECT Statement A single-row select statement returns a single row to the program. The INTO clause returns the single-row to one or more host variables. The row is identified in a WHERE clause by a unique key value or a unique value of a column in the row. Using a Value of a Column. This example shows a SELECT statement that returns only one row based on unique value of a column in the row (a non-key value). This example retrieves a customer s name and address. Each customer is identified by a unique number so that only one customer can satisfy this query. This example: Assumes that a user enters a customer number to retrieve the customer s name and address. Declares the host variable :FIND^THIS^CUSTOMER to hold the value of the customer number whose address is requested (set to 5635 in the example, but would be entered by a user in an actual program). Declares other host variables for the returned column values. Uses a WHERE clause to specify that the column CUSTOMER.CUSTNUM contains a unique value that is equal to the value of a host variable :FIND^THIS^CUSTOMER. Uses an INTO clause to return the single-row to the host variables. Uses BROWSE ACCESS because it does not modify the data, does not want to wait for locked data, and does not care if it reads uncommitted data. Uses the NOT FOUND condition of the WHENEVER directive to direct control to a recovery routine (not shown here) if the customer number is not found. When the SELECT statement is executed, the system scans the database to find the first row with the specified value in CUSTOMER.CUSTNUM. When found, this specific row is returned to the program. Because CUSTOMER.CUSTNUM is not a primary key, the program then reads the rest of the table to make sure the row it found is the only qualifying row; if it is not, the program returns an error. 3-32

NonStop SQL Statements and Directives SELECT EXEC SQL BEGIN DECLARE SECTION;! Variable declarations STRUCT customer^type; BEGIN INT custnum; STRING custname[0:17]; STRING street[0:21]; STRING city[0:13]; STRING state[0:11]; STRING postcode[0:9]; END; STRUCT.customer(customer^type); INT find^this^customer; EXEC SQL END DECLARE SECTION; PROC handle^not^found; FORWARD; EXEC SQL WHENEVER NOT FOUND CALL :handle^not^found;... PROC find^record; BEGIN find^this^customer := 5635; EXEC SQL SELECT custname, street, city, state, postcode INTO :customer.custname,:customer.street,:customer.city, :customer.state, :customer.postcode FROM sales.customer WHERE customer.custnum = :find^this^customer BROWSE ACCESS;...! Print values in host variables END;! end of find^record PROC driver MAIN; BEGIN CALL find^record; END;... Using a Primary Key Value. This example shows a SELECT statement that selects a row using a primary key column. EXEC SQL SELECT column2, column3, column4 INTO :host^var2, :host^var3, :host^var4 FROM mytable WHERE column1 = :host^varkey ; In this example, the WHERE clause specifies that the selected row contains a primary key, COLUMN1, whose value is equal to the value of a specified host variable. Only one row is retrieved from the table because a unique primary key value is used for the selection. 3-33

NonStop SQL Statements and Directives SELECT Executing a Multi-Row SELECT Statement A multi-row SELECT statement returns multiple rows one row at a time. Because host variables cannot hold more than the first row, you must declare this type of SELECT statement as a cursor. A cursor is the mechanism for dealing with a set of rows returned in sequence to a program. To use a cursor, you use the DECLARE CURSOR, OPEN, FETCH, and CLOSE statements as shown in these steps. These steps are required even when only the next single row is needed and only one FETCH is done. 1. Name and define a cursor in a DECLARE CURSOR statement. The DECLARE CURSOR statement includes a SELECT statement to describe the rows to be returned. Initialize any host variables used in the WHERE clause of the cursor declaration. Once the cursor is declared and the values initialized, you can open the cursor and fetch each selected row sequentially. 2. Open the cursor using the OPEN statement. 3. Fetch each selected row into the program with the FETCH statement. 4. Close the cursor with the CLOSE statement. This example shows a cursor SELECT for a cursor named LISTNEXT: EXEC SQL DECLARE listnext CURSOR FOR SELECT column1, column2, column3 FROM table WHERE column1 > :host^var^key ;...! Move the initial value to :host^var^key EXEC SQL OPEN listnext ; EXEC SQL FETCH listnext INTO :host^var1, :host^var2, :host^var3 ; EXEC SQL CLOSE listnext ; A row is returned each time the FETCH statement is executed. This example retrieves all the rows with COLUMN1 values greater than the :HOST^VAR^VKEY value. 3-34

NonStop SQL Statements and Directives SQL SQL When to Initialize a Cursor. Opening a cursor causes the set of rows in the query result to be defined and ordered. If a cursor SELECT statement contains host variables in its WHERE clause, you must initialize the values of the host variables either before you open the cursor with an OPEN statement or else in the USING clause of the OPEN statement. The SQL executor places the input variables into its buffers when it opens the cursor. If you do not initialize the variables before the OPEN statement, several things can happen: If the variables contain values that do not conform to the data type expected, overflow or truncation errors can result when the cursor is opened. If the variables are of the expected type but they contain values left from a previous usage of the program, these bad values are used as a starting point for subsequent FETCH operations. As a result, the returned rows do not begin at the expected location. When to Close a Cursor. Only an explicit CLOSE statement or a FREE RESOURCES statement closes an open cursor. As a general rule, you can leave cursors open to save the overhead of reopening a cursor you plan to use again. In some cases, however, you should explicitly close open cursors. In particular, when you use cursors in PATHWAY applications, you should follow these rules: 1. Close any open cursors before returning control to a requester. 2. If your program is a server and a TMF transaction was started in a requester, close any cursors to release space used by the cursors and to free locks before returning control to the requester. The SQL TAL compiler directive causes the TAL compiler to process subsequent SQL statements and directives. Put the SQL directive in the first line of the primary source file or in the command line when you run the TAL compiler. SQL [ option ] [ ( option [, option ]... ) ] option is: [ PAGES num-pages ] [ WHENEVERLIST NOWHENEVERLIST ] [ RELEASE1 RELEASE2 ] [ SQLMAP NOSQLMAP ] 3-35

NonStop SQL Statements and Directives SQL PAGES num-pages specifies the number of 2048-byte pages of memory available to the TAL compiler to process SQL statements. The default is 384 pages, which is the minimum number required and a usable value for most programs. A recommended upper limit is 32,000. The actual upper limit depends on space allocated by the compiler and a value specified by the SYMBOLPAGES directive. By increasing the value, you increase the number of lines allowed in an SQL statement. WHENEVERLIST NOWHENEVERLIST controls writing active WHENEVER options to the listing file after each SQL statement is processed. WHENEVERLIST specifies writing the options. NOWHENEVERLIST WHENEVER options are not written. NOWHENEVERLIST is the default. RELEASE1 RELEASE2 specifies the NonStop SQL release version that supports the program. This release option affects the version of the SQLDA structures generated for the application and internally marks the object program as RELEASE1 or RELEASE2. RELEASE1 specifies object code and SQLDA structures that are compatible with the NonStop SQL C10 compiler. If you specify RELEASE1, the program can be SQL compiled and run on a C10 or C30 system. You can use RELEASE1 to develop programs on a C30 system that will run on a C10 system. The SQLDA structure, however, does not support null values or the C30 SQL data types: FLOAT, DOUBLE PRECISION, REAL, DATETIME, DATE, TIME, TIMESTAMP, and INTERVAL. If you compile the program with a NonStop SQL C10 compiler, the SQL compiler rejects C30 features. For detailed information on RELEASE2 features and using the release version options, see Appendix D, NonStop SQL Version Issues. RELEASE2 specifies object code and SQLDA structures that are compatible with the NonStop SQL C30 compiler. A program compiled with RELEASE2 cannot be SQL compiled or run on a NonStop SQL C10 system. RELEASE2 is the default. 3-36

NonStop SQL Statements and Directives SQLMEM SQLMAP NOSQLMAP specifies whether the compiler listing includes an SQL map. This map enables you to determine SQL statements using output from the Measure program. SQLMEM SQLMAP causes an SQL map to be added at the end of the compiler listing. An SQL map is a table that contains the: Run-time data unit (RTDU) name in the format: _SQLRTDU_ julian-timestamp Section location table (SLT) index number Source file name Source file line number The table is sorted first by RTDU name and then by SLT index number. You can use this table to correlate Measure output with the SQL statement. The global RTDU contains the cursors and CONTROL directives that are declared in the global declarations. NOSQLMAP causes the SQL map not to be added. NOSQLMAP is the default. The SQLMEM TAL compiler directive specifies where in memory the TAL compiler places the SQLIN, SQLIVARS, and SQLOVARS SQL data structures. These data structures, which describe SQL statements and host variables, are passed to the SQL executor at run time. Although your program does not explicitly declare these structures and cannot directly access them, you can control their placement in memory. Table 3-3 shows the internal data structures and when each structure is generated. 3-37

NonStop SQL Statements and Directives SQLMEM Table 3-3. NonStop SQL Data Structures SQL Data Structure SQLIN SQLIVARS SQLOVARS Generated For Each: SQL statement or directive except:: BEGIN DECLARE SECTION and END DECLARE SECTION directives CONTROL directives INCLUDE directive INVOKE directive WHENEVER directive DECLARE CURSOR statement for static cursors DECLARE CURSOR statement for dynamic cursors that do not use cursor or statement host variables SQL statement that has input host variables SQL statement that has output host variables The SQLMEM directive has this syntax: SQLMEM { USER } { EXT } { STACK } { MAPPED address length } USER causes the TAL compiler to place the SQL data structures in the global area, which is addressable with 16 bits. Specify USER only if the global area can hold all of the SQL data structures. EXT causes the TAL compiler to place the SQL data structures in the automatic extended segment. The extended segment is the default if you do not specify the SQLMEM directive. If your program uses the EXT option, SQL statements can access data only in the default extended segment. If your program uses the EXT option and manages extended segments with the USESEGMENT procedure, you must ensure that the default extended segment is always visible when SQL statements are executed. If you need to access data in another extended segment, you can copy the data needed by the SQL statements to the global area of the user data stack or to the default extended segment before executing the SQL statement. However, use this technique carefully, because data is not always accessed when you might expect. 3-38

NonStop SQL Statements and Directives SQLMEM For example, a host variable used in a DECLARE CURSOR statement is not accessed when the DECLARE CURSOR statement is processed; it is accessed when the cursor is opened. STACK places the SQL data structures in the default extended segment only initially. Before an SQL statement executes, the system allocates space at the top of the stack and issues a MOVEX procedure call to copy the SQL data structures needed for that statement to the top of the stack. After each SQL statement executes, the system deallocates the top of the stack. The STACK option allows you to have any extended segment active at the time an SQL statement executes, because the MOVEX procedure can copy data from inactive segments. In programs that are close to using all their stack space, however, using the STACK option can cause a stack overflow because extra stack space must be used to temporarily hold the SQL data structures. When an error is returned from a generated call to the MOVEX procedure, the TAL compiler sets SQLCODE to 254. If an SQLCA structure is present, NonStop SQL also sets this error in the SQLCA. The STACK option cannot appear in a subprocedure. MAPPED address length places the SQL data structures in the default extended segment only initially. Before each SQL statement, the system calls the MOVEX procedure to copy the SQL data structures to a location in memory you specify in the currently active extended segment. Because moving data between segments is slower than moving data to the stack, the MAPPED option can degrade system performance. To use the MAPPED option, your SOURCE directive for $SYSTEM.SYSTEM.EXTDECS must specify the MOVEX and USESEGMENT procedures. Use the MAPPED option if your program manages extended segments with the USESEGMENT procedure and does one of these: Does not use the default extended segment Contains SQL statements that refer to host variables located in a segment other than the default extended segment and you do not have enough memory available in the data stack to select the USER or STACK option. address is the address in the current extended segment where you want the compiler to place the data structures. This address can be a constant, literal, or variable string (data type STRING.EXT). When you use a variable or literal, the compiler evaluates the name in the same scope as the SQL statement being compiled, and not where the SQLMEM directive appears. 3-39

NonStop SQL Statements and Directives SQLMEM length is the number of bytes that are available at address for the data structures. This length should be large enough to hold the largest SQL statement description expected in your program (that is, the sum in bytes of the SQLIN, SQLIVARS, and SQLOVARS structures). The value cannot exceed 65,536. You can use a constant or a literal for length. When you use a literal, the compiler evaluates the name as for address, in the same scope as the SQL statement being compiled. Follow these steps to estimate a value for length: 1. Compile the program with a high value. Use the information under Estimating Sizes for SQLIN and SQLVARS on page 3-41 to estimate the value. 2. Check the compiler listing. When SQLMEM MAPPED is specified, the listing shows the total size needed to store the SQL data structures for each SQL statement by printing the this message after each SQL statement: SQLMEM: MOVEX length = movex-length. The maximum size needed is also computed and printed at the end of the listing with the message: SQLMEM: Maximum MOVEX length = maximum-length. If length is too small, the compiler generates an error. 3. If necessary, change the length to a value at least equal to the maximum MOVEX length as shown at the end of the listing. Ensuring That SQL Data Structures Are Accessible The following data structures must be accessible in the active extended segment whenever your program executes an SQL statement: SQLIN for the specific statement SQLIVARS and SQLOVARS (together called SQLVARS) for the input and output host variables in the statement. The host variables themselves must also be accessible. For a static OPEN, any host variables referenced in the DECLARE CURSOR statement must also be accessible. SQLCA structure for error handling SQLSA structure for statistics and dynamic SQL The SQLCA and SQLSA structures are always allocated on the standard data stack. SQLIN and SQLVARS are allocated by default in the default extended segment, or by the programmer using SQLMEM. 3-40

NonStop SQL Statements and Directives SQLMEM Estimating Sizes for SQLIN and SQLVARS The size estimates for the SQL data structures are: Structure Size, Bytes SQLCA 430 (approximate) SQLSA 838 (approximate) SQLIN 72 To estimate the size of the SQLIVARS and SQLOVARS structures, use this formula: size = (4 + 24 * n ) bytes where n is the number of host variables. For example, for the statement: SELECT * FROM table WHERE col1 = :a AND col2 = :b ; where TABLE has 200 columns, you would need 4804 bytes to store the SQLOVARS structure for the host variables to receive the column values, plus 52 bytes to store the SQLIVARS structure for the host variables to supply values for the WHERE clause. Using Shared Memory If you are using shared memory, consider these items, which apply to any shared memory situation in TAL: If two or more programs use the same data area for SQL data structures, you must protect each SQL statement from concurrent execution of other SQL statements. To avoid this situation, use different areas of memory for each program or synchronize access to the shared segment. If you place the SQL data structures in a read-only data segment, obscure errors can occur as a result of interactions with the operating system. Recommendations For various programming environments follow these general guidelines. Specific programs, however, might require different analysis and methods. If your program does not need to manage extended segments, omit SQLMEM and allow the compiler to place the SQLIN and SQLVARS structures in the default extended segment. If your program has few SQL statements, the statements are small, and you do not expect to add statements, use SQLMEM USER. If your program was written before the availability of the default extended segment and the program manages its own extended segments with the ALLOCATESEGMENT and USESEGMENT procedures, use one of these choices (listed in order of preference): Specify the USER option if your program has a small number of SQL statements, the statements reference a small number of host variables, and you do not expect to add statements. 3-41

NonStop SQL Statements and Directives SYMBOLPAGES Specify the STACK option to allow TAL to create a default extended segment for initial placement of the data structures. Convert the program to use the default extended segment and specify the EXT option (or allow EXT to be the default). For some programs, the MAPPED option might be simpler to implement than to convert the program. Specify the MAPPED option. As for the STACK option, TAL creates a default extended segment to store the data structures initially. If your program uses the default extended segment and also manages additional extended segments, use SQLMEM based on your specific environment and the guidelines in this section. Because memory allocation can change in various parts of a program, you might need to specify SQLMEM more than once. SYMBOLPAGES The SYMBOLPAGES TAL compiler directive specifies the number of 2048-byte pages that the TAL compiler allocates for the symbol table. The TAL compiler uses the symbol table as a temporary storage area in memory for processing variables. The syntax for SYMBOLPAGES is: SYMBOLPAGES num-pages num-pages specifies the number of pages that the TAL compiler should allocate for the symbol table in the automatic extended data segment. The range is 512 through 32767 pages. The default is 512 pages. If a symbol table overflow occurs, the TAL compiler displays error 57 (symbol table overflow). Use SYMBOLPAGES to enlarge the size of the table. To specify the SYMBOLPAGES directive, you must issue the directive on the command line for the TAL compiler when you compile a program. For example: UPDATE TAL /IN tsrc, OUT $s.#tlst, NOWAIT/ tobj; SYMBOLPAGES 4096 The UPDATE statement updates values in one or more columns in a row or set of rows of a table or a protection view. The number of rows is determined by the WHERE clause. An UPDATE statement can update: A single row A set of rows 3-42

NonStop SQL Statements and Directives UPDATE A set of rows, one row at a time using a cursor (a mechanism for dealing with a set of rows returned in sequence to a program) A lock on an updated row is held until the TMF transaction is committed or rolled back (audited table) or until the program releases the lock (nonaudited table). To execute an UPDATE statement, a program's process accessor ID (PAID) must have read and write access to the table or view being updated. A program's PAID must also have read access to any table or view specified in subqueries of the search condition. In general, specifying an update operation programmatically in a TAL program is the same as specifying an update operation using SQLCI commands. With SQLCI, you specify the new values in an UPDATE statement, while in a program, you set one or more host variables to the new values and then use the host variables in the UPDATE statement. The UPDATE statement updates rows in sequence. If an error occurs, NonStop SQL returns an error code to the SQLCODE variable and terminates the operation. This table shows the SQLCODE values that NonStop SQL returns after an UPDATE statement. SQLCODE Value Description 0 The UPDATE statement was successful. 100 No rows were found for a search condition. < 0 An error occurred; SQLCODE contains the error number. > 0 (not 100) A warning occurred; SQLCODE contains the first warning number. The SQLCA structure contains the number of rows updated. To obtain the contents of the SQLCA, use the SQLCADISPLAY or SQLCATOBUFFER procedure. Updating a Single Row A single-row update operation updates a single row in a table. This example updates a single row of the ORDERS table that contains information about order number 200038. This example declares the host variables :ORDERS and :NEWDATE, which serve as input variables in the UPDATE statement. (In a program, a user enters values for :ORDERS and :NEWDATE; in the example, they are set using assignment statements.)! Variable declarations: EXEC SQL BEGIN DECLARE SECTION; STRUCT.orders; BEGIN INT(32) ordernum; STRING orderdate[0:9]; STRING deliv^date[0:9]; INT salesrep; INT custnum; END; string newdate[0:9]; 3-43

NonStop SQL Statements and Directives UPDATE EXEC SQL END DECLARE SECTION;...! Procedure code: PROC update^orders; BEGIN... newdate ':=' "1987-05-22"; orders.ordernum := 200038; EXEC SQL UPDATE orders SET deliv^date = :newdate TYPE AS DATE WHERE ordernum = :orders.ordernum STABLE ACCESS; END;... Updating Multiple Rows Using a Single UPDATE Statement Multi-row operations (sometimes called set operations) are performed on one or more rows by a single SQL statement. These operations provide maximum efficiency in both coding and execution. Use set operations wherever possible for updating sets of rows. However, sometimes, you must check a row before updating it. In this case, you must use cursors as described under Using a Cursor to Update Multiple Rows on page 3-44. The following single statement updates the SALARY column of every row in the EMPLOYEE table where the current value of the SALARY column is less than the value of the host variable :HOSTVAR^MIN^SALARY. (A user enters values for :HOSTVAR^INC and :HOSTVAR^MIN^SALARY.) EXEC SQL UPDATE employee SET salary = salary * :hostvar^inc WHERE salary < :hostvar^min^salary ; This example updates all rows in the DEPTNUM column that contain the value in the :HOSTVAR^OLD^DEPTNUM host variable. Effectively, all employees who were previously in department 100 are now in department 200. (A user enters values for :HOSTVAR^OLD^DEPTNUM and :HOSTVAR^NEW^DEPTNUM.) EXEC SQL UPDATE employee SET deptnum = :hostvar^new^deptnum WHERE deptnum = :hostvar^old^deptnum ; Using a Cursor to Update Multiple Rows To read and test each value before you update it, you must use a cursor. A cursor allows you to update a set of rows one row at a time. You specify the set of rows with the SELECT clause in the DECLARE CURSOR statement. You read each row using a FETCH statement, test the data, and then ignore or update the row depending on your test logic. 3-44

NonStop SQL Statements and Directives UPDATE When you use a cursor to select rows for subsequent update, you must use the FOR UPDATE OF clause in the cursor declaration. If you determine you want to update the data, you use a WHERE CURRENT OF clause to update the row from the table. Note. Do not use a stand-alone UPDATE operation to update a row that has been retrieved using a cursor FETCH operation. This can invalidate the cursor's buffering for the table and might degrade performance. For audited tables and views, a TMF transaction must be in progress. The same TMF transaction must include the OPEN, FETCH, and UPDATE operations. This example declares a cursor, fetches and tests the data, then updates the row: EXEC SQL DECLARE check_emp CURSOR FOR SELECT deptnum FROM employee WHERE deptnum = :deptnum^del OR deptnum = :deptnum^upd FOR UPDATE OF deptnum ; EXEC SQL FETCH check_emp INTO :deptnum ;! Program logic to test the data... EXEC SQL UPDATE employee! Update deptnum in current row SET deptnum = :newdept WHERE CURRENT OF check_emp ; You can refer to a static SQL cursor only in the compilation unit where the cursor is declared. Thus, for static SQL programs, the UPDATE WHERE CURRENT, DECLARE CURSOR, OPEN, FETCH, and CLOSE statements that refer to the cursor must be in the same compilation unit. If a program exits a procedure with an open cursor, procedures that execute later can still refer to the cursor, provided the procedures are in the same compilation unit. For a dynamic SQL cursor, all statements referring to the cursor must appear in the procedure where the cursor is defined. However, if you open the cursor and use it in a call to the procedure where it is defined, you can still use the cursor in subsequent calls without opening the cursor again. This example uses a cursor to position in the PARTS table on the part number specified by host variable STARTING^PARTNUM. The example can then fetch rows and determine whether to update data in the columns. The row updated is at the current position of the cursor GET_BY_PARTNUM_CURSOR. 3-45

NonStop SQL Statements and Directives UPDATE The example uses the host variables :NEW^PARTDESC, :NEW^PRICE, and :NEW^QTY and sets them to new values (entered by a user) for the columns before executing the UPDATE statement. EXEC SQL DECLARE get_by_partnum_cursor CURSOR FOR SELECT partnum, partdesc, price, qty_available FROM sales.parts WHERE (partnum >= :starting^partnum ) STABLE ACCESS FOR UPDATE OF partdesc, price, qty_available;...! Declare host variables new^partdesc, new^price,and new^qty....! Get one row from the PARTS table: EXEC SQL FETCH get_by_partnum_cursor... ;...! Determine whether this is a row to be updated...! If the row is to be updated, assign update values to! new^partdesc, new^price, and new^qty. If necessary,! update the row at the current cursor position. EXEC SQL UPDATE sales.parts SET partdesc = :new^partdesc, price = :new^price, qty_available = :new^qty WHERE CURRENT OF get_by_partnum_cursor; 3-46

NonStop SQL Statements and Directives WHENEVER Updating a Column With a Null Value This example updates a column by setting the column to a null value using an indicator variable. This example uses the TACL DEFINE name =EMPLOYEE for the EMPLOYEE table.! Variable declarations: EXEC SQL BEGIN DECLARE SECTION; EXEC SQL INVOKE =employee AS emp^tbl; STRUCT.emp(emp^tbl); INT ind^1; EXEC SQL END DECLARE SECTION;...! Executable statements: ind^1 := -1; EXEC SQL UPDATE =employee SET salary =:emp.salary INDICATOR :ind^1 WHERE jobcode = :hostvar^jobcode; This example uses the NULL keyword instead of an indicator variable: WHENEVER EXEC SQL UPDATE =employee SET salary = NULL WHERE jobcode = :hostvar^jobcode; The WHENEVER directive specifies an action that a program takes depending on the outcome of subsequent statements DML, DCL, and DDL SQL statements. For a description of the WHENEVER directive, see Section 6, Error and Status Processing. 3-47

NonStop SQL Statements and Directives WHENEVER 3-48

4 System Procedures Use the provided system library procedures, written in TAL, to perform various SQL functions. The EXTDECS file contains source declarations for these procedures. Use the SOURCE directive to specify the declarations in the EXTDECS file for the procedures that you want to call in your program. For example, this directive specifies declarations for the SQLCADISPLAY and SQLCAFSCODE procedures:?source $SYSTEM.SYSTEM.EXTDECS ( SQLCADISPLAY,? SQLCAFSCODE ) Table 4-1 describes the SQL system procedures by function. The procedures beginning with SQL are described in this section. The FILEINQUIRE procedure is described in the Guardian Procedure Calls Reference Manual. Table 4-1. System Procedures for NonStop SQL Operations Procedure Description Displaying Errors and Warnings SQLCADISPLAY Writes to a file or terminal the error and warning messages that NonStop SQL returns to the program. SQLCAFSCODE Returns information about file-system, disk-process, or NonStop Kernel operating system errors returned to the program. SQLCAGETINFOLIST Writes to a record area in a program a subset (which you specify) of the error or warning information in the SQLCA. SQLCATOBUFFER Writes to a record area in the program the error or warning messages that NonStop SQL returns to the program. Displaying Execution Statistics SQLSADISPLAY Writes to a file or terminal the execution statistics that NonStop SQL returns to the program. Retrieving Version Information SQLGETCATALOGVERSION Returns a value that indicates the version of an SQL catalog. SQLGETOBJECTVERSION Returns a value that indicates the version of an SQL objects (represents the oldest NonStop SQL release that can perform all DML and most DDL operations for a given SQL table, index, or view.) SQLGETSYSTEMVERSION Returns a value that indicates the version of the NonStop SQL file-system and disk-process components on a given system. Determining the Catalog for a Table, Index, or View FILEINQUIRE (Guardian procedure) Returns information about a file. The input codes 13 and 14 apply specifically to SQL objects. 4-1

System Procedures Procedure Descriptions Procedure Descriptions The following SQL procedures are described in alphabetical order on subsequent pages. Each description includes the syntax, parameter definitions, and guidelines. SQLCADISPLAY SQLCAFSCODE SQLCAGETINFOLIST SQLCATOBUFFER SQLGETCATALOGVERSION SQLGETOBJECTVERSION SQLGETSYSTEMVERSION SQLSADISPLAY SQLCADISPLAY The SQLCADISPLAY procedure displays information that NonStop SQL returns to the SQLCA data structure. SQLCADISPLAY writes this information to a file or terminal. NonStop SQL communicates errors, warnings, and statistics to a program through the SQLCA. However, because the SQLCA contains information in a format that is not suitable to display, you must call the SQLCADISPLAY procedure to convert this information to a suitable format. The SQLCA information can be from these subsystems or system components: NonStop SQL FASTSORT program (SORTPROG process) Sequential I/O (SIO) procedures File system NonStop Kernel operating system 4-2

System Procedures SQLCADISPLAY Disk process (DP2) CALL SQLCADISPLAY ( sqlca^! i, [ output^file number ]! i, [ output^record^length ]! i, [ sql^msg^file^number ]! i,o, [ errors ]! i, [ warnings ]! i, [ statistics ]! i, [ caller^error^loc ]! i, [ internal^error^loc ]! i, [ prefix ]! i, [ prefix^length ]! i, [ suffix ]! i, [ suffix^length ]! i, [ detail^params ] ) ;! i sqlca^ input INT.EXT is a pointer to the SQLCA structure. The TAL compiler automatically declares the SQLCA structure when you specify the INCLUDE SQLCA directive. output^file^number input INT is the output file number. If you omit this value or set it to a negative value, SQLCADISPLAY displays information at your home terminal. In this case, SQLCADISPLAY opens your home terminal, displays the message, and then closes your terminal. NonStop ignores this parameter if detail^params specifies sequential I/O (SIO). output^record^length input INT defines the length in bytes of records to be written to the output file. The length must be an integer value from 60 through 600. The default length is 79 bytes. sql^msg^file^number input/output INT is the file number of the SQLMSG file. If you specify 1 on input, the system opens the SQLMSG file and returns the resulting file number. If you specify a value other than 1, the system uses that value as the file number of the SQLMSG file. To improve the performance of a program that makes multiple calls to the SQLCADISPLAY (or SQLCATOBUFFER) procedure, specify a variable containing 1 on the first call, and then use the returned file number for subsequent calls. By 4-3

System Procedures SQLCADISPLAY using the file number, the system opens the file only once and uses the file number for subsequent calls; otherwise, the system opens the file for each call. errors input INT controls the display of error messages. The values you can specify and their meanings are: N Y B Display only the first error. Display all errors. Display all errors but suppress this prefix: ERROR from subsystem [nn]: The default is Y. warnings input INT controls the display of warning messages. The values you can specify and their meanings are: N Display no warning messages. Y Display all warning messages. B Display all warnings but suppress the prefix: WARNING from subsytem [nn]: The default is Y. statistics input INT controls the display of statistics. The values you can specify and their meanings are: Y Display row and cost statistics if the value returned to the SQLCA in the ROW or COST field is greater than or equal to 0. R Display rows only. C Display cost only. N Display no statistics. The default is Y. 4-4

System Procedures SQLCADISPLAY caller^error^loc input INT controls displaying the program name and line number of the SQL statement that received the error. The values you can specify and their meanings are: Y Enable the display of the information. N Suppress the display of the information. The default is Y. internal^error^loc input INT controls displaying the location in system code where the first error in the SQLCA structure occurred. The values you can specify and their meanings are: Y Enable the display of the information. N Suppress the display of the information. The default is Y. prefix input STRING.EXT specifies a string that the program uses to precede each output line. The default is three asterisks and a space (*** ). prefix^len input INT specifies the length of the prefix string to precede each output line. The length can be an integer value from 1 through 15. If you include the prefix parameter, you must also include this parameter. If you omit the prefix parameter, you must also omit this parameter. suffix input STRING.EXT specifies a string to be appended to each output line. The default is a null string. 4-5

System Procedures SQLCADISPLAY suffix^len input INT specifies the length of the suffix string to append to each output line; the length can be an integer value from 1 through 15. If you include the suffix parameter, you must also include this parameter. If you omit the suffix parameter, you must also omit this parameter. detail^params input INT.EXT determines whether the program uses sequential SIO (SIO) or Enscribe I/O (which is the default) for writing to the output file. The parameter DETAIL^PARAMS points to a structure with this declaration: STRUCT detail^params; BEGIN STRING sio; INT.EXT out^fcb^1; INT.EXT out^fcb^2 ; END; sio specifies whether sequential I/O is used; sio can have these values: Y Use sequential I/O; ignore output^file^number. N Do not use sequential I/O; write to output^file^number. outfcb1 specifies the first output file control block if sio is enabled. outfcb2 specifies the second output file control block if sio is enabled. To use outfcb2, assign it a value greater than 0. Guidelines Follow these guidelines when you call the SQLCADISPLAY procedure: NonStop SQL returns errors as negative numbers and warnings as positive numbers. If there is no text for an error number, NonStop SQL displays: No error text found. The $SYSTEM.SYSTEM.SQLMSG file contains the error text for SQL messages. If you receive this message, your version of the SQLMSG file might not match the version of the SQL executor. 4-6

System Procedures SQLCAFSCODE If the error text exceeds output^record^length, the output is wrapped at word boundaries producing subsequent lines that are indented 5 spaces. The SQLCA can contain a maximum of 7 errors and 180 bytes of text of the actual parameters returned to the program. Any information that exceeds these limits is lost. SQLCADISPLAY prints a warning message that indicates when information is lost. A call statement to the SQLCADISPLAY procedure using all default parameters is: CALL SQLCADISPLAY (SQLCA); An example of diagnostic messages that SQLCADISPLAY might generate is: *** WARNING from SQL [100]: Record not found or end of file *** encountered on table \SYS1.$VOL1.SALES.ODETAIL. *** SQLCA display of SQL statement at: SCAN.#201.1 process \SYS1.$B *** Error detected within SQL executor at: EXE^EXEC.#450 *** ERROR from SQL [-8408]: Division by zero occurred. *** Statistics: Rows accessed/affected: 10 *** Estimated cost: 100 SQLCAFSCODE The SQLCAFSCODE procedure returns either the first or the last error in the SQLCA structure that was set by the file system, disk process, or NonStop Kernel operating system. SQLCAFSCODE returns 0 if the requested error does not exist. error := SQLCAFSCODE ( sqlca^! i, [ first^flg ] ) ;! i error returned value INT returns the requested error. Zero (0) indicates this error does not exist. sqlca^ input INT.EXT is a pointer to the SQLCA structure. The TAL compiler automatically declares the SQLCA structure when you specify the INCLUDE SQLCA directive. 4-7

System Procedures SQLCAGETINFOLIST first^flg input INT specifies whether the first or the last error is set in the SQLCA. You can set first^flg as follows: Nonzero value (or omitted) First error 0 Last error Guidelines Follow these guidelines when you call the SQLCAFSCODE procedure: If the SQLCA is full when a file-system error occurs, the error is lost and cannot be returned by SQLCAFSCODE. Use SQLCAFSCODE to get the Guardian or file-system error code that occurs for an SQL operation. You can then determine the action your program should take, depending on this error rather than on the SQL error. This example shows a call to the SQLCAFSCODE procedure: INT fserr;!guardian 90 or file-system error EXEC SQL INCLUDE SQLCA;... fserr := SQLCAFSCODE (sqlca);! Check fserr to determine the error... SQLCAGETINFOLIST The SQLCAGETINFOLIST procedure returns error or warning information that NonStop SQL sets in the SQLCA structure. You specify a list of numbers, called item codes, to select this information, and then SQLCAGETINFOLIST returns the information to a structure you define. By using item codes, you can specify the exact information you want SQLCAGETINFOLIST to return. This information can be from these subsystems or system components: NonStop SQL FASTSORT program (SORTPROG process) Sequential I/O (SIO) procedures File system NonStop Kernel operating system 4-8

System Procedures SQLCAGETINFOLIST Disk process (DP2) error := SQLCAGETINFOLIST ( sqlca^! i, itemlist! i, numberitems! i, result! o, resultmax! i, [ errorindex ]! i, [ namesmax ]! i, [ paramsmax ]! i, [ resultlen ]! o, [ erroritem ] ) ;! o error returned value INT returns the outcome of the operation. Zero (0) indicates a successful operation. For more information on the description of other return values, see Table 4-3 on page 4-12. sqlca^ input INT.EXT is a pointer to the SQLCA structure. The TAL compiler automatically declares the SQLCA structure when you specify the INCLUDE SQLCA directive. itemlist input INT.EXT is an array of item codes that describes the information you want returned in the result structure. For more information on the list of these codes, see Table 4-2 on page 4-11. numberitems input INT is the number of items you specified in the itemlist array. result output INT.EXT is a structure you define to receive the requested information. The items are returned in the order you specified in itemlist. Each item is aligned on a word boundary. 4-9

System Procedures SQLCAGETINFOLIST resultmax input INT is the maximum size, in bytes, of the result structure. errorindex input INT is the index of the SQLCA error or warning entry. The SQLCA has a fixed set of fields (item codes 1 21) that pertain to all errors and warnings. In addition, SQLCA has a table of records (item codes 22 29) with each record describing one error or warning. NonStop SQL uses errorindex to access this table to determine the error or warning If errorindex is omitted, NonStop SQL returns the first error record. namesmax input INT is the maximum length your program allows for procedure names or file names (item codes 9, 13, and 19). Longer names are truncated (and no error results from the truncation). paramsmax input INT is the maximum length your program allows for parameter information (item codes 16 and 29). Parameter information that exceeds this length is truncated (no error results from the truncation). resultlen output INT.EXT returns the total number of bytes used in the result structure. erroritem output INT.EXT returns the index of the item being processed when the error occurred. The index starts at 0. Table 4-2 lists the codes you can specify in the itemlist array. 4-10

System Procedures SQLCAGETINFOLIST Table 4-2. SQLCAGETINFOLIST Procedure Item Codes (page 1 of 2) Item Code Size (in bytes) Description 1 2 SQLCA version. 2 2 Maximum number of errors or warnings the SQLCA can represent. 3 2 Actual number of errors or warnings. 4 2 Whether there were more errors or warnings than the SQLCA had space to store: 0 There were no more errors or warnings. Nonzero There were more errors or warnings. 5 2 Whether there were more parameters than the SQLCA had space to store: 0 There were no more parameters. Nonzero There were more parameters. 6 2 Maximum byte length of the name of the function in which the SQL statement appears. 7 2 Actual byte length of the name of the function in which the SQL statement appears. 8 (in item Name of the function in which the SQL statement appears. code 7) 9 4 Source code line number of the SQL statement that caused an error. 10 2 Syntax error location; if there was no syntax error, SQL returns 1. 11 2 Maximum byte length of the system procedure that sets the first error or warning. 12 2 Actual byte length of the system procedure that sets the first error or warning. 13 (in item Name of the system procedure that sets the first error or warning. code 12) 14 2 Maximum byte length of the parameter buffer. 15 2 Used bytes in the parameter buffer. 16 (in item Parameter buffer. code 15) 17 2 Maximum byte length of the source name buffer. 18 2 Used bytes in the source name buffer. 19 (in item Source name buffer. code 18) 20 4 Number of processed rows. 21 8 Estimated query cost. 4-11

System Procedures SQLCAGETINFOLIST Table 4-2. SQLCAGETINFOLIST Procedure Item Codes (page 2 of 2) Item Code Size (in bytes) 22 2 SQL error or warning number 23 2 Subsystem ID: First byte is 0; second byte can be one of these letters: S Compiler, catalog manager, executor, SQLUTIL, SQLCI F SQL file system D DP2 disk process G NonStop Kernel operating system R FASTSORT program (SORTPROG process) L Load routines I Sequential I/O (SIO) procedures 24 2 Suppress printing this error (0 = False, nonzero = True) 25 2 Offset into the parameters buffer for parameters associated with the call. SQL returns 1 if there are no parameters. 26 2 Number of parameters for this error. 27 2 Sequence in which the error or warning was set. 28 2 Size of the buffer that contains parameters. 29 (in item code 28) Description Buffer that contains parameters, delimited by zero. Each parameter begins on an even word boundary and is preceded by 2 bytes. Table 4-3 lists the SQLCAGETINFOLIST error codes. Table 4-3. SQLCAGETINFOLIST Procedure Error Codes Error Code Description 8510 A required parameter is missing. 8511 The program specified an invalid item code. 8512 The program specified an invalid SQLCA structure. 8513 The program specified an SQLCA structure with a version that is more recent than the version of the SQLCAGETINFOLIST procedure. 8514 Insufficient buffer space is available. 8515 The program specified an error entry index that is less than zero or greater than the number of errors. 8516 The program specified a namesmax parameter that is less than or equal to zero. 8517 The program specified a paramsmax parameter that is less than or equal to zero. 4-12

System Procedures SQLCATOBUFFER In the example below, SQLCAGETINFOLIST returns the: Name of the function containing the SQL statement that produced one or more errors or warnings Name length of the function Number of errors or warnings that occurred To avoid coding the maximum length for the function name (NAME[0:29] in this example): 1. Call SQLCAGETINFOLIST passing item code 7 (ERR^WARN.NAMELEN). 2. Call SQLCAGETINFOLIST again passing a buffer of the appropriate size.! Declare a structure to hold the error information STRUCT.err^warn; BEGIN INT namelen; INT numerrs; STRING name[0:29]; END;! Include the SQLCA structure EXEC SQL INCLUDE SQLCA;! Declare a variable to hold the return code for the call INT errcode;! Declare and initialize the itemlist array INT itemlist[0:2] := [ 7, 3, 8 ];! 7 code for name length! 3 code for number of errors/warnings! 8 code for procedure id! Call SQLCAGETINFOLIST errcode := SQLCAGETINFOLIST ( sqlca,! SQLCA structure itemlist,! List of item codes 3,! Number of items err^warn,! Result goes here $LEN(err^warn),! Size of result area,! No error index needed 30 );! Truncate names greater! than 30 characters SQLCATOBUFFER The SQLCATOBUFFER procedure writes to a buffer the error or warning messages that NonStop SQL returns to the application program. The buffer is a record area declared in the variable declarations in the TAL program. The messages can be from these subsystems or system components: 4-13

System Procedures SQLCATOBUFFER NonStop SQL FASTSORT program (SORTPROG process) Sequential I/O (SIO) procedures File system NonStop Kernel operating system Disk process (DP2) CALL SQLCATOBUFFER ( sqlca! i, output^buffer! i,o, output^buffer^length! i, [ first^output^record ]! i, [ output^records ]! o, [ more ]! o, [ output^record^length ]! i, [ sql^msg^file^number ]! i,o, [ errors ]! i, [ warnings ]! i, [ statistics ]! i, [ caller^error^loc ]! i, [ internal^error^loc ]! i, [ prefix ]! i, [ prefix^length ]! i, [ suffix ]! i, [ suffix^length ] ) ;! i sqlca input INT.EXT is a pointer to the SQLCA structure. The TAL compiler automatically declares the SQLCA structure when you specify the INCLUDE SQLCA directive. output^buffer input/output STRING.EXT specifies the buffer name where SQLCATOBUFFER writes the error information. output^buffer^length input INT specifies the length of output^buffer in bytes. This length must be: An integer value from output^record^length through 600 A multiple of output^record^length The recommended minimum length is 300 bytes. 4-14

System Procedures SQLCATOBUFFER first^output^record input INT is the ordinal number of the first error record (line) to be written to the output buffer. The procedure discards any error records with a lower number. The default is 1. The count of lines begins with 1. To obtain more than one error record, you must increment the value in first^output^record. output^records output INT is the number of records (lines) written by SQLCATOBUFFER to output^buffer. more output.int returns a flag that indicates whether all the desired lines fit into the output^buffer. The values SQLCATOBUFFER can return and their meanings are: Y There were additional records; the buffer overflowed. N There were no additional records. output^record^length input INT defines the length of records to be written to the output^buffer; the length must be an integer value from 60 through 600. The default is 79 bytes. The procedure pads each line with blanks and adds the suffix and prefix strings if the call specifies them. sql^msg^file^number input/output INT contains the file number of the SQLMSG file. If you pass 1 on input, the system opens the SQLMSG file and returns the resulting file number. If you pass a value other than 1, the system uses that value as the file number of the SQLMSG file. You can improve performance when your program makes multiple calls to the SQLCATOBUFFER (or SQLCADISPLAY procedure) by specifying a variable containing 1 on the first call and then including the returned file number on subsequent call statements. By including the file number, the system opens the file only for the first call and uses the file number for subsequent calls; otherwise, the system must open the file for every call. 4-15

System Procedures SQLCATOBUFFER errors input INT controls the error messages that are written to the buffer. The values you can specify and their meanings are: N Write only the first error. Y Write all errors. B Write all errors but suppress the prefix: ERROR from subsystem [nn]: The default is Y. warnings input INT controls the warning messages that are written to the buffer. The values you can specify and their meanings are: N Write no warning messages. Y Write all warning messages. B Write all warnings but suppress the prefix: WARNING from subsystem [nn]: The default is Y. statistics input INT controls the statistics that are written to the buffer. The values you can specify and their meanings are: Y Write row and cost statistics if the value returned to the SQLCA in the ROW or COST data item is greater than or equal to 0. R Write rows only. C Write cost only. N Write no statistics. The default is Y. 4-16

System Procedures SQLCATOBUFFER caller^error^loc input INT controls writing the program name and line number of the SQL statement that received the error. The values you can specify and their meanings are: Y Enable writing of the information. N Suppress writing of the information. The default is Y. internal^error^loc input INT controls writing the location in system code where the first error in the SQLCA occurred. The values you can specify and their meanings are: Y Enable writing the information. N Suppress writing the information. The default is Y. prefix input STRING.EXT specifies a string to precede each output line. The default is three asterisks and a space (*** ). prefix^len input INT specifies the length of the prefix string precede each output line; the length can be an integer value from 1 through 15. If you include the prefix parameter, you must also include this parameter. If you omit the prefix parameter, you must also omit this parameter. suffix input STRING.EXT specifies a string to be appended to each output line. The default is a null string. 4-17

System Procedures SQLCATOBUFFER suffix^len input INT specifies the length of the suffix string to append to each output line; the length can be an integer value from 1 through 15. If you include the suffix parameter, you must also include this parameter. If you omit the suffix parameter, you must also omit this parameter. Guidelines Follow these guidelines when you call the SQLCATOBUFFER procedure: NonStop SQL returns errors as negative numbers and warnings as positive numbers. If there is no text for an error number, NonStop SQL displays: No error text found. The $SYSTEM.SYSTEM.SQLMSG file contains the error text for SQL messages. If you receive this message, your version of the SQLMSG file might not match the version of the SQL executor. SQLCATOBUFFER works by starting with the first^record^number indicated to move output lines to the record area until all error messages are moved or until the text fills the record area. SQLCATOBUFFER returns to output^records a count of the lines moved to the buffer. If an overflow occurs, the procedure sets the more flag to Y. On an overflow condition, your program can retrieve the rest of the error message text by calling SQLCATOBUFFER again, setting first^output^record to output^records + 1. This example uses a 75-character output record and a buffer of 375 characters. The example also declares an SQLMSG file number, which it initializes to -1. The SQLCATOBUFFER call returns the SQLMSG file number so that it can be used in subsequent calls. CALL SQLCATOBUFFER ( sqlca,! SQLCA structure msg^buf,! Message buffer 375,! Buffer length,,,! Omitted 75,! output record size sqlmsg^file);! SQLMSG file number 4-18

System Procedures SQLGETCATALOGVERSION SQLGETCATALOGVERSION The SQLGETCATALOGVERSION procedure returns the version of an SQL catalog. error := SQLGETCATALOGVERSION ( [ catalogname ]! i, sqlversion ) ;! o error returned value INT returns the outcome of the operation. Zero (0) indicates a successful operation. For a description of SQL errors, see the SQL/MP Messages Manual. catalogname input STRING.EXT specifies the fully qualified name of the catalog for which you are requesting information. The name must be: Left justified and padded with blanks A maximum of 26 characters If you omit catalogname, SQLGETCATALOGVERSION uses the default catalog. sqlversion output INT.EXT is the version of the catalog. The procedure returns one of these values: 1. Version 1 catalog (created by NonStop SQL C10) 2. Version 2 catalog (created by NonStop SQL C30) SQLGETOBJECTVERSION The SQLGETOBJECTVERSION procedure returns a value that indicates the SQL object version. This value represents the oldest NonStop SQL release that can perform all DML and most DDL operations defined for a given table, view, or index. error := SQLGETOBJECTVERSION ( objectname,! i sqlversion ) ;! o error returned value INT returns the outcome of the operation. Zero (0) indicates a successful operation. For a description of SQL errors, see the SQL/MP Messages Manual. 4-19

System Procedures SQLGETOBJECTVERSION objectname input STRING.EXT specifies the fully qualified file name of the NonStop SQL object for which you are requesting information. The name must be: Left justified and padded with blanks A maximum of 34 characters sqlversion output INT.EXT is the version of the object. The value returned is: 1. Version 1 object that is compatible with NonStop SQL C10 2. Version 2 object that is compatible with NonStop SQL C30 Guidelines If the object uses any of the Version 2 features shown in this table, SQLGETOBJECTVERSION returns a value representing a Version 2 object. Otherwise, SQLGETOBJECTVERSION returns a value representing a Version 1 object. Table 4-4. NonStop SQL Release C30 (Version 2) Features Category Data Types Functions Exponentiation Features Features FLOAT (includes REAL and DOUBLE PRECISION) DATETIME (includes DATE, TIME, and TIMESTAMP) INTERVAL UPSHIFT CHARACTER or VARCHAR Date-time functions UPSHIFT function Columns that can contain null values Clustering key Constraints using Version 2 data types or functions The following attributes are Version 2 features that do not cause SQLGETOBJECTVERSION to return the value 2 in sqlversion. To determine if these attributes are present, a program must query the catalog tables containing the description of the table or view. NO AUDITCOMPRESS attribute HEADING attribute HELP TEXT attribute 4-20

System Procedures SQLGETSYSTEMVERSION These attributes, however, are considered Version 2 features by the catalog manager process, which handles DDL statements. Tables and views that use these features must be handled by DDL statements executed on a NonStop SQL C30 system. SQLGETSYSTEMVERSION The SQLGETSYSTEMVERSION procedure returns the version of NonStop SQL file system and disk process components that are running on a system. error := SQLGETSYSTEMVERSION ( [ nodenumber ]! i, sqlversion ) ;! o error returned value INT returns the outcome of the operation. Zero (0) indicates a successful operation. For more information on the description of SQL errors, see the SQL/MP Messages Manual. nodenumber input INT specifies the node number of the system for which you are requesting information. The default is the local system. sqlversion output INT.EXT is the NonStop SQL software release version for the system. The values for sqlversion are: 1. NonStop SQL C10 (release 1) 2. NonStop SQL C30 (release 2) Guidelines Follow these guidelines when you call the SQLGETSYSTEMVERSION procedure: For a specific system, you can assume that all NonStop SQL components are the same release level. When you request the version number for a remote system, SQLGETSYSTEMVERSION returns the version information for the remote disk process. A successful call does not guarantee that NonStop SQL is installed on the remote system. If you try to return the version of a remote system that has NonStop SQL release C10 installed, SQLGETSYSTEMVERSION returns an error. 4-21

System Procedures SQLSADISPLAY SQLSADISPLAY The SQLSADISPLAY procedure displays the execution statistics of SQL statements. However, SQLSADISPLAY does not display an SQLSA structure produced by a PREPARE statement. CALL SQLSADISPLAY ( sqlsa^! i, [ sqlca^ ]! i, [ out^file^number ]! i,o, [ detail^params ] ) ;! i sqlsa^ input INT.EXT is a pointer to the SQLSA structure. The TAL compiler automatically declares the SQLSA structure when you specify the INCLUDE SQLSA directive. sqlca^ input INT.EXT is a pointer to the SQLCA structure. The TAL compiler automatically declares the SQLCA structure when you specify the INCLUDE SQLCA directive. The SQLCA structure contains the procedure name and line number of the SQL statement that set the SQLSA. If you omit the SQLCA name, the display does not contain the procedure name and process name of the caller. out^file^number input INT is the output file number. If you omit this value or set it to a negative value, SQLDADISPLAY displays information at your home terminal. NonStop ignores this parameter if detail^params specifies sequential I/O (SIO). detail^params input INT.EXT determines whether the application uses SIO or Enscribe I/O (which is the default) to write to the output file. detail^params points to a structure with this declaration: STRUCT detail^params; BEGIN STRING sio; INT.EXT out^fcb^1; INT.EXT out^fcb^2 ; END; The fields in the detail^params structure are: 4-22

System Procedures SQLSADISPLAY sio specifies whether sequential I/O (SIO) is used; it can have these values: Y Use SIO; ignore out^file^number. N Do not use SIO; write to out^file^number. out^fcb^1 specifies the first output file control block if SIO is enabled. out^fcb^2 specifies the second output file control block if SIO is enabled. To use this field, assign it a value greater than 0. Guidelines The PREPARE statement continually redefines the fields of the SQLSA during the execution of dynamic SQL statements. Therefore, SQLSADISPLAY cannot display an SQLSA returned by a PREPARE statement. SQLSADISPLAY displays statistics in this format: SQL statistics @ \ system.$vol.subvol.file.#line process cpu,pin Records Records Disc Message Message Lock Table Name Accessed Used Reads Count Bytes WE This table describes the elements of the SQLSADISPLAY display: Table 4-5. SQLSADISPLAY Procedure Display Elements Element Description \ system.$ vol. subvol. file The fully qualified file name of the calling program # line The line number of the calling program process cpu,pin The processor and PIN of the calling program Table Name The name of each table Records Accessed The number of records accessed in each table (includes records examined by the disk process, file system, and SQL executor) Records Used The number of records actually used by the statement Disc Reads The number of disk reads caused by accessing this table Message Count The number of messages sent to execute operations on this table Message Bytes The number of message bytes sent to access this table Lock WE A flag indicating either that lock waits occurred (W) or that lock escalations occurred (E) for the table 4-23

System Procedures SQLSADISPLAY Figure 4-1 shows an example of the information that SQLSADISPLAY displays at the home terminal. To generate this display, a program must: 1. Include the SQLSA and SQLCA structures. 2. Execute an SQL DML statement. 3. Call the SQLSADISPLAY procedure: CALL SQLSADISPLAY (sqlsa, sqlca); Figure 4-1. SQLSADISPLAY Display SQL statistics @ \sanfran.$system.accts.prog10.#333.2 process 12,255 Table Name Records Accessed Records Used Disc Reads Message Count Message Bytes Lock WE \sanfran.$sqlvol.accts.tab10 123 22 3 10 3245 \sanfran.$vol001.fy91.employee 9987231 1 99999 1 100 e \sanfran.$sqlvol.accts.tab20 1 1 0 1 100 w VST0401.vsd 4-24

5 Program Compilation and Execution This section describes the compilation and execution of a TAL program that contains embedded SQL statements. This section covers: Compiling a TAL source program including running the TAL and SQL compilers, running the Accelerator, and using the Binder program Determining SQL program file validity Understanding automatic SQL recompilation Maximizing local autonomy Executing an SQL program file Figure 5-1 on page 5-2 shows the steps you follow to compile and execute a TAL program that contains embedded SQL statements. Steps 1 through 4 are described under Compiling a TAL Program on page 5-2. These steps are similar to the steps for compiling a TAL program that does not contain embedded SQL statements, except for the SQL compilation step (Step 4). Step 5 is described under Executing an SQL Program File on page 5-30. 5-1

Program Compilation and Execution Compiling a TAL Program Figure 5-1. Compiling and Executing a Program TAL/SQL TALLIB Source File (s) Run-Time Library TAL Compiler Binder Accelerator SQL Compiler 1 2 3 4 TAL/SQL TAL/SQL TAL/SQL Obejct File (s) Single Object File Single Object File TAL/SQL Obejct File TAL Object Code TAL Object Code TAL TNS and TNS/R Object Code 5 Run the object file SQL Source Statements SQL Source Statements SQL Source Statements VST0501.vsd Compiling a TAL Program To compile a TAL source file that contains embedded SQL statements: 1. Run the TAL compiler to compile the TAL statements in each source file of your program. 2. Use the Binder program, if necessary, to combine multiple object files into one object file. 3. Run the SQL compiler to compile the SQL statements in the TAL object file. These steps are described in detail in this section. 5-2

Program Compilation and Execution Running the TAL Compiler Running the TAL Compiler To run the TAL compiler, enter an implicit TACL RUN command at your TACL prompt or from an OBEY command file. The syntax is: TAL / [ IN source-file ] [, OUT list-file ] [, run-option] [, run-option]... / [ object-file ] [ ; directive [, directive ]... ] directive can be: [ SYMBOLPAGES num-pages ] [ SQL [ option ] [ ( option [, option ]... ) ] option is: [ PAGES num-pages ] [ RELEASE1 RELEASE2 ] [ SQLMAP NOSQLMAP ] [ WHENEVERLIST NOWHENEVERLIST ] source-file is the primary source file of your compilation unit. The source file can be an EDIT format disk file (file code 101), a terminal, a magnetic tape unit, or a process. The default is your home terminal (if your TACL process is in interactive mode). list-file is the name of the file that receives the output from the compiler. If you specify OUT without a list file, TAL suppresses the output. If you omit OUT and you started the compiler from your TACL process, the OUT file is your home terminal. Often, the list file is a spooler location (for example, $S.#TALLIST). run-option is a TACL RUN command option, as described in the TACL Reference Manual. object-file is a Guardian file name that specifies the bindable object code for the compilation unit. If you omit the object file, the compiler creates a file named OBJECT on your default subvolume. If the compiler cannot create OBJECT (usually, because a file with this name already exists and cannot be purged), the compiler creates a file 5-3

Program Compilation and Execution Using the Binder Program named ZZBI nnnn on your default subvolume (nnnn is a 4-digit number determined by the system). directive is a TAL compiler directive as described in this manual or in the TAL Reference Manual. You must include the SQL directive either in the command line or at the beginning of the primary source file. Other TAL compiler directives are optional. For more information on the description of the SQL directive, see Section 3, NonStop SQL Statements and Directives. In this example, the TAL compiler compiles the source file PARTSRC, writes the listing to the spooler location $S.#PARTLST, and writes the object file to the disk file PARTOBJ on your default subvolume. TAL /IN partsrc, OUT $s.#partlst, NOWAIT / partobj; SQL For more information about TAL compiler options, see the TAL Reference Manual. Using the Binder Program The Binder program allows you to read, link, modify, and build executable object files for SQL and TAL object files (as well as C, COBOL85, and Pascal object files). Follow these guidelines when you bind SQL object files: Consider SQL object files to be like other object files. Bind object files after they are compiled by either the TAL or the SQL compiler. Binding invalidates a previously SQL validated object file (which is the result of a successful explicit SQL compilation). You must explicitly SQL compile the file again to revalidate it. Caution. Do not use the Binder STRIP command on object files that contain embedded SQL statements. The STRIP command removes the Binder and INSPECT tables from the object file. Without the Binder table, the SQL compiler cannot compile the program and the SQL executor cannot execute the program. Including the TALLIB Run-Time Library Before you can compile an object file using the SQL compiler, the TALLIB run-time library must be bound with the object file. The TALLIB library should be installed on the same subvolume as the TAL compiler. Specify the TALLIB library file either during the TAL compilation using a SEARCH directive or after compilation using the Binder program. 5-4

Program Compilation and Execution Running the Accelerator When you run the TAL compiler, use the SEARCH directive to include the TALLIB runtime library. This SEARCH directive appears in a TAL source file:! TAL source file?search ($system.system.tallib)... You can also specify the SEARCH directive in the command line for the TAL compiler: TAL /IN partsrc, OUT $s.#partlst, NOWAIT / partobj ; SQL, SEARCH ($system.system.tallib) These Binder commands build an object file named PROGOBJ that includes the TALLIB library: ADD * FROM progobj SELECT SEARCH $system.system.tallib BUILD progobj! Running the Accelerator If your object file will run on a TNS/R system, you can run the Accelerator to optimize the object code. Because the Accelerator invalidates SQL object files, you must run it before you run the SQL compiler. For more information about the Accelerator, see the Programmer s Guide for TNS/R Systems and the Accelerator Manual. Running the SQL Compiler The SQL compiler generates SQL object code in the TAL object file. SQL compilation also verifies the SQL objects used in SQL statements and generates an optimized execution plan for each SQL statement. Optionally, you can invoke the EXPLAIN utility to produce a report on the execution plans for SQL DML statements and the TACL DEFINEs used by the program. (For a complete list of SQL compiler functions, see What Does the SQL Compiler Do? on page 5-11. 5-5

Program Compilation and Execution Running the SQL Compiler To run the SQL compiler, use the SQLCOMP command. The syntax is: SQLCOMP / IN object-file [, OUT [ list-file ] ] [, run-option] [, run-option ]... / [ compiler-option [, compiler-option ]... ] compiler-option is: [ CATALOG catalog-name ] [ CURRENTDEFINES STOREDDEFINES ] [ EXPLAIN ] [ [ PLAN ] ] [ [ DEFINES [ file-name ] [, OBEYFORM ] ]] [ ] [ NOEXPLAIN ] [ FORCE NOFORCE ] [ OBJECT NOOBJECT ] [ RECOMPILE NORECOMPILE ] [ RECOMPILEONDEMAND RECOMPILEALL ] object-file is a disk file name. This file cannot be in a user library or a system library. The object file can be generated by the: TAL compiler Binder program Accelerator SQL compiler You must run the SQL compiler on the same system where object-file exists. If you do not specify a system or volume name, the SQL compiler uses your current default values. list-file identifies the destination where the SQL compiler directs the listing; list-file can be a disk file name, process name (including a spooler collector), or a device name (including a terminal, magnetic tape unit, or line printer). The syntax is: [\ system.] external-file 5-6

Program Compilation and Execution Running the SQL Compiler \ system is an optional system name. external-file is one of these Guardian names: [$ volume-name.][subvolume-name.] disk-file-name $ device-name $ device-number $ process-name $ spooler-collector-name[.# spooler-location-name] If list-file does not exist, the SQL compiler creates it. If list-file already exists, the SQL compiler appends the new output to it. If you specify OUT but omit list-file, the SQL compiler does not produce a listing. If you omit OUT, the SQL compiler directs the listing to the OUT file of the invoking process (which is usually your home terminal). run-option is a TACL RUN command option, as described in the TACL Reference Manual. catalog-name is the name of the catalog that is to hold a description of the program; catalogname is a subvolume name. If you partially qualify the catalog name, the system expands the name by using your current default values. You can also specify a TACL CLASS CATALOG DEFINE name for catalog-name. The catalog, object file, and SQL compiler must be on the same system. If the program was previously SQL compiled and recorded in a different catalog, catalog-name overrides the catalog name stored in the program file. The program is dropped from the previous catalog and recorded in catalog-name. If you omit the CATALOG clause, the SQL compiler uses the current default catalog. If you have not defined a default catalog, the SQL compiler uses your current default subvolume. CURRENTDEFINES STOREDDEFINES specifies the set of TACL DEFINEs used to interpret DEFINE names in the SQL statements in the program file. CURRENTDEFINES selects the current set of TACL DEFINEs for compiling the program. CURRENTDEFINES is the default. 5-7

Program Compilation and Execution Running the SQL Compiler STOREDDEFINES selects set of TACL DEFINEs stored with the program the last time it was SQL compiled. This option applies only to programs that have been SQL compiled. FORCE NOFORCE controls how syntax errors affect SQL compilation. FORCE directs the SQL compiler to produce a valid, executable object file regardless of any syntax errors. The SQL compiler writes the SQL source statements to the object file so that the statements can automatically be recompiled if executed at run time. You can use the FORCE option to debug a program if you do not need to execute the SQL statements that generate errors. NOFORCE directs the SQL compiler to produce the SQL object file only if there are no syntax errors. NOFORCE is the default. [ EXPLAIN ] [ [ PLAN ] ] [ [ DEFINES[ file-name ][, OBEYFORM ] ] ] [ ] [ NOEXPLAIN ] controls whether the compiler invokes the EXPLAIN utility. EXPLAIN PLAN enables the EXPLAIN utility. selects the optimized execution plan determined by the SQL compiler for DML statements in the program. PLAN is the default. DEFINES [ file-name ] [, OBEYFORM ] displays the TACL DEFINEs used to SQL compile the SQL statements. The DEFINEs appear at the end of the SQL compiler listing. These DEFINEs are the ones that would be used if you were to recompile the program with the STOREDDEFINES option. file-name is the destination where the DEFINE listing is written. The destination is an external-file as described for OUT list-file. 5-8

Program Compilation and Execution Running the SQL Compiler OBEYFORM NOEXPLAIN specifies writing the TACL DEFINE list in OBEY format so that you can enter an OBEY command from your TACL prompt to set the DEFINEs before run time or compile time. If you omit OBEYFORM, the listing is in the format displayed by the INFO DEFINE command. If you omit DEFINES, a DEFINE listing is not generated. disables the EXPLAIN utility. NOEXPLAIN is the default. OBJECT NOOBJECT controls whether the compiler produces an SQL program file. OBJECT directs the compiler to generate an SQL program file (depending on whether errors occur and whether the FORCE or NOFORCE option is in effect). OBJECT is the default. NOOBJECT directs the compiler to perform checking functions, to generate an EXPLAIN listing if you have also specified EXPLAIN, and not to produce an SQL program file. RECOMPILE NORECOMPILE specifies whether the program should be automatically recompiled, if necessary. RECOMPILE directs the SQL compiler to automatically recompile a program whenever all of these conditions occur at run time: The program file is marked invalid. Run-time TACL DEFINEs are different from SQL compile-time DEFINEs. The timestamp check on file opens indicate that the program should have been marked as invalid, but it was not marked because the program was network-inaccessible or already executing. An access path is unavailable. RECOMPILE is the default. 5-9

Program Compilation and Execution Running the SQL Compiler NORECOMPILE directs the SQL compiler not to automatically recompile the program. (Therefore, if any of the preceding run-time conditions occur, the program cannot continue execution and would need explicit SQL compilation for revalidation.) RECOMPILEONDEMAND RECOMPILEALL specifies whether the compiler should recompile an entire invalid program or only those SQL statements that require recompilation and are actually executed. If you specify NORECOMPILE, this option is ignored. RECOMPILEONDEMAND directs the SQL compiler to recompile only those statements in the invalid program that are actually executed. Automatic recompilation occurs the first time an individual SQL statement is executed. RECOMPILEALL directs the SQL compiler to automatically recompile the entire program if it is invalid. Automatic recompilation occurs at program load time. RECOMPILEALL is the default. In this example, the SQL compiler compiles the program file PARTOBJ, writes the listing to the spooler location $S.#PARTLST, and records the program file in catalog PROGCAT on volume $VOL1. Upon successful completion of the run, the compiler rewrites PAROBJ as a validated SQL program file. SQLCOMP /IN partobj, OUT $s.#partlst, NOWAIT / & CATALOG $vol1.progcat Caution. Do not use the same name for different procedures in separate source modules if the modules contain SQL statements. NonStop SQL might interpret internal data structures as duplicates, which would cause the SQL statements in one of the procedures not to be included in the SQL object program. Access Privileges To SQL compile a program file, you must have these access privileges: Read and purge authority for the program file Read and write authority for the PROGRAMS, USAGES, and TRANSIDS tables of the catalog in which the program is to be registered Read and write authority for the USAGES and TRANSIDS tables of any catalog in which a table, view, or index that the program uses is registered 5-10

Program Compilation and Execution Running the SQL Compiler Statistics Information For the SQL compiler to determine the best execution plan, it needs the current statistics for any referenced tables. To provide these statistics, a database administrator can use the UPDATE STATISTICS statement, which writes statistical information about the tables in the catalog in which the table is registered. For more information, see the UPDATE STATISTICS statement in the SQL/MP Reference Manual. What Does the SQL Compiler Do? When you SQL compile a program file, the SQL compiler performs these functions: Resolves names. The compiler expands SQL object names, including TACL DEFINE names, in the program using the current default volume, the current catalog. Checks object references in catalogs. The compiler checks the catalogs for SQL object names to verify their existence and to read their descriptions. Then, the compiler evaluates the object type and characteristics for each reference. Determines an optimized execution plan. The compiler analyzes the SELECT, INSERT, UPDATE, and DELETE statements to determine the best access paths and join, sort, and blocking strategies for executing each statement. Then, the compiler writes the object code for the execution plan to the program file. Generates executable code. The compiler compiles the execution plan into executable object code. Stores information in catalogs. If the compilation is successful, the compiler registers the program in the specified PROGRAMS catalog table and stores dependencies in the USAGES table. The compiler also stores dependencies in the USAGES catalog table of the catalogs where tables, views, and indexes that the program uses are registered. Marks the program file SQL sensitive and SQL valid. If the compilation is successful, the compiler sets the SQL sensitive and SQL valid indicators in the program's file label. Generates a listing. The compiler writes the compiler listing (including any warning or error messages) to the OUT file or device. Estimates execution cost. For SQL DML statements, the compiler lists an estimate for the cost of processing the statement based on the statistics in the catalogs. Reports error and warning conditions. The compiler reports error and warning conditions, as described under Interpreting SQL Compiler Messages on page 5-14. 5-11

Program Compilation and Execution Running the SQL Compiler SQL Program File Format The input program file to the SQL compiler can be a TAL object file, a file generated by the Binder program, a file generated by the Accelerator, or a file previously compiled by the SQL compiler. Figure 5-2 shows the format of a NonStop SQL program file. Figure 5-2. NonStop SQL Program File Format SQL Program File SQL Valid SQL Sensitive Compilation Timestamp File Label Information Generated by the SQL Compiler TAL Object Code Object Code Generated by the TAL Compiler SQL Source Statement 1 SQL Source Statement 2... SQL Source Statements Stored by the TAL Compiler SQL Source Statement n SQL Object Code Execution Plans Generated by the SQL Compiler Stored DEFINES VST0502.vsd 5-12

Program Compilation and Execution Running the SQL Compiler Using a PARAM Command With the SQL Compiler Use the TACL PARAM command to specify the BINSERV processes and the swap-file subvolume that the SQL compiler uses for explicit SQL compilation. A PARAM command does not apply to automatic SQL recompilation or dynamic SQL compilation. The syntax for the PARAM command for explicit SQL compilation is: PARAM [ parameter-name parameter-value ] [, parameter-name parameter-value ]... parameter-name parameter-value are parameter name and value pairs. These pairs apply to the SQL compiler: BINSERV guardian-90-name SWAPVOL subvol BINSERV guardian-90-name specifies the program file of the BINSERV program that the SQL compiler uses during compilation. Follow these guidelines for guardian-name: If guardian-90 - name designates a system other than the system on which the SQL compiler is running, the BINSERV parameter is ignored. If guardian-90-name does not include a volume or subvolume name, the SQL compiler uses your current default values. The default value for guardian-90-name is the BINSERV program file on the same subvolume as the SQL compiler. SWAPVOL subvol designates a subvolume as the location for temporary files. If you do not specify a SWAPVOL subvolume, the SQL compiler uses your default subvolume for temporary files. You enter a PARAM command before you run the SQL compiler. For example: PARAM BINSERV $talsql.utils.binserv, SWAPVOL $scratch... SQLCOMP /IN tobj, OUT $s.#tlst, NOWAIT / CATALOG $vol.cat To see parameters that are currently defined, enter a PARAM command without any parameter name and value pairs. For more information about the PARAM command, see the TACL Reference Manual. 5-13

Program Compilation and Execution Running the SQL Compiler Interpreting SQL Compiler Messages The SQL compiler issues messages for error and warning conditions. An error can prevent successful compilation of a program file, but a warning does not prevent successful compilation. For a description of SQL compiler messages, see the SQL/MP Messages Manual. Error Conditions. An error condition results from an invalid reference to an SQL object in an SQL statement. Examples of invalid references are incorrect column names or incompatible data types. If an error occurs, the SQL compiler produces a listing, but it does not record the program file in the catalog and does not validate it for execution. Dynamic SQL statements are not compiled during explicit SQL compilation. These statements are compiled at run time by a PREPARE statement, which returns a runtime error if invalid syntax or an invalid reference occurs. You can force the SQL compilation regardless of errors. To force compilation, specify the FORCE option in the SQLCOMP command. If you use the FORCE option, the compiler records the SQL object program file in the catalog and validates the program file for execution even if errors occur. The FORCE option is sometimes useful for program debugging when you are not concerned about executing the SQL statements that produce errors. The SQL compiler also writes the SQL source statements that have errors to the object file so that the statements can be automatically recompiled if executed at run time. Warning Conditions. A warning condition usually occurs when the SQL compiler has insufficient information available. If a warning occurs, the SQL compiler still records the program file in the catalog and validates the file for execution and then returns a warning message. The following paragraphs describe some of the conditions that cause warnings. In these two cases, the SQL compiler issues a warning message but still compiles the statement: Compiler assumptions The compiler made an assumption necessary to complete the compilation. For example, if the number of columns in the SELECT statement does not match the number of host variables, the compiler returns a warning message and assumes that you do not want to use either the extra columns or the extra host variables. Unavailable statistics The compiler did not have the necessary statistics for tables to optimize an execution plan. The compiler uses statistics in the catalog in which a table or view is registered to determine an optimized execution plan. These statistics are usually generated by a database administrator running the UPDATE STATISTICS statement on tables. 5-14

Program Compilation and Execution Running the SQL Compiler For other cases, the SQL compiler first marks the statement as having insufficient information to compile and then at run time tries to resolve the problem with automatic recompilation. The SQL compiler does not record dependencies in the USAGES catalog tables for the affected statement. At run time, if the necessary information is still not available or any TACL DEFINEs are still unresolved, execution of the statement causes an error. These cases are: Insufficient information The SQL compiler did not have enough information to determine the validity of a statement. For example, an SQL statement refers to a table that is unavailable because the table is on an unavailable remote node. (Another example is an SQL statement that refers to a table that does not exist. This case always occurs for a program that both creates and refers to a table; the table, of course, does not exist when the program is explicitly SQL compiled.) Unresolved TACL DEFINEs An SQL statement often uses a TACL DEFINE name that is not present in the DEFINE set when the program is explicitly SQL compiled. SQL Compiler Listings The SQL compiler writes all the SQL statements in the program file to a listing. If error or warning conditions occur, the compiler writes messages following the statements that cause the condition. For SQL DML statements, the SQL compiler includes the estimated cost of processing the statement in the listing following the statement. This estimate is a positive integer that indicates the relative cost. For example, the larger the value, the more processor time and disk access time is required to execute the statement. Figure 5-3 shows a sample SQL compiler listing. 5-15

Program Compilation and Execution Running the SQL Compiler Figure 5-3. Sample SQL Compiler Listing (page1of2) SQL Compiler - T9095C30 - (01NOV91) COPYRIGHT TANDEM COMPUTERS INCORPORATED 1987, 1988, 1989, 1990, 1991 DATE - TIME : 11/15/91-10:08:10 Options : NOFORCE, OBJECT, CURRENTDEFINES, RECOMPILE, RECOMPILEALL, NOEXPLAIN SQL - PROGRAM FILE = \SYS1.$VOL1.SQLTAL.PROGOBJ SQL - PROGRAM CATALOG = \SYS1.$VOL1.DBI SQL - DEFAULT CATALOG = \SYS1.$VOL1.DBI 222 ************************************************************* SQL - Source File = $VOL1.SQLTAL.PROG ROLLBACK WORK 187 145 146 147 148 *** Statistics: Estimated cost: 1 170 171 172 173 174 *** Statistics: Estimated cost: 2 101 48 49 50 51 52 53 54 55 56 57 *** Statistics: Estimated cost: 1 COMMIT WORK INSERT INTO =PARTLOC VALUES ( :PARTLOC^REC.LOC^CODE, :PARTLOC^REC.PARTNUM, :PARTLOC^REC.QTY^ON^HAND ) INSERT INTO =PARTS VALUES ( :PARTS^REC.PARTNUM, :PARTS^REC.PARTDESC, SETSCALE (:PARTS^REC.PRICE, 2), :PARTS^REC.QTY^AVAILABLE) BEGIN WORK DECLARE GET_SUPPLIER_CURSOR CURSOR FOR SELECT SUPPNUM, SUPPNAME, STREET, CITY, STATE, POSTCODE FROM =SUPPLIER WHERE SUPPNUM = :SUPPLIER^OF^PARTS REPEATABLE ACCESS VST0503.vsd 5-16

Program Compilation and Execution Using the EXPLAIN Utility Figure 5-3. Sample SQL Compiler Listing (page2of2) BINDER - OBJECT FILE BINDER - T9621C30 - (01NOV91) SYSTEM \SYS1. Copyright Tandem Computers Incorporated 1982-1989, 1991 Object file \SYS1.$VOL1.SQLTAL.PROGOBJ TIMESTAMP 1991-11-15 10:08:10 2 Code Pages 12 Primary data words 408 Secondary data words 64 Data pages 0 Resident code pages 2 Extended data pages PAGE 1 11/15/91-10 : 08 : 10 Heap location: Extended data space 1 Heap size in pages 420 Top of stack location in words 1 Code segment 0 Binder Warnings 0 Binder Errors PAGE 2 11/15/91-10 : 08 : 10 SQL ************************************************************************************ SQL - Summary of SQL Compiling SQL - Number of SQL Statements = 6 SQL - Number of SQL Errors = 0 SQL - Number of SQL Warnings = 0 SQL - Number of other Errors = 0 SQL - Compile Time 00 : 00 : 01.137 SQL - Elapsed Time 00 : 00 : 34.294 SQL - Program file is \SYS1.VOL1.SQLTAL.TROGOBJ SQL - > > > SQL COMPILATION STORED IN PROGRAM FILE < < < SQL ************************************************************************************ VST0503a.vsd Using the EXPLAIN Utility The EXPLAIN utility generates reports about the execution plans used for each SQL statement. You can use EXPLAIN reports to determine the database tables and indexes used by your program. You can also determine whether creating other indexes or modifying a query would improve the performance of your program. The EXPLAIN utility has these report options: EXPLAIN PLAN report EXPLAIN DEFINES report 5-17

Program Compilation and Execution Using the EXPLAIN Utility Generating an EXPLAIN PLAN Report The EXPLAIN PLAN report applies only to SQL DML statements. A plan shows the strategy for executing a DML statement and includes optimized access paths, joins, and sorts. The EXPLAIN PLAN report generates a plan for a statement that contains subqueries into separate query plans, one for each subquery and one for the statement itself. This report numbers the query plans in each statement in the order they appear. Each plan can contain these steps: 1. Scan a table 2. Join two or more tables 3. Insert into a table 4. Perform a sort operation In the next example, the SQL compiler compiles the newprog program file using the EXPLAIN PLAN option to generate the statement execution plans. The command also specifies the catalog name rather than use the current default subvolume name for the catalog. The SQL compiler writes the output to the spooler. The command is: SQLCOMP / IN newprog, OUT $s.#explain, NOWAIT / &... CATALOG sales, EXPLAIN PLAN By default, the SQL compiler uses the current set of TACL DEFINEs to create the object file. In the next example, the SQL compiler writes an execution plan and set of DEFINEs to the EDIT file EXOUT, but it does not recompile the OXPLAIN program file: SQLCOMP /IN oxplain, OUT exout/ NOOBJECT STOREDDEFINES & EXPLAIN PLAN DEFINES, OBEYFORM The catalog name for the program unit is stored in the program file so that you do not have to include the CATALOG option. NOOBJECT suppresses the generation of a new object file, so the compiler does not write a record about the program file to the catalog. The TACL DEFINE set is the set stored with the program OXPLAIN. The execution plans are the plans that the compiler would generate if it were generating object code; they are not the plans stored in the object file OXPLAIN. Generating an EXPLAIN DEFINES Report The EXPLAIN DEFINES report shows the mapping of TACL DEFINE names used in SQL DML, DCL, and DDL statements. This report lists: Each TACL DEFINE name and its associated Guardian name The default volume and default catalog used by the program (which it obtains from the =_DEFAULTS DEFINE) 5-18

Program Compilation and Execution Using the EXPLAIN Utility You can have the EXPLAIN utility generate the EXPLAIN DEFINES report in either of these formats: OBEY command file format INFO DEFINE format The EXPLAIN utility generates the TACL ADD DEFINE commands for the DEFINEs. You can subsequently use the TACL OBEY command to generate the commands in the file. The EXPLAIN utility uses the format produced by the TACL INFO DEFINE command. Figure 5-4 shows an example of the OBEY command file format report. In an actual report, each instance of subvolume-name, guardian-name, and define-name would be replaced by the actual name. Figure 5-4. OBEY Command File Format of the EXPLAIN DEFINES Report ALTER DEFINE = _DEFAULTS, VOLUME subvolume-name ALTER DEFINE = _DEFAULTS, CATALOG subvolume-name ADD DEFINE = define-name, FILE guardian-90-name ADD DEFINE = define-name, FILE guardian-90-name... VST0504.vsd Note. When you issue an OBEY command using the OBEY command file format to compile or execute a program, ensure that these TACL DEFINE parameters are set as follows: SET DEFMODE ON SET DEFINE CLASS MAP Figure 5-5 shows an an example of the INFO DEFINE format report. In an actual report, each instance of guardian-name and define-name would be replaced by the actual name. 5-19

Program Compilation and Execution Using the EXPLAIN Utility Figure 5-5. INFO DEFINE Format of the EXPLAIN DEFINES Report DEFINE NAME CLASS VOLUME CATALOG DEFINE NAME CLASS FILE =_DEFAULTS DEFAULTS guardian-90-name guardian-90-name define - name MAP guardian-90-name DEFINE NAME CLASS FILE define - name MAP guardian-90-name...... VST0505.vsd Figure 5-6 shows an EXPLAIN report that includes both the execution plans and stored DEFINEs. The EXPLAIN sample listing shows the SQL compiler options in effect, a portion of the execution plan, and the DEFINEs report in the OBEY command file format. 5-20

Program Compilation and Execution Using the EXPLAIN Utility Figure 5-6. EXPLAIN Utility Report SQL Compiler - T9095C30 - (01NOV91) COPYRIGHT TANDEM COMPUTERS INCORPORATED 1987, 1988, 1989, 1990, 1991 DATE - TIME : 11/15/91-09:18:15 Options : NOFORCE, NOOBJECT, STOREDDEFINES, RECOMPILE, RECOMPILEALL, EXPLAIN PLAN DEFINES, OBEYFORM SQL - PROGRAM FILE = \SYS1.$VOL1.PROGS.OXPLAIN SQL - PROGRAM CATALOG = \SYS1.$VOL1.INVENT SQL - DEFAULT CATALOG = \SYS1.$VOL1.INVENT ************************************************************* SQL - Source File = \SYS1.$VOL1.PROGS.XPLAIN 59 60 61 62 63 64 65 66 67 68... DECLARE GET_EMP_BY_AVG_SAL_CURSOR CURSOR FOR SELECT EMPNUM, FIRST_NAME, LAST_NAME, SALARY FROM =EMPLOYEE WHERE SALARY > ( SELECT AVG (SALARY) FROM =EMPLOYEE BROWSE ACCESS ) AND DEPTNUM = :select_dept BROWSE ACCESS ----------------------------------------------------------------------------------------- QUERY PLAN : 1 STATEMENT TYPE : SELECT ----------------------------------------------------------------------------------------- 109 CONTROL EXECUTOR PARALLEL EXECUTION ON ----------------------------------------------------------------------------------------- DEFINES MAPPING ----------------------------------------------------------------------------------------- ALTER DEFINE =_DEFAULTS, VOLUME \SYS1.$VOL1.PROGS ALTER DEFINE =_DEFAULTS, CATALOG \SYS1.$VOL1.INVENT ADD DEFINE =EMPLOYEE, FILE \SYS1.$VOL1.PERSNL.EMPLOYEE ADD DEFINE =CUSTOMER, FILE \SYS1.$VOL1.SALES.CUSTOMER ADD DEFINE =ORDERS, FILE \SYS1.$VOL1.SALES.ORDERS SQL ************************************************************* SQL - Summary of SQL Compiling SQL- Number of SQL Statements = 3 SQL- Number of SQL Errors = 0 SQL- Number of SQL Warnings = 0 SQL - Number of other Errors = 0 SQL - Compile Time = 00:00:01.887 SQL - Elapsed Time = 00:00:11.656 SQL - Program file is \SYS1.$VOL1.PROGS.OXPLAIN SQL- >> PROGRAM FILE UNCHANGED BECAUSE OF NOOBJECT OPTION << SQL ************************************************************* VST0506.vsd 5-21

Program Compilation and Execution Determining Program File Validity Determining Program File Validity SQL program files can be valid or invalid. A valid program file can execute with the current description of the database. Certain operations performed on the program file or on database objects used by the program cause a program file to become invalid. An invalid program file requires SQL recompilation because of changes to either itself or the database (or both). The SQL compiler validates a program file after a successful explicit SQL compilation or after errors occurred during the compilation and the FORCE option was in effect. The SQL compiler records the validation in the file label of the program file and in the PROGRAMS catalog table. A program file has two classifications for SQL validation: SQL sensitive SQL valid The SQL sensitive classification is required for program file execution. It also protects the file from access by Enscribe utilities. The SQL compiler marks a file as SQL sensitive by setting the SQL sensitive flag in the file label. The SQL valid classification indicates that the program file can execute without automatic recompilation. An SQL valid program contains compiled SQL statements (rather than SQL source statements). An SQL valid program ensures better performance because a fully optimized execution plan is available and no automatic SQL recompilation is required. The SQL compiler sets the SQL valid flag and records the compilation timestamp in the file label during explicit SQL compilation. To determine whether an SQL program file is valid or invalid, use one of these commands: FUP FILEINFO command with the DETAIL option (described in the FUP Reference Manual) SQLCI FILEINFO or VERIFY command (described in the SQL/MP Version Management Guide) Changes to a Program File The following operations on a program file invalidate the file. An invalid program file has the VALID flag and the SQL SENSITIVE flag set to N in its file label. Moving or copying a file. For example, if you use the FUP DUPLICATE command to copy a program file, the original file is unaffected, but the new file is invalid. Binding a file. If you explicitly bind a file, the original file is unaffected, but the resulting target file is invalid. Running the Accelerator on a file. If you run the Accelerator to optimize the object code, the file becomes invalid. 5-22

Program Compilation and Execution Changes to Database Objects Changes to Database Objects When changes are made to database objects (such as tables, views, and indexes), a program file that uses these objects becomes invalid. Altering the database object requires a new execution plan for the program file. These database changes are: Executing an UPDATE STATISTICS statement with the RECOMPILE option for a table Dropping a table or view Adding an index to a table that was created by a CREATE INDEX statement with the INVALIDATE option specified Dropping an index or constraint on a table Adding a constraint, column, or partition to a table Note. These last two items invalidate a program regardless of its use of the particular index, column, or partition. A program s dependency on an affected table, as recorded in the USAGES table, causes invalidation. When a program file is invalidated by one of the operations just listed, the SQL catalog manager also resets the VALID flag for the program in the PROGRAMS catalog. Other Changes Not all changes to the program file or database cause the program file to become invalid. The database changes that do not invalidate a program file are: Renaming a program file Altering the security or owner of a program file or an object the program uses Altering the file attributes including the AUDIT flag Creating a new view on a table Adding an index to a table that was created by a CREATE INDEX statement with the NO INVALIDATE option specified Adding or dropping comments to a table or view Executing an UPDATE STATISTICS statement with the NORECOMPILE option for a table used by the program Changing a TACL DEFINE does not invalidate a program file; however, automatic recompilation might be necessary if the DEFINE is different from the one that was used during the original compilation. Sometimes, however, either the program file or the catalog in which the program is registered is not available to have the VALID flag reset. For example, a table is altered on system \SYSTEMA in a network when system \SYSTEMB is unavailable, but a program on \SYSTEMB uses the altered table on \SYSTEMA. In this case, the program on \SYSTEMB is not marked as invalid in the file label or in the catalog. 5-23

Program Compilation and Execution Understanding Automatic SQL Recompilation Therefore, an invalid program file is sometimes marked as SQL valid. NonStop SQL allows this discrepancy to provide local autonomy in database management operations. An invalid program that is erroneously marked valid is detected at run time by a timestamp check and automatically recompiled. Understanding Automatic SQL Recompilation Automatic SQL recompilation is the run-time compilation, invoked by the SQL executor, of an entire program file or a single SQL statement in a program file. The functions of automatic SQL recompilation are: Determines the most efficient access to a database by ensuring that an execution plan uses the current description of the database (this execution plan remains in effect until the program stops or another SQL recompilation occurs) Maximizes database availability and node autonomy by generating a new execution plan at run time if the currently compiled plan cannot work because a required index is unavailable Allows a program to refer to database objects that did not exist during explicit SQL compilation Allows a program to use different sets of TACL DEFINEs to specify different databases (for example, a development database and a production database) If the SQL recompilation is successful, the program file or SQL statement executes. If the recompilation fails, NonStop SQL returns an error to the SQLCODE variable and the SQL communication area (SQLCA), if it is declared. Several considerations for automatic SQL recompilation are: Automatic SQL recompilation does not validate the program file itself; it validates only the copy of the file in memory. Only explicit SQL compilation validates an invalid program file. When an SQL statement is recompiled, the SQL compiler uses the default volume and catalog that were used for the explicit compilation and the TACL DEFINEs set from SQL load time (described under SQL Load Time on page 5-25). Automatic SQL recompilation can cause the performance degradation of a program. For the best performance, run valid program files that do not need to be recompiled. Predicting Automatic SQL Recompilation You can enable or disable automatic SQL recompilation when you explicitly SQL compile a program file. When you enter the SQLCOMP command, use the RECOMPILE option (which is the default) to enable automatic SQL recompilation and the NORECOMPILE option to disable it. For application management considerations (that is, whether you want to enable or disable automatic recompilation), see the SQL/MP Installation and Management Manual. 5-24

Program Compilation and Execution Predicting Automatic SQL Recompilation If automatic SQL recompilation is enabled, these events can trigger a recompilation: SQL load time Table open time A new TACL DEFINE at SQL load time An unavailable access path (index) The attempted execution of an uncompiled SQL statement SQL Load Time SQL load time occurs when the first SQL statement in a program is executed. These conditions can cause automatic recompilation at SQL load time: If the SQL valid flag is set to invalid, recompilation occurs. Automatic recompilation of an invalid program file occurs each time the program runs. If the set of TACL DEFINEs at run time is different from the set used when you explicitly compiled the program. To control the extent of recompilation at SQL load time, use the SQLCOMP command RECOMPILEALL or RECOMPILEONDEMAND option. For automatic recompilation of the entire program, use the RECOMPILEALL option (which is the default). To limit automatic recompilation to only statements that are actually executed, use the RECOMPILEONDEMAND option. Table Open Time When the SQL executor accesses a table, an SQL statement is automatically recompiled if the timestamp for the table is different than the timestamp for the last SQL compilation of the statement. Usually, the SQL executor opens a table the first time the program executes an SQL statement that refers to the table. The executor then leaves the table open until the program stops. DDL and database utility operations on the table (or on a dependent index) cause the table to be closed and the timestamp of the table to be updated. When the SQL statement that uses the table executes again and the table has been closed, the executor compares the timestamp of the new statement to the timestamp of the table and recompiles the statement, if necessary. Only the specific SQL statement is automatically recompiled when the timestamp check reveals a discrepancy with the table timestamp. New TACL DEFINEs If the set of TACL DEFINEs at run time is different from the set when you explicitly compiled the program and you specified the SQLCOMP command RECOMPILEONDEMAND option, the statement is recompiled. The compiler uses the 5-25

Program Compilation and Execution Understanding the Run-Time Timestamp Check SQL load time TACL DEFINEs for a static SQL statement and the current active TACL DEFINEs when a PREPARE statement is executed for a dynamic SQL statement. Unavailable Access Path (Index) If the SQL executor tries to execute an SQL statement and detects that an access path in the execution plan is unavailable, the executor invokes the SQL compiler to recompile the statement. The SQL compiler then determines the best alternate access path (if such a path exists) to execute the statement. Only the affected statement is automatically recompiled when the access path becomes unavailable. Attempted Execution of an Uncompiled SQL Statement If the SQL executor encounters an uncompiled SQL statement, it invokes the SQL compiler to compile the statement. A program can contain uncompiled SQL statements if: A table or view used by an SQL statement did not exist during explicit SQL compilation. A description of a table, view, or index needed for the execution plan of an SQL statement was not available during explicit SQL compilation. The program was explicitly compiled with the FORCE option and an SQL statement had errors. Understanding the Run-Time Timestamp Check A program file and all SQL database objects (such as a tables, protection views, and indexes) have unique timestamps. The SQL executor checks each timestamp to ensure that a program file uses the current definition of an object for its execution plan. For example, consider these cases: Program PROGRAMA, which is SQL valid when it runs, uses table TABLEA. After PROGRAMA starts executing, a database administrator adds a new column to TABLEA using the ALTER TABLE statement (TABLEA is not locked by PROGRAMA). The execution plans in PROGRAMA that were generated from the old TABLEA definition during explicit SQL compilation time are no longer valid. When the first SQL statement that uses TABLEA executes, the SQL executor opens TABLEA and checks the timestamp to ensure that PROGRAMA has a valid definition for TABLEA. The SQL executor compares the TABLEA timestamp with the PROGRAMA timestamp. The TABLEA timestamp is more recent than the PROGRAMA timestamp. The SQL executor invokes the SQL compiler to recompile the statement using the current TABLEA definition. Recompilation does not modify PROGRAMA on disk or record dependencies in the catalog; it only changes the copy of PROGRAMA in memory. 5-26

Program Compilation and Execution Understanding the Run-Time Timestamp Check If TABLEA is open when you execute the ALTER TABLE statement, the system closes the table. The next time the SQL statement is executed, the SQL executor reopens TABLEA, which forces the timestamp check and the statement to be recompiled. Figure 5-7 shows this run-time object definition check. Figure 5-7. Run-Time Checks and Automatic SQL Recompilation SELECT... SQL Object Code... FROM tablea... Timestamp programa SQL Executor SQL Object Code (copy)... SELECT... FROM tablea... Automatic SQL Recompilation Rewrites Area Timestamp programa Catalog Timestamp programa VST0507.vsd 5-27

Program Compilation and Execution Understanding Run-Time Recompilation Errors Understanding Run-Time Recompilation Errors For automatic SQL recompilation of an entire program at run time, the SQL executor returns compilation errors or warnings as follows: If an SQL statement causes an error or warning, the statement remains uncompiled in the program file and the SQL executor suppresses the error or warning message. If the SQL executor subsequently tries to execute the uncompiled statement, the SQL executor tries again to automatically recompile the statement. If the statement still causes a compilation error or warning, the SQL executor returns a run-time error message to the program. At run time, a program receives SQL compiler errors only when the SQL statement that produces the error executes. Maximizing Local Autonomy Local autonomy in a network-distributed database ensures that a program can access data on the local system, regardless of the availability of remote SQL objects. If your program accesses a network-distributed database, you can maximize local autonomy by: Using a local partition, rather than the primary partition, as the table name for partitioned tables Using TACL DEFINEs Using current statistics Skipping unavailable partitions For more information about managing applications for local autonomy, see the SQL/MP Installation and Management Manual. Using a Local Partition If your program uses a remote partition, the SQL compiler looks for information about the table in a remote catalog. If the remote system is down, the SQL compilation fails. However, if your program uses a local partition, the SQL compiler looks for the information in a local catalog. Provided the local system and data are available, the SQL compilation is successful. 5-28

Program Compilation and Execution Using TACL DEFINEs This example shows the concept of maximizing local autonomy. The parts table is a partitioned table that resides on the \NEWYORK and \CHICAGO systems: \NEWYORK The first partition contains all rows in which PARTS.PARTNUM (the primary key) is less than 5000. \CHICAGO The second partition contains all rows in which PARTS.PARTNUM is 5000 or greater. An index on the PARTDESC column of table PARTS is named IXPART. A program declares a cursor defined as: EXEC SQL DECLARE get_part_cursor CURSOR FOR SELECT partnum, partdesc, price, qty_available FROM =parts WHERE parts.partnum < 5000 AND parts.partdesc = "V8 DISK OPTION"; The program running on \NEWYORK uses a TACL DEFINE named =PARTS to associate the parts table with the first partition located at \NEWYORK: SET DEFINE CLASS MAP ADD DEFINE =parts, FILE \newyork.$vol1.sales.parts If \CHICAGO is unavailable at compile time, the SQL compiler can still compile the program because enough information is available in the catalogs on \NEWYORK where the first partition is registered. Assume that the compiler uses the index on \CHICAGO in the optimized execution plan. If \CHICAGO is still unavailable at run time, the SQL executor invokes the SQL compiler to automatically recompile the statement. The SQL compiler determines an execution plan that does not use the index IXPART but will sequentially scan the rows in the first partition to find all parts that have V8 DISK OPTION in the PARTDESC column. Using TACL DEFINEs By using TACL DEFINEs in a program to refer to tables and associating those TACL DEFINEs with local partitions, you increase the possibilities for successful compilations of programs that access a distributed database. All SQL compilations are affected, including explicit and dynamic compilations and automatic recompilations. Using Current Statistics For a partitioned table to have local autonomy, the UPDATE STATISTICS statement must be executed on the table at least once. If the SQL catalog in which a table is registered does not have any statistics for the table, the SQL optimizer does a catalog look-up operation for each partition of the table to estimate the aggregate number of nonempty blocks and records. Also, if the statistics for an unavailable partitioned table have not been updated, you will receive an SQL warning and file-system error even if your query does not try to retrieve any rows from the unavailable partition. Executing the UPDATE STATISTICS statement eliminates both of these problems. 5-29

Program Compilation and Execution Skipping Unavailable Partitions Skipping Unavailable Partitions Use the SKIP UNAVAILABLE PARTITION option of the CONTROL TABLE directive to cause NonStop SQL to skip a partition that is not available and to open the next available partition that satisfies the search condition of a query. (NonStop SQL also returns a warning message (8239) to the SQLCA.) The SKIP UNAVAILABLE PARTITION option applies to static or dynamic SQL statements that refer to partitioned tables and partitioned indexes of the tables. Executing an SQL Program File You execute an SQL program file as you would any program file by using the TACL RUN (or RUND) command or a process-creation system procedure such as NEWPROCESS. This subsection describes how to execute a program file from your TACL process; for information about executing a program file using a system procedure, see the Guardian Procedure Calls Reference Manual. Before running the program file, you can specify TACL DEFINE, PARAM, and ASSIGN commands for run-time parameters and control. For more information about these commands, see the TACL Reference Manual. NonStop SQL returns any run-time errors and warnings to the SQLCODE variable and the SQL communications area (SQLCA) if it is declared. For information about error processing, see Section 6, Error and Status Processing. For a list of errors and warnings, see the SQL/MP Messages Manual. For an SQL program file to execute, the file must be: Validated by the SQL compiler for execution Recorded in a PROGRAMS catalog table To execute an SQL program file, you (or your application process if you use a processcreation system procedure) must have access authority as follows: Read and execute authority to the program file Read authority to the catalog in which the program is registered Read authority to any catalog in which tables or views used by the program are registered for SQL statements requiring automatic recompilation Using the RUN Command To execute an SQL program file from your TACL process, use the TACL RUN command. You can enter a RUN command either explicitly or implicitly. For an explicit RUN command, enter the keyword RUN (or RUND) followed by the program file. For 5-30

Program Compilation and Execution Using TACL DEFINEs an implicit RUN command, enter only the name of the program file. The syntax for the RUN command is: [ RUN[D] ] program-file [ / run-option [, run-option ]... / ] [ param-set ] RUN RUND executes the program file without debugging. executes the program file and initiates debugging under the control of INSPECT or DEBUG. program-file is the name of the SQL program object file. run-option is a run option of the RUN command, as described in the TACL Reference Manual. param-set is a list of one or more parameters to pass to the program, with each parameter separated by a space, as described in the TACL Reference Manual. Using TACL DEFINEs A DEFINE is a named set of attributes and associated values stored in the process file segment (PFS) of a process. TACL DEFINEs allow you to specify information about a process before you run the process. You specify this information by entering TACL DEFINE commands at your TACL or SQLCI prompt, or by calling Guardian system procedure calls (or a by a combination of both command and procedure calls). With NonStop SQL, you can use TACL DEFINE names in your program to specify the names of catalogs, tables, views, indexes, partitions, and other programs. If you use TACL DEFINE names in SQL statements to refer to the above SQL objects, follow the guidelines listed below. For more information about using TACL DEFINEs with NonStop SQL, see the SQL/MP Reference Manual. TAL Compilation For TAL compilation, set TACL DEFINEs for any DEFINE names of tables or views you use in INVOKE directives. 5-31

Program Compilation and Execution Estimating Program Size SQL Compilation statements. The SQL compiler registers programs in a catalog. If you are SQL compiling an object file, you might want to use a DEFINE to specify the catalog. For explicitly recompiling a program, you can specify the DEFINE set stored in the program file by using the SQLCOMP command STOREDDEFINES option. If you specify a DEFINE name in an SQL statement that is not present in your current set of DEFINEs, the SQL compiler issues a warning message and leaves the statement uncompiled in the object file. When you run your program, NonStop SQL tries again to compile the SQL statement using automatic recompilation. If the SQL compiler fails to find the DEFINE name this time, it issues an error message. Program Execution For program execution, set TACL DEFINEs for all DEFINE names used in SQL statements if the current DEFINE set is not the same set used for SQL compilation. If the current DEFINE set is different, the program is subject to automatic recompilation as described on page 5-24. Before issuing the RUN command, you can specify TACL DEFINE commands that apply to SQL statements in the program. You can create, modify, delete, and display DEFINEs with TACL commands or Guardian system procedure calls. You can also specify the =_SORT_DEFAULTS DEFINE to control sort operations. However, if you modify a DEFINE after SQL load time, the change has no effect on static SQL statements. To determine the DEFINE set with which a program was compiled, use the EXPLAIN DEFINES option of the SQLCOMP command. When the process begins execution, it receives your current set of DEFINE values from the process file segment (PFS) of your TACL process, provided the DEFMODE option is ON. If DEFMODE is OFF, TACL propagates only your =_DEFAULTS DEFINE to the new process. Estimating Program Size A program that uses embedded SQL statements and directives to access a NonStop SQL database uses much more memory than a program that accesses an Enscribe database. This subsection describes how to estimate the virtual memory used by embedded SQL statements and directives in a program s extended data segment. Some statements require no extra extended memory, but other statements generate a run-time call to the SQL executor and do use extra memory. The SQL executor uses extended memory to run and the memory shown below for parameters and data structures. 5-32

Program Compilation and Execution Estimating Program Size These structures are shared by all SQL statements and directives in a program: Bytes Structure Description 430 SQLCA Count once if you specify INCLUDE SQLCA 838 SQLSA Count once if you specify INCLUDE SQLSA Use this table to estimate the number of bytes used by each embedded SQL statement and directive in the extended data segment. Table 5-1. Calculating Virtual Memory Requirements for Each SQL Statement or Directive Bytes Required Description of SQL Statement 72 Base value for a statement with no host variables + 4 + (24 * number of input host Required for a statement with input host variables variables) + 4 + (24 * number of output host Required for a statement with output host variables variables) + 146 Required for a static SQL statement that uses a cursor declared in the global area of the program Follow these guidelines when you use this table: Count a host variable once per occurrence. Count only these SQL statements and directives (which generate a run-time call to the SQL executor): ALTER DROP LOCK TABLE BEGIN WORK END WORK OPEN CLOSE EXECUTE RELEASE COMMENT EXECUTE IMMEDIATE ROLLBACK WORK CREATE FETCH SELECT DELETE FREE RESOURCES UNLOCK TABLE DESCRIBE HELP TEXT UPDATE DESCRIBE INPUT INSERT UPDATE STATISTICS Do not count: BEGIN DECLARE SECTION and END DECLARE SECTION CONTROL EXECUTOR, CONTROL QUERY, and CONTROL TABLE DECLARE CURSOR INVOKE WHENEVER 5-33

Program Compilation and Execution Estimating Program Size Caution. The system allocates real memory in 2 KB pages. If an SQL statement uses only part of a page, the system allocates the entire page. Therefore, the real memory used by embedded SQL statements can be larger than the figures shown in Table 5-1 on page 5-33. A program can encounter memory problems in these cases: It contains a large number of embedded SQL statements. It runs on a system with limited memory (for example, 16 MB or less). It runs in a processor that is also running a large number of other programs. To reduce the memory use in the extended data segment, follow these guidelines: Declare only the host variables that your program actually requires. Declare all host variables in one Declare Section if possible. The system allocates the host variables contiguously in one or more pages, rather than allocating each host variable in a separate page. Execute SQL statements in listing order as often as possible. Thus, the SQL statements can share many of the pages in the extended data segment. As a last measure, use dynamic SQL statements. Using dynamic SQL statements can reduce memory use; however, it also can degrade a program s performance because of the additional SQL run-time compilations. 5-34

6 Error and Status Processing NonStop SQL returns error and status information to an application program following the execution of each embedded SQL statement. NonStop SQL returns some information to the integer SQLCODE variable and more extensive information to these data structures: SQL communications area (SQLCA). The SQLCA contains run-time information including errors and warnings generated by the most recently executed dynamic or static SQL statement. SQL descriptor area (SQLDA). The SQLDA contains information about input parameters and output variables in dynamic SQL statements. SQL statistics area (SQLSA). The SQLSA contains statistics and performance information after the execution of DML and some dynamic SQL statements. This section describes how to check the SQLCODE variable and the SQL data structures to get information about: Errors and warnings after the execution of SQL statements Performance and statistics after the execution of SQL statements Dynamic SQL operations Getting Error and Warning Information NonStop SQL provides these methods you can use to check for and process errors and warnings in your program: Checking the value of the SQLCODE variable Using the WHENEVER directive Checking information in the SQLCA Using the SQLCODE Variable NonStop SQL returns status to the SQLCODE variable after the execution of each embedded SQL statement. The SQLCODE variable can have these values: Value Status < 0 Error > 0 Warning 0 Successful Each NonStop SQL message has an assigned code number that is returned to SQLCODE. For the values for SQLCODE and their meanings, see the SQL/MP Messages Manual. 6-1

Error and Status Processing Using the SQLCODE Variable Declaring the SQLCODE Variable Declare SQLCODE in your program as an integer variable: INT SQLCODE; If you omit the SQLCODE declaration, the compiler generates an undeclared identifier error. The SQLCODE variable must be declared within scope of the embedded SQL statement that you will execute. To ensure SQLCODE is always in this scope, declare SQLCODE as a global variable at the start of each module that contains embedded SQL statements. Checking the SQLCODE Variable Figure 6-1 shows an example that inserts two column values into the PARTS table and checks for errors using the SQLCODE variable. 6-2

Error and Status Processing Using the SQLCODE Variable Figure 6-1. Checking the SQLCODE Variable! Variable declarations EXEC SQL BEGIN DECLARE SECTION; STRUCT.in^parts^rec; BEGIN INT in^partnum; FIXED(2) in^price; STRING in^partdesc[0:17]; END; EXEC SQL END DECLARE SECTION; EXEC SQL INCLUDE SQLCA;! Include the SQLCA structure!! for detailed error information! INT SQLCODE;! Include the SQLCODE variable!! for simple error checking!... PROC driver MAIN; BEGIN! Blank fill in^partdesc: in^parts^rec.in^partdesc ':=' [ $OCCURS(in^parts^rec.in^partdesc) * [" "] ] ;! Begin TMF transaction and check SQLCODE: EXEC SQL BEGIN WORK; IF SQLCODE < 0 THEN CALL handle^errors; IF SQLCODE > 0 AND SQLCODE <> 100 THEN CALL handle^warnings;! Do an SQL INSERT into the parts table: in^parts^rec.in^partnum := 4120; in^parts^rec.in^price := 60000.00; in^parts^rec.in^partdesc ':=' "V8 DISK OPTION"; EXEC SQL INSERT INTO sales.parts (partnum, price, partdesc) VALUES ( :in^parts^rec.in^partnum, :in^parts^rec.in^price, :in^parts^rec.in^partdesc);! Check SQLCODE for errors and warnings: IF SQLCODE < 0 THEN CALL handle^errors; IF SQLCODE > 0 AND SQLCODE <> 100 THEN CALL handle^warnings;! End TMF transaction and check SQLCODE: EXEC SQL COMMIT WORK; IF SQLCODE < 0 THEN CALL handle^errors; IF SQLCODE > 0 AND SQLCODE <> 100 THEN CALL handle^warnings; END; VST0601.vsd 6-3

Error and Status Processing Using the WHENEVER Directive Using the WHENEVER Directive The WHENEVER directive specifies an action that a program takes depending on the outcome of subsequent DML, DCL, and DDL SQL statements. WHENEVER provides tests for these conditions: An error occurred. A warning occurred. No rows were found. You can specify a WHENEVER directive anywhere in your program. When you specify this directive, the TAL compiler inserts statements that perform run-time checking after the SQL statement using the SQLCODE variable. Table 6-1 shows the TAL compiler pseudocode used to check SQLCODE and the order in which the checks are made. Table 6-1. TAL Compiler Pseudocode for Checking SQLCODE Order Condition Compiler Pseudocode 1 NOT FOUND IF SQLCODE = 100 THEN action-specification ; 2 SQLERROR IF SQLCODE < 0 THEN action-specification ; 3 SQLWARNING IF SQLCODE > 0 AND SQLCODE <> 100 THEN action-specification ; action-specification is one of: CALL : procedure-name ; GOTO : label-name ; GO TO : label-name ; CONTINUE ; Each WHENEVER directive independently applies to the SQL statement. For example, specifying a WHENEVER SQLWARNING directive does not affect the checking for a WHENEVER SQLERROR or a WHENEVER NOT FOUND directive. Determining the Scope of a WHENEVER Directive The order that a WHENEVER directive appears in a program determines its scope. Some points to consider are: A WHENEVER directive is in effect until another WHENEVER directive for the same condition appears. If a WHENEVER directive is coded in a procedure, the directive remains in effect outside of the procedure even if the scope of the procedure is no longer valid. Therefore, if you do not want the directive to remain in effect, disable it at the end of the procedure as described in the next subsections. A program s order includes any files that are copied into the program using a SOURCE directive. If a copied file contains a WHENEVER directive, that directive is in effect following the SOURCE directive. 6-4

Error and Status Processing Using the WHENEVER Directive A WHENEVER directive does not affect SQL statements if they appear in the program before the WHENEVER directive. If you are debugging a program and you use a WHENEVER directive to call an error handling procedure, you might need to save the SQLCODE value in a local variable within the error handling procedure. Each subsequent SQL statement resets SQLCODE, and you might lose a value you need to debug your program. Enabling and Disabling the WHENEVER Directive You can enable and disable the WHENEVER directive for different parts of your program. For example, you might want to handle SQL errors by checking the SQLCODE variable after an SQL statement instead of using WHENEVER SQLERROR. This example shows how to enable and disable condition checking for the WHENEVER directive: EXEC SQL WHENEVER SQLERROR CALL :error^proc;! Enables checking... EXEC SQL WHENEVER SQLERROR;! Disables checking To avoid an infinite loop if the error handling code generates errors or warning, you can disable the WHENEVER directive within the error handling procedure. An infinite loop can occur when the: SQLERROR condition executes a statement that generates an error SQLWARNING condition executes a statement that generates a warning NOT FOUND condition executes a statement that generates a NOT FOUND condition To avoid these situations, disable the appropriate WHENEVER directive for the part of your program that handles each condition. Figure 6-2 shows an example that enables and disables the directive. 6-5

Error and Status Processing Using the WHENEVER Directive Figure 6-2. Enabling and Disabling the WHENEVER Directive EXEC SQL WHENEVER SQLERROR CALL :error^handler; PROC proc^1(i, j, k); INT i; INT j; INT k; BEGIN EXEC SQL SELECT...; EXEC SQL SELECT...; EXEC SQL SELECT...; END; PROC proc^2(i, j, k); INT i; INT j; INT k; BEGIN EXEC SQL SELECT...; EXEC SQL SELECT...; EXEC SQL SELECT...; END;! Reset SQLERROR checking while in error handler: EXEC SQL WHENEVER SQLERROR; PROC error^handler; BEGIN CALL SQLCADISPLAY(sqlca); CALL ABEND; END;! Reenable SQLERROR checking after error^handler: EXEC SQL WHENEVER SQLERROR CALL :error^handler; PROC driver MAIN; INT a; INT b; INT c; BEGIN CALL proc^1(a, b, c); CALL proc^2(c, b, a); EXEC SQL INSERT...; END; VST0602.vsd 6-6

Error and Status Processing Using the WHENEVER Directive Using the CALL Format If you use the CALL format of WHENEVER to call an error handling procedure, follow these guidelines: Specify the WHENEVER directive globally and precede the directive with a forward declaration of the error handling procedure(s). Declare the error handling procedure or subprocedure without parameters, and do not allow it to return a value. Ensure that the error handling procedure or subprocedure you call is accessible from each SQL statement affected by the WHENEVER directive. Using the GOTO Format If you use the GOTO (or GO TO) format, specify the WHENEVER directive at the beginning of the procedure containing the GOTO and disable it at the end of the procedure. For example: PROC error^proc; BEGIN EXEC SQL WHENEVER SQLERROR GOTO :error^handler; RETURN;... error^handler:...! error handling routine EXEC SQL WHENEVER SQLERROR;! Disable WHENEVER END;! End of error^proc Using an Aggregate Function All aggregate functions except COUNT return a null value when operating on an empty set. If a host variable receives the null value as the result of an aggregate function, you must specify an indicator variable and test the result of the indicator variable. Otherwise, NonStop SQL returns a no indicator variable provided condition instead of a no rows found condition. A WHENEVER NOT FOUND directive does not detect this condition. Example of Using WHENEVER Directives This example inserts two column values into the PARTS table and checks for errors using WHENEVER directives. The WHENEVER SQLWARNING and WHENEVER SQLERROR directives refer to parts of the program that handle the respective condition. 6-7

Error and Status Processing Using the WHENEVER Directive Figure 6-3. Using WHENEVER Directives! Variable declarations: EXEC SQL BEGIN DECLARE SECTION; STRUCT.in^parts^rec; BEGIN INT in^partnum; FIXED(2) in^price; STRING in^partdesc[0:17]; END; EXEC SQL END DECLARE SECTION;! Include the SQLCA for detailed error information: EXEC SQL INCLUDE SQLCA;! Include SQLCODE for simple error checking: INT SQLCODE;! Forward declare error handling code: PROC handle^warnings; FORWARD; PROC handle^errors; FORWARD;! Specify WHENEVERs globally, for errors and warnings: EXEC SQL WHENEVER SQLWARNING CALL :handle^warnings; EXEC SQL WHENEVER SQLERROR CALL :handle^errors; PROC DRIVER MAIN; BEGIN! Blank fill in^partdesc: in^parts^rec.in^partdesc ':=' [ $OCCURS(in^parts^rec.in^partdesc) * [" "] ] ;! Begin the TMF transaction: EXEC SQL BEGIN WORK; in^parts^rec.in^partnum := 4120; in^parts^rec.in^price := 60000.00; in^parts^rec.in^partdesc ':=' "V8 DISK OPTION";! Execute an SQL INSERT into the parts table: EXEC SQL INSERT INTO =parts (partnum, price, partdesc) VALUES ( :in^parts^rec.in^partnum, :in^parts^rec.in^price, :in^parts^rec.in^partdesc);! End the TMF transaction: EXEC SQL COMMIT WORK; END; VST0603.vsd 6-8

Error and Status Processing Getting Information From the SQLCA Getting Information From the SQLCA NonStop SQL returns run-time information, including errors and warnings, for the most recently executed SQL statement to the SQL communication area (SQLCA). The SQLCA is the primary status checking area for application programs because it contains more detailed information than the SQLCODE variable. The compiler initializes the SQLCA before each executable SQL statement. Declaring the SQLCA Structure Use the INCLUDE SQLCA directive to declare the SQLCA in the variable declarations part of your TAL program. If the SQLCA must always be accessible to all parts of your program, include the INCLUDE SQLCA directive with your global variable declarations. The syntax is: INCLUDE SQLCA An example of the INCLUDE SQLCA directive is:! Global declarations: EXEC SQL INCLUDE SQLCA;... Using System Procedures With the SQLCA Structure Table 6-2 shows SQL system procedures you can use to retrieve and display information from the SQLCA structure. Table 6-2. System Procedures for the SQLCA Structure System Procedure SQLCADISPLAY SQLCAGETINFOLIST SQLCATOBUFFER SQLCAFSCODE Description Writes to a file or to a terminal the error or warning messages returned to the program by SQL Writes to a record area in the program a subset (which you specify) of the error or warning information in the SQLCA Writes to a record area in the program the error or warning messages returned to the program by SQL Returns information about file-system, disk-process, or NonStop Kernel operating system errors To include declarations for these procedures in your program, use the SOURCE directive for the EXTDECS file. Figure 6-4 shows an example that calls the SQLCADISPLAY procedure. 6-9

Error and Status Processing Getting Performance and Statistics Information Figure 6-4. Calling an SQL System Procedure?SOURCE $system.system.extdecs (SQLCADISPLAY,? SQLCAFSCODE,? SQLCAGETINFOLIST,?! Global declarations: EXEC SQL INCLUDE SQLCA;... SQLCATOBUFFER)! Error handling routine:...... CALL SQLCADISPLAY (SQLCA); VST0604.vsd If your program uses the NUMOUT procedure to display an error message, you must remove the negative sign before displaying the error number. To avoid this situation, use the INCLUDE SQLCA directive and then call the SQLCADISPLAY procedure to display the error message. For more information about SQL system procedures, see Section 4, System Procedures Getting Performance and Statistics Information NonStop SQL uses the SQL statistics area (SQLSA) to communicate statistics to a TAL program. NonStop SQL returns a new set of statistics in the SQLSA following the execution of these statements: The OPEN, FETCH, SELECT, INSERT, UPDATE, and DELETE statements A PREPARE statement that describes input parameters and output columns associated with a dynamic SQL statement that was prepared Use the INCLUDE SQLSA directive to declare the SQLSA in your program. The syntax is: INCLUDE SQLSA Place the INCLUDE SQLSA directive in your program with: Global declarations to use the SQLSA throughout your program Local declarations to use the SQLSA for special purposes (for example, one SQLSA for PREPARE statements and another SQLSA for DML statements) 6-10

Error and Status Processing Getting Performance and Statistics Information Figure 6-5 shows the SQLSA structure generated in a TAL program by the INCLUDE SQLSA directive. NonStop SQL generates this structure and inserts it in the program following the INCLUDE SQLSA directive. Figure 6-5. SQLSA Structure Description STRUCT.sqlsa; BEGIN STRING eye^catcher[0:1]; INT version; STRUCT dml; BEGIN INT num^tables; STRUCT stats[0:15]; BEGIN STRING table^name[0:23]; INT(32) records^accessed; INT(32) records^used; INT(32) disc^reads; INT(32) messages; INT(32) message^bytes; INT waits; INT escalations; STRING sqlsa^reserved[0:3]; END; -- stats END; -- dml STRUCT prepare = dml; BEGIN INT input^num; INT input^names^len; INT output^num; INT output^names^len; INT name^map^len; INT sql^statement^type; END; -- prepare VST0605.vsd END; -- sqlsa Table 6-3 describes the fields in the SQLSA data structure. Table 6-3. SQLSA Fields (page1of3) Field Name EYE^CATCHER VERSION DML Description Identification field, set by the system to SA. Current version of the SQLSA; subsequent NonStop SQL software releases can change this version ID. Structure where statistics on DML statement execution are returned. 6-11

Error and Status Processing Getting Performance and Statistics Information Table 6-3. SQLSA Fields (page2of3) Field Name NUM^TABLES STATS TABLE^NAME RECORDS^ACCESSED RECORDS^USED DISC^READS MESSAGES MESSAGE^BYTES WAITS ESCALATIONS SQLSA^RESERVED PREPARE INOUT^NUM INPUT^NAMES^LENGTH Description Number of tables accessed by a DML statement. Maximum is 16. Array containing NUM^TABLES valid entries, one for each table accessed. Guardian internal file name of the table accessed. Number of records accessed in the corresponding table. Number of records altered or returned. Number of disk reads and writes. Number of messages sent to the disk process. Number of bytes sent in all the messages sent to the disk process. Number of lock waits or timeouts. Number of times record locks are escalated to file locks. Reserved Structure to which statistics on a PREPARE statement are returned. This structure applies only for dynamic SQL. The information provided is used by your program to allocate the buffers required to describe the prepared statement. Number of input parameters in the prepared statement. Length of the buffer required to contain names of input parameters. 6-12

Error and Status Processing Getting Information About Dynamic SQL Operations Table 6-3. SQLSA Fields (page3of3) Field Name OUTPUT^NUM OUTPUT^NAMES^LENGTH NAME^MAP^USE Description Number of output variables in the prepared statement. Output variables are SELECT columns or LASTSYSKEY on INSERT RETURNING. Length of buffer required to contain names of output variables. Reserved for system use SQL^STATEMENT^TYPE Type of statement being prepared. This literal declarations represent the values for this field: _SQL_STATEMENT_SELECT Cursor SELECT _SQL_STATEMENT_INSERT Insert _SQL_STATEMENT_UPDATE Update _SQL_STATEMENT_DELETE Delete _SQL_STATEMENT_DDL DDL statement _SQL_STATEMENT_CONTROL Run-time CONTROL TABLE _SQL_STATEMENT_DCL Lock, unlock, or FREE RESOURCES To use these declarations, include the TALDECS file in your program with a SOURCE directive:?source $ vol. subvol.taldecs Getting Information About Dynamic SQL Operations NonStop SQL uses the SQL descriptor area (SQLDA) to provide information about input parameters and output variables in dynamic SQL statements. The SQLDA also provides pointers to data buffers that your program uses to set values for input parameters and to receive values for output variables. The names buffer, which you can generate with the SQLDA or declare separately, receives the names of the input parameters or output variables. You can use the SQLDA data structure in: A DESCRIBE INPUT statement to get information about input parameters A DESCRIBE statement to get information about output columns The USING DESCRIPTOR clause of a FETCH statement to fill a cursor with rows from an SQL table The USING DESCRIPTOR clause of an EXECUTE statement to execute an dynamic SQL statement 6-13

Error and Status Processing Declaring the SQLDA and Names Buffer Declaring the SQLDA and Names Buffer Use the INCLUDE SQLDA directive to declare a structure template for the SQLDA in a TAL program using dynamic SQL statements. The syntax is: INCLUDE SQLDA ( sqlda-name [, sqlvar-count ] [, names-buffer-name, name-string-size ] [, { RELEASE1 RELEASE2 } ]) sqlda-name is the SQLDA structure name. sqlvar-count is the number of parameters for which you expect to specify input values or number of columns for which you expect to receive output values. The default is 1. names-buffer-name is the SQLDA names buffer name-string-size is the number of characters in the longest parameter or column name expected in the DESCRIBE or DESCRIBE INPUT statement. A qualified column name can be from 1 to 30 characters long and is in the format: table-name.column-name A parameter name is an SQL identifier with a maximum of 30 characters. RELEASE1 or RELEASE2 is the NonStop SQL release. The default is the release of the TAL compiler, unless it is overridden by the release option parameter in the SQL directive. Follow these guidelines when you use INCLUDE SQLDA: Supply a place-holder value for the parameters or columns and the length of the names buffer. Then allocate memory as needed. Indicator variable names appear in the names buffer. If the names are short, the INCLUDE SQLDA directive generates sufficient space for them; however, if the names are long and you use many indicator variables, you should explicitly allocate the names buffer separately from the INCLUDE SQLDA statement. 6-14

Error and Status Processing Declaring the SQLDA and Names Buffer Figure 6-6 and Figure 6-7 on page 6-16 show structure templates generated by the INCLUDE SQLDA directive for NonStop SQL Release 1 and Release 2. Figure 6-6. Release C30 SQLDA Template and Names Buffer LITERAL SQLDA^EYE^CATCHER = "D1"; STRUCT sqlda-name (*) ; BEGIN END; STRING eye^catcher[0:1]; INT num^entries; STRUCT sqlvar[0: sqlvar-count - 1]; BEGIN INT data^type; INT data^len;! fields for NUMBERS:! scale = data^len.<0:7>! length = data^len.<8:15>! fields for DATETIME or INTERVAL:! qualifier = data^len.<0:7>! length = data^len.<8:15> INT precision;! fields for DATETIME or INTERVAL:! leading field precision = precision.<0:7>! fraction precision = precision.<8:15> INT null^info; INT(32) var^ptr; INT(32) ind^ptr; FIXED reserved; END; STRING. names-buffer-name[ 0 : length - 1 ]; VST0606.vsd 6-15

Error and Status Processing Declaring the SQLDA and Names Buffer Figure 6-7. Release C10 SQLDA Template and Names Buffer LITERAL SQLDA^EYE^CATCHER^R1 = "DA"; STRUCT sqlda-name (*) ; BEGIN STRING eye^catcher[0:1]; END; INT num^entries; STRUCT sqlvar[0: sqlvar-count - 1 ]; BEGIN INT data^type; INT data^len;! fields for NUMBERS:! scale = data^len.<0:7>! length = data^len.<8:15> INT null^info; INT(32) var^ptr; INT(32) reserved; END; STRING. names-buffer-name[ 0 : length - 1 ]; VST0607.vsd The SQL compiler determines length in bytes for the names buffer using this formula: length = ( name-string-size + 11 ) * sqlvar-count The compiler derives the 11 bytes added to the name-string-size from the: length field 2 bytes table name 8 bytes separator ( ) 1 byte Table 6-4 describes each field in the SQLDA. 6-16

Error and Status Processing Declaring the SQLDA and Names Buffer Table 6-4. SQLDA Fields (page 1 of 2) Field Name SQLDA^EYE^CATCHER EYE^CATCHER NUM^ENTRIES SQLVAR DATA^TYPE DATA^LEN PRECISION * Description A constant declared by the system. If you requested an SQLDA structure of a release that is different from the release of the SQL compiler, SQLDA^EYE^CATCHER appears as either SQLDA^EYE^CATCHER^R1 or SQLDA^EYE^CATCHER^R2. Identifying field that your program must initialize with the system-declared SQLDA^EYE^CATCHER literal. NonStop SQL statements do not return values to EYE^CATCHER. Number of input parameters or output variables this SQLDA structure can accommodate. If your program used INCLUDE SQLDA, TAL sets NUM^ENTRIES to the number you specified for sqlvar^count. If your program allocated the SQLDA dynamically, the program must supply a value for NUM^ENTRIES. Descriptions for input parameters or output variables. The DESCRIBE INPUT and DESCRIBE statement returns one SQLVAR entry for each input parameter or each output variable. Data type of the parameter or output variable. The length in DATA^LEN depends on the data type as follows: For a fixed-length character string, DATA^LEN contains the number of characters in the string. For a variable-length character string, DATA^LEN contains the maximum number of characters allowed in the string (not including the two bytes of length). For both binary and decimal numeric items, DATA^LEN bits 0:7 contain the decimal scale of the item. For a binary numeric item, DATA^LEN bits 8:15 contain the byte length of the item (2, 4, or 8). For a decimal numeric item, DATA^LEN bits 8:15 contain the byte length of the item (the number of characters). For a DATETIME or INTERVAL item, DATA^LEN bits 0:7 contain a code for the range of DATETIME fields. Bits 8:15 contain the storage size for the item. PRECISION depends on the data type as follows: For a FLOAT or binary numeric column, PRECISION contains the numeric precision. For a date-time or INTERVAL item, PRECISION bits 0:7 contain the leading field precision. Bits 8:15 contain the fraction precision. If the FRACTION field is not included, bits 8:15 are 0. 6-17

Error and Status Processing Initializing the EYE^CATCHER Field Table 6-4. SQLDA Fields (page 2 of 2) Field Name NULL^INFO * VAR^PTR IND^PTR * Description Initializing the EYE^CATCHER Field To initialize the EYE^CATCHER field in the SQLDA, use the SQLDA^EYE^CATCHER literal declaration: sqlda^name.eye^catcher ':=' SQLDA^EYE^CATCHER; where sqlda^name is the SQLDA in your program. If you specify an SQLDA structure with a release that is different from the release of the SQL compiler, NonStop SQL appends an _R1 or _R2 to SQLDA_EYE_CATCHER declaration. For example, you are using NonStop SQL release C30 and you specify a C10 SQLDA structure, the flag ^R1 is appended to the SQLDA^EYE^CATCHER declaration (SQLDA^EYE^CATCHER^R1). Using Literal Declarations for the SQLDA Use the literal declarations in the TALDECS file as values in the SQLDA DATA^TYPE and PRECISION fields. To include these declarations in your program, use the SOURCE directive. For example:?source $ volume. subvol.taldecs For input parameters, NULL^INFO contains a negative integer if the parameter could contain a null value. For output columns, NULL^INFO contains a negative integer if the column could contain a null value. (To verify whether the parameter or column is really null, check for a negative value at the location shown in IND^PTR). VAR^PTR is the extended address of the actual data (the value of the input parameter or output column). The extended address is not returned by NonStop SQL; your program must initialize VAR^PTR to point to the input and output data buffers. IND^PTR is the extended address of a flag that indicates whether or not a parameter or column is actually null. If your program must process null values, initialize IND^PTR to a valid address. For input parameters, the program then sets the flag pointed to by IND^PTR to -1 if the parameter is null and 0 if the parameter is not null. For output columns, NonStop SQL initializes the flag pointed to by IND^PTR to -1 if the column is null and to 0 if the column is not null. If your program does not need to process null values, initialize IND^PTR to an invalid address. * This data item is generated only when you specify RELEASE2 in the INCLUDE SQLDA directive. Table 6-5 and Table 6-6 show the literal declarations in the TALDECS file. 6-18

Error and Status Processing Using Literal Declarations for the SQLDA Table 6-5. Literal Declarations for Character, Numeric, and Decimal Values Type of Data Value Literal Declaration Character Data ASCII (fixed-length string) 0 _SQLDT_ASCII_F ASCII (fixed-length string, upshifted) 1 _SQLDT_ASCII_F_UP ASCII (variable-length string) 64 _SQLDT_ASCII_V ASCII (variable-length string, upshifted) 65 _SQLDT_ASCII_V_UP Numeric Data 16-bit signed (signed SMALLINT) 130 _SQLDT_16BIT_S 16-bit unsigned (unsigned SMALLINT) 131 _SQLDT_16BIT_U 32-bit signed (signed INT) 132 _SQLDT_32BIT_S 32-bit unsigned (unsigned INT) 133 _SQLDT_32BIT_U 64-bit signed (signed LARGEINT) 134 _SQLDT_64BIT_S 32-bit floating point 140 _SQLDT_REAL 64-bit floating point 141 _SQLDT_DOUBLE Decimal Data Unsigned DECIMAL 150 _SQLDT_DEC_U DECIMAL, leading sign separate (not SQL type) 151 _SQLDT_DEC_LSS ASCII DECIMAL, leading sign embedded 152 _SQLDT_DEC_LSE DECIMAL, trailing sign separate (not SQL type) 153 _SQLDT_DEC_TSS DECIMAL, trailing sign embedded (not SQL type) 154 _SQLDT_DEC_TSE For a date-time or interval item, bits 0:7 of the DATA^LEN field in the SQLDA contain a code for the range of date-time fields. Table 6-6 shows the literal declarations defined to represent these codes. Table 6-6. Literal Declarations for Date-Time and INTERVAL Values (page 1 of 2) Type of Data Value Literal Declaration General DATETIME 192 _SQLDT_DATETIME Literal Declarations for Interval Data Types YEAR TO YEAR 195 _SQLDT_INT_Y_Y MONTH TO MONTH 196 _SQLDT_INT_MO_MO YEAR TO MONTH 197 _SQLDT_INT_Y_MO DAY TO DAY 198 _SQLDT_INT_D_D HOUR TO HOUR 199 _SQLDT_INT_H_H DAY TO HOUR 200 _SQLDT_INT_D_H MINUTE TO MINUTE 201 _SQLDT_INT_MI_MI HOUR TO MINUTE 202 _SQLDT_INT_H_MI 6-19

Error and Status Processing Using Literal Declarations for the SQLDA Table 6-6. Literal Declarations for Date-Time and INTERVAL Values (page 2 of 2) Type of Data Value Literal Declaration DAY TO MINUTE 203 _SQLDT_INT_D_MI SECOND TO SECOND 204 _SQLDT_INT_S_S MINUTE TO SECOND 205 _SQLDT_INT_MI_S HOUR TO SECOND 206 _SQLDT_INT_H_S DAY TO SECOND 207 _SQLDT_INT_D_S FRACTION TO FRACTION 208 _SQLDT_INT_F_F SECOND TO FRACTION 209 _SQLDT_INT_S_F SECOND TO FRACTION 209 _SQLDT_INT_S_F MINUTE TO FRACTION 210 _SQLDT_INT_MI_F HOUR TO FRACTION 211 _SQLDT_INT_H_F DAY TO FRACTION 212 _SQLDT_INT_D_F Table 6-7. Literal Declarations for Ranges of Date-Time Fields (page 1 of 2) Range of Fields Value Literal Declaration YEAR TO YEAR 1 _SQLDT_INT_QUAL_Y_Y MONTH TO MONTH 2 _SQLDT_INT_QUAL_MO_MO DAY TO DAY 3 _SQLDT_INT_QUAL_D_D HOUR TO HOUR 4 _SQLDT_INT_QUAL_H_H MINUTE TO MINUTE 5 _SQLDT_INT_QUAL_MI_MI SECOND TO SECOND 6 _SQLDT_INT_QUAL_S_S FRACTION TO FRACTION 7 _SQLDT_INT_QUAL_F_F YEAR TO MONTH 8 _SQLDT_INT_QUAL_Y_MO YEAR TO DAY 9 _SQLDT_INT_QUAL_Y_D YEAR TO HOUR 10 _SQLDT_INT_QUAL_Y_H YEAR TO MINUTE 11 _SQLDT_INT_QUAL_Y_MI YEAR TO SECOND 12 _SQLDT_INT_QUAL_Y_S YEAR TO FRACTION 13 _SQLDT_INT_QUAL_Y_F MONTH TO DAY 14 _SQLDT_INT_QUAL_MO_D MONTH TO HOUR 15 _SQLDT_INT_QUAL_MO_H MONTH TO MINUTE 16 _SQLDT_INT_QUAL_MO_MI MONTH TO SECOND 17 _SQLDT_INT_QUAL_MO_S MONTH TO FRACTION 18 _SQLDT_INT_QUAL_MO_F DAY TO HOUR 19 _SQLDT_INT_QUAL_D_H DAY TO MINUTE 20 _SQLDT_INT_QUAL_D_MI 6-20

Error and Status Processing Example of Using the SQLDA Table 6-7. Literal Declarations for Ranges of Date-Time Fields (page 2 of 2) Range of Fields Value Literal Declaration DAY TO SECOND 21 _SQLDT_INT_QUAL_D_S DAY TO FRACTION 22 _SQLDT_INT_QUAL_D_F HOUR TO MINUTE 23 _SQLDT_INT_QUAL_H_MI HOUR TO SECOND 24 _SQLDT_INT_QUAL_H_S HOUR TO FRACTION 25 _SQLDT_INT_QUAL_H_F SECOND TO SECOND 26 _SQLDT_INT_QUAL_S_S SECOND TO FRACTION 27 _SQLDT_INT_QUAL_S_F FRACTION TO FRACTION 28 _SQLDT_INT_QUAL_F_F Example of Using the SQLDA Assume you declare an SQLDA structure named SQLDAX and a names buffer named NAMEBUF for allocation during compilation. The SQLDA structures must reserve space for the 20 columns you plan to use in dynamic SQL statements. The names buffer must reserve space for column names with a maximum length of 30 characters. You code the INCLUDE SQLDA directive as: EXEC SQL INCLUDE SQLDA ( sqldax, 20, namebuf, 30 );... Figure 6-8 shows the SQLDA structure template generated by the TAL compiler. 6-21

Error and Status Processing Example of Using the SQLDA Figure 6-8. SQLDA Structure Template LITERAL SQLDA^EYE^CATCHER = "D1"; STRUCT SQLDAX (*); BEGIN STRING eye^catcher[0:1]; INT num^entries; STRUCT sqlvar[0:19]; BEGIN INT data^type; INT data^len;! fields for NUMBERS:! scale = data^len.<0:7>! length = data^len.<8:15>! fields for DATETIME or INTERVAL:! qualifier = data^len.<0:7>! length = data^len.<8:15> INT precision;! fields for DATETIME or INTERVAL:! leading field precision = precision.<0:7>! fraction precision = precision.<8:15> INT null^info; INT(32) var^ptr; INT(32) ind^ptr; FIXED reserved; END; END; STRING.namebuf [0:819]; VST0608.vsd The compiler determines the length (820 bytes) of the names buffer (NAMEBUF) from the parameters in the INCLUDE SQLDA directive using the formula under Declaring the SQLDA and Names Buffer on page 6-14. You then declare a structure for the output SQLDA: STRUCT.osqlda (sqldax);... 6-22

7 Dynamic NonStop SQL Operations Dynamic SQL operations allow a program to construct, compile, and execute an SQL statement that is unknown until the program is executing. This section describes concepts that are important for understanding how dynamic SQL operations work. A static SQL statement appears in the TAL source program at compile time. A program using static SQL statements receives input values from host variables and sends output values to host variables. A static SQL statement is: EXEC SQL INSERT INTO EMPLOYEE_TABLE VALUES ('BROWN',6400); In contrast, all or part of a dynamic SQL statement is input or generated, stored in a character host variable, compiled, and executed at run time. A program using dynamic SQL sends input values to SQL through SQL input parameters and receives output values from SQL through host variables or data buffers defined in the program. A dynamic SQL example is: User enters an INSERT statement Program reads INSERT statement into command buffer EXEC SQL PREPARE statement-name FROM : statement-buffer; EXEC SQL EXECUTE statement-name;! Insertion performed You can perform most of the same operations using dynamic SQL that you can perform with static SQL. You can use DDL, DML, and DCL statements in both modes; cursors work similar in both modes. After compilation, SQL executes the statements in the same way whether they are dynamic SQL statements or static SQL statements. With dynamic SQL, however, you must perform some operations, such as building descriptors for host variables, that the TAL compiler performs for you if you are using static SQL. For examples of TAL programs that use dynamic SQL operations, see Appendix C, Examples of Dynamic NonStop SQL Programs 7-1

Dynamic NonStop SQL Operations Determining Uses for Dynamic SQL Operations Determining Uses for Dynamic SQL Operations Programs that use dynamic SQL operations can be useful for a number of applications. For example: You can develop an interactive interface that is similar to SQLCI, but is designed for an inexperienced user. You want to switch between several copies of identical databases. For this application, you use a dynamic SQL program with run-time TACL DEFINEs. You want to restrict access to the data in a table. For example, the program might code an UPDATE statement for certain columns in a table, but allow the user to enter the selection criteria (WHERE clause) at run time. Your program must communicate with other software that communicates with the user. For example, an application exists on a personal computer, and the user wants to manipulate data in a NonStop SQL database on a host system. Your program cannot use SQLCI. The application allows the user to formulate an SQL statement on the personal computer and send it to a server process on the HP NonStop system over MULTILAN or some other communications protocol. Developing a Dynamic SQL Application A dynamic SQL application can accept statements directly from the user or through a screen interface like Pathway, or the program can build the statements with little or no user input. The application might process an entire SQL statement, or it might process only part of a statement (such as the WHERE clause) and explicitly code the rest of the statement in the program. A program that uses dynamic SQL to process input directly from a user can be similar to the NonStop SQL Conversational Interface (SQLCI), requiring the user to know SQL syntax to formulate a complete SQL statement. The statement can contain input parameters; if it does, the program can prompt the user for the parameter values. You can also write a program for direct user input so that the user does not have to know SQL syntax. In this case, the program prompts the user for the necessary values (or displays a screen for the user to enter the values) and then constructs the SQL statement by concatenating these values to known syntax elements. For example, a program can handle any CREATE TABLE statement by concatenating the string CREATE TABLE and punctuation (for example, commas, colons) to the table name, column names, data types, and options entered by a user and stored in local variables. The program user sees only a series of prompts, such as ENTER THE TABLE NAME, ENTER THE FIRST COLUMN NAME, and so forth. 7-2

Dynamic NonStop SQL Operations Writing a Dynamic SQL Pathway Server Writing a Dynamic SQL Pathway Server If you are writing a TAL server that interfaces with Pathway and uses dynamic SQL statements, follow these steps: 1. Use the TAL SOURCE directive to include the declarations in the EXTDECS file for the Guardian OPEN, READUPDATE, and REPLY system procedures:?source $SYSTEM.SYSTEM.EXTDECS (OPEN, READUPDATE, REPLY) Except for constructing the SQL statement, these tasks are not unique to servers using SQL. You perform these tasks in addition to the tasks you would perform for any dynamic SQL program: 2. Define storage for the messages to be received from the SCREEN COBOL requester. 3. Define a character string to contain the statement that the program will construct from the input. 4. Call the OPEN and READUPDATE procedures to read $RECEIVE. 5. Construct the SQL statement: Check values passed from the requester in the buffer to decide what the statement includes. As each value is read, concatenate the corresponding text to form the statement. For example, suppose the screen describes a personnel record. If any column does not have a value, the user can enter N. The request message you defined is named LIST^MSG. This code checks the EMPNUM field in LIST^MSG and, if required, concatenates the text empnum to the statement you are constructing: STRING.cmd [0:199]; STRING.cmd^end; cmd ':=' "SELECT " -> @cmd^end;... IF list^msg.empnum <> "N" THEN cmd^end ':=' "EMPNUM " -> @cmd^end; The statement now contains the string SELECT EMPNUM. You continue to construct the entire statement based on the values the user entered. 6. After the database request has been processed, construct the reply message. Instead of formatting and displaying the output values, you assign the values to the reply message. The first field in the reply message record must contain the reply code to communicate with the SCREEN COBOL requester. 7. Call REPLY to send the reply message to the requester (screen program). 7-3

Dynamic NonStop SQL Operations Specifying Input Parameters and Output Variables Restrictions for Record Layout If possible, avoid having any fields in your requester or server messages that are an odd number of bytes long. There are some subtle differences in the way SCREENÊCOBOL and TAL generate fields in records when fields contain an odd number of bytes. Therefore, take special care that the field layout in the TAL server matches the layout in the SCREEN COBOL requester. Therefore, to avoid problems, follow these guidelines: Use DDL to describe the request and reply messages and then use the TAL and COBOL85 forms of the structures derived from the DDL. In the SCREEN COBOL requester, avoid constructing messages by listing several data items in the SEND statement; instead, the requester should send a single structure to the server. Specifying Input Parameters and Output Variables A dynamic SQL statement can contain input parameters. Input parameters might denote criteria to be used in a WHERE clause, values to be inserted into the database, or values used to update or delete database records. Input parameters are specified in the statement as either a question mark (?) or a question mark plus a name (?VAL). An input parameter can appear in an SQL expression wherever a constant can appear. The program uses the DESCRIBE INPUT statement with an input SQLDA structure to get information about the input parameters and obtain pointers to the input values. NonStop SQL returns data to a program through output variables. Output variables are user-defined areas in the program. Output variables can be host variables or individual data buffers to which the program s output SQLDA structure points. Output variables usually contain columns returned from a SELECT statement. A program uses the DESCRIBE statement with an output SQLDA structure to get information about the output variables. This sequence shows a typical context for input parameters and output variables in dynamic SQL operations. If you know in advance which columns will be selected, you can use this sequence. HOSTVAR ':=' "SELECT empnum, salary FROM =employee WHERE SALARY >?sal";! input parameter?sal!.. dynamically compile the statement, use DESCRIBE INPUT! to get information about input parameters, prompt the! user and read in the value for?sal, declare and open! a cursor for the statement.... EXEC SQL FETCH cursor INTO :enum, :salary;! output variables! :enum and :dept 7-4

Dynamic NonStop SQL Operations Using the SQLDA and Names Buffer If you do not know in advance which columns to select, you can dynamically compile the statement, use DESCRIBE to find out which columns are being selected, and then allocate data buffers to receive the column values. The SQLDA structure contains pointers to the buffers. In this case, the FETCH statement would look like this: EXEC SQL FETCH cursor USING DESCRIPTOR : sqlda;! The SQLDA contains! pointers to output! data buffers Internally, SQL execution is the same for both options. Using the SQLDA and Names Buffer To allocate storage for information about input parameters and output variables in a dynamic SQL statement, the dynamic SQL program declares one or more instances of the SQLDA and names buffer. The SQLDA holds this information: The number of input parameters or output variables the SQLDA can accommodate in the NUM^ENTRIES field For each input parameter or output variable, an SQLVAR structure with this information: Field DATA^TYPE DATA^LEN PRECISION NULL^INFO VAR^PTR IND^PTR Description Data type (TAL data type literals are shown under Allocating Memory for the Values. on page 7-20) Length and scale or date-time qualifier Leading field precision for a date-time or INTERVAL item, or the numeric precision for a FLOAT or binary numeric item Indicator for whether the item can contain a null value Extended address of the input parameter or output variable Extended address of the associated indicator variable (if it exists) The DESCRIBE and DESCRIBE INPUT statements set the NULL^INFO field depending on whether the prepared SQL statement includes a null indicator and not whether the column actually allows a null value. To determine if a column allows a null value, check the NULLALLOWED column in the COLUMNS table for the catalog where the table is registered. When your program issues a DESCRIBE INPUT or DESCRIBE statement, the system supplies values for all the fields of the SQLDA except EYE^CATCHER, NUM^ENTRIES, VAR^PTR, and IND^PTR. Your program must initialize these SQLDA fields as described in these susbsections. 7-5

Dynamic NonStop SQL Operations Using the SQLDA and Names Buffer Before DESCRIBE INPUT or DESCRIBE: Set the EYE^CATCHER field to the literal SQLDA^EYE^CATCHER. Set NUM^ENTRIES to the number of SQLVAR entries allocated in the SQLDA (the number of input parameters or output columns expected). If you do not know this number in advance, you can get it from the INPUT^NUM or OUTPUT^NUM fields of the SQLSA after the PREPARE statement executes. After DESCRIBE INPUT or DESCRIBE: Set VAR^PTR to point to the input or output data buffers. Set IND^PTR to point to any indicator variables. If your program does not process null values, set IND^PTR to an invalid address such as the one shown in the detailed dynamic SQL program in Appendix C. In some cases, your program might change the contents of the DATA^TYPE, DATA^LEN, or PRECISION fields. Two cases are when the data type of the input parameter or output variable you declared is compatible with but not the same as the data type SQL uses, or when you want to manipulate the scale information in the first byte of the DATA^LEN field. For input parameter handling, the FETCH or EXECUTE operation usually references the same SQLDA structure used for DESCRIBE INPUT. Similarly, for output variable handling, the FETCH or EXECUTE operation references the same SQLDA structure used for DESCRIBE. If the program will execute a statement using input parameters, you declare an SQLDA to describe the input parameters. If the program will execute a dynamic SELECT statement or an INSERT statement with the RETURNING LASTSYSKEY option, you declare a second SQLDA to describe the output variables (SELECT columns or system-defined primary key). The names buffer stores the names of the input parameters (after DESCRIBE INPUT) or the names of selected columns (after DESCRIBE). For an expression, the names buffer contains a null string. If you will need to prompt the user for parameter values or display column names for output to the user, you should declare one or more names buffers. You can generate an SQLDA template and allocate a names buffer by entering the INCLUDE SQLDA directive. The generated SQLDA template has the format shown with INCLUDE SQLDA in Section 6, Error and Status Processing To process the SELECT statement SELECT EMPNUM, SALARY FROM =EMPLOYEE WHERE SALARY >?SAL 7-6

Dynamic NonStop SQL Operations Using Dynamic SQL Programming Techniques The program performs these tasks: Issues the PREPARE statement to dynamically compile the SELECT statement. Declares an input SQLDA and an output SQLDA. If needed, the program also declares corresponding input and output names buffers. Uses the DESCRIBE INPUT statement to retrieve the description for the input parameter?sal into an input SQLDA. The input SQLDA will need at least one SQLVAR entry for the parameter. Uses the DESCRIBE statement to retrieve the ENUM and SALARY descriptions for an output SQLDA. The output SQLDA will need at least two SQLVAR entries, one for each column. Sets the VAR^PTR fields in the SQLDAs to point to the input and output data buffers. Sets the IND^PTR fields to the addresses of any associated indicator variables or to a null address. Using Dynamic SQL Programming Techniques The simplest dynamic SQL program does not have any input parameters or output variables. This program processes statements such as CREATE TABLE or DROP INDEX, which do not require input parameters. A dynamic SQL program that executes a dynamic SELECT statement is more complex; it does not know the number of SELECT columns and input parameters until run time. This section describes programming techniques for dynamic SQL programs that include: Input parameters and output variables Run-time memory allocation This section shows several methods to use dynamic SQL statements; it does not show the most efficient or only method to develop a particular application. Appendix C, Examples of Dynamic NonStop SQL Programs provides program examples that use dynamic SQL operations. Overview of a Dynamic SQL Program The following paragraphs describe a dynamic SQL program that handles any SQL statement and allocates memory at run time. The examples use host variables to store the cursor name and statement name. Using host variables allows the program to dynamically compile multiple statements and have all the statements simultaneously available for execution. The names for functions, such as ALLOCATE^SQLDA, and variables, such as IMNAMESBUB^PTR, are arbitrarily chosen. 7-7

Dynamic NonStop SQL Operations Overview of a Dynamic SQL Program Setting Up the Environment 1. Use the DATAPAGES directive to cause the BINSERV process to allocate the maximum object program data pages (64) for SQL data structures and statement buffers:?datapages 64 2. Copy any required external declarations. Some of these declarations are shown below; however, your application might need additional declarations.?source $system.system.extdecs (! For SQL! SQLCADISPLAY, SQLCATOBUFFER, SQLFSCODE, SQLGETINFOLIST, SQLSADISPLAY,! For startup! INITIALIZER,! For memory management! DEFINEPOOL, GETPOOL, PUTPOOL! For terminal I/O! MYTERM, OPEN, READ, WRITE, WRITEREAD! For data conversion! NUMIN, DNUMIN, FORMATCONVERT, FORMATDATA, FNAMEEXPAND,! For abnormal termination! ABEND );! For data type literals and utility routines (required)?source $vol.subvol.taldecs;! For run-time and utility routines (optional)?search $vol.subvol.tallib; 3. Declare the SQLCA and SQLSA data structures: EXEC SQL INCLUDE SQLCA; EXEC SQL INCLUDE SQLSA; 4. Declare the SQLDA and names buffers. INCLUDE SQLDA generates a template; for the names buffer, you must declare your own template. If you do not plan to allocate the names buffer dynamically, use INCLUDE SQLDA with the name-stringsize parameter instead of creating your own template. EXEC SQL INCLUDE SQLDA (sqlda^templ, 1); STRUCT namesbuf^template(*); BEGIN STRING namestr [0:1000]; END; 7-8

Dynamic NonStop SQL Operations Overview of a Dynamic SQL Program 5. Declare the SQLCODE variable and any host variables: INT sqlcode; -- required for error processing EXEC SQL BEGIN DECLARE SECTION;! Pointers to input and output SQLDAs. (The SQLDAs will! be dynamically allocated later.) INT.isqlda^ptr (sqlda^templ); INT.osqlda^ptr (sqlda^templ);! Pointers to input and output names buffers. INT.inamesbuf^ptr (namesbuf^templ); INT.onamesbuf^ptr (namesbuf^templ);! Buffer for the statement entered by the user.! MAXLEN is a literal you define for the statement length. STRING statement^buffer[0:maxlen];! Variable for the statement name. Use with PREPARE,! DESCRIBE, OPEN, FETCH, CLOSE. LEN is a literal you! define for the length of the name. STRING statement^hostvar[0:len];! Variable for the name of the cursor to use for! processing the statement. STRING cursor^hostvar[0:len]; EXEC SQL END DECLARE SECTION; The variables STATEMENT^HOSTVAR and CURSOR^HOSTVAR are optional. You can code statement and cursor names in the PREPARE and DECLARE CURSOR statements. Reading and Compiling the Statement 1. Specify WHENEVER directives for error handling: EXEC SQL WHENEVER SQLERROR CALL :handle^error; EXEC SQL WHENEVER SQLWARNING CONTINUE; You can place the WHENEVER directives anywhere; however, you must declare or forward declare the error handling procedures before you declare the WHENEVER directives. 2. Read the SQL statement you want to execute from input from a user. 3. Prepare the SQL statement:! Using a statement name: EXEC SQL PREPARE s1 FROM :statement^buffer;! Using a statement host variable: statement^hostvar ':=' "s1"; EXEC SQL PREPARE :statement^hostvar FROM :statement^buffer; 7-9

Dynamic NonStop SQL Operations Overview of a Dynamic SQL Program Use the information returned to the SQLSA structure after the PREPARE statement executes in the next procedure. Handling the Input Parameters If sqlsa.prepare.input^num is 0, skip these steps. 1. Get the number of input parameters and the length of the names buffer (for parameter names) from the SQLSA structure (sqlsa.prepare.input^num and sqlsa.prepare.input^names^len). 2. Allocate memory for the input SQLDA (and names buffer, if needed). This example uses the procedure ALLOCATE^SQLDA. The GETPOOL procedure returns a pointer to the SQLDA in ISQLDA^PTR. 3. Initialize the SQLDA header fields (SQLDA^EYE^CATCHER is defined by the TAL compiler): isqlda^ptr.eye^catcher ':=' SQLDA^EYE^CATCHER; isqlda^ptr.num^entries := sqlsa.prepare.input^num; 4. Specify a DESCRIBE INPUT statement to access input parameters:! Using a statement name: EXEC SQL DESCRIBE INPUT s1 INTO :isqlda^ptr NAMES INTO :inamesbuf^ptr.namestr;! Using a statement host variable: EXEC SQL DESCRIBE INPUT :statement^hostvar INTO :isqlda^ptr NAMES INTO :inamesbuf^ptr.namestr; 5. Loop through the SQLVAR array in the input SQLDA. Loop n times, where n is the number of parameters from sqlsa.prepare.input^num). On each iteration: Check the DATA^TYPE field. If necessary, adjust the data type and reset DATA^LEN and PRECISION accordingly. Allocate a data buffer with size equal to DATA^LEN for the parameter. Use GETPOOL to allocate the memory. DATA^LEN is used differently for different data types. For example, for a binary numeric item the upper byte contains the scale, so you must ignore the upper byte if you are not handling scale. For more information, see Table 6-4 on page 6-17. Set VAR^PTR to point to the memory. If you are not allocating memory dynamically, you will have declared a variable for each input parameter value, and put the address of the variable in VAR^PTR. 7-10

Dynamic NonStop SQL Operations Overview of a Dynamic SQL Program If you know the number and data type of your input parameter values, you can simply set DATA^TYPE, DATA^LEN, and VAR^PTR. Some programs might check DATA^TYPE and DATA^LEN again when the actual values are obtained. If you are handling null values, check NULL^INFO and continue as follows according to its value: 0 Do not allocate memory. However, for the best results, set IND^PTR to an invalid address, such as %HFFFC0000%D, as shown in the example on page 7-18. -1 Allocate 2 bytes of memory for the indicator variable and set IND^PTR to point to the memory allocated in the previous step. (If you are not allocating memory dynamically, define a variable for the indicator and put its address in IND^PTR.) 6. Loop through the names buffer to read the corresponding name for each parameter and prompt the user for each value. Read each value into the data buffer you have allocated for the corresponding parameter, according to the data type of the value. If the parameter can be null (NULL^INFO is -1) and the value entered was null, set the indicator variable at the location in IND^PTR to -1. Handling the Output Variables Perform these steps if sqlsa.prepare.output^num is greater than 0 (zero). 1. Get the length of the output names buffer from sqlsa.prepare.output^names^len 2. Call ALLOCATE^SQLDA to allocate memory for the output SQLDA (and output names buffer, if needed). GETPOOL returns a pointer to the SQLDA in OSQLDA^PTR. 3. Initialize the SQLDA header fields (SQLDA^EYE^CATCHER is defined by the TAL compiler): OSQLDA^PTR.EYE^CATCHER ':=' SQLDA^EYE^CATCHER; OSQLDA^PTR.NUM^ENTRIES := sqlsa.prepare.output^num; 4. Issue a DESCRIBE statement to access the output variables:! Using a statement name: EXEC SQL DESCRIBE s1 INTO :osqlda^ptr NAMES INTO :onamebuf^ptr.namestr;! Using a statement host variable: EXEC SQL DESCRIBE :statement^hostvar INTO :osqlda^ptr NAMES INTO :onamebuf^ptr.namestr; 7-11

Dynamic NonStop SQL Operations Overview of a Dynamic SQL Program 5. Loop through the SQLVAR array in the output SQLDA (loop n times, where n is the number of columns from sqlsa.prepare.output^num). On each iteration: Check DATA^TYPE. If necessary, adjust the data type and reset DATA^LEN and PRECISION accordingly. Allocate a data buffer with size equal to DATA^LEN for the output column. GETPOOL allocates the memory. DATA^LEN is used differently for different data types. For example, for a binary numeric item the upper byte contains the scale, so you must ignore the upper byte if you are not handling scale. For more information, see Table 6-4 on page 6-17. Set VAR^PTR to point to the memory. If you are not allocating memory dynamically, you will have declared a variable for each possible column value; therefore, put the address of the variable in VAR^PTR. If you know the number and data type of your output column values, you can simply set DATA^TYPE, DATA^LEN, and VAR^PTR. Some programs might check DATA^TYPE and DATA^LEN again when the actual values are obtained. If you are handling null values, check NULL^INFO and continue as follows according to its value: -1 Allocate two bytes of memory for the indicator variable. 0 Do not allocate any memory. If necessary, set IND^PTR to point to the memory allocated in the previous step. (If you are not allocating memory dynamically, you will define a variable for the indicator and put its address in IND^PTR.) 6. To show column headings (as SQLCI does), loop through the names buffer to read the corresponding name for each column and display the column names. Performing the Database Request and Displaying the Values If the statement is a SELECT (or if sqlsa.prepare.sql^statement^type is SQL^STATEMENT^SELECT), perform Steps 1 through 8. If the statement is not a SELECT statement, perform Steps 2, 6, and 7. 1. Declare a cursor to handle the SELECT statement.! Using cursor and statement names: EXEC SQL DECLARE c1 CURSOR FOR s1;! Using cursor and statement host variables: EXEC SQL DECLARE :cursor^hostvar CURSOR FOR :statement^hostvar; 7-12

Dynamic NonStop SQL Operations Overview of a Dynamic SQL Program 2. Begin a TMF transaction (for both SELECT and non-select statements): EXEC SQL BEGIN WORK; 3. Open the cursor:! Using a cursor name: EXEC SQL OPEN c1 USING DESCRIPTOR :isqlda^ptr;! Using a cursor host variable: EXEC SQL OPEN :cursor^hostvar USING DESCRIPTOR :isqlda^ptr; 4. Execute a loop to fetch the values and display them.! Using a cursor name: EXEC SQL FETCH c1 USING DESCRIPTOR :osqlda^ptr;! Using a cursor host variable: EXEC SQL FETCH :cursor^hostvar USING DESCRIPTOR :osqlda^ptr; Display the values in a format according to data type. (For a repetitive display of column names, use the output names buffer at this point and omit the last step under Step 4.) Handle null values as follows: If NULL^INFO is -1, then check the indicator variable pointed to by IND^PTR. If the indicator variable is also -1, display something representing a null value (perhaps blanks or zeroes); otherwise, display the value pointed to by VAR^PTR. If NULL^INFO is 0, display the value pointed to by VAR^PTR. 5. Close the cursor:! Using a cursor name: EXEC SQL CLOSE c1;! Using a cursor host variable: EXEC SQL CLOSE :cursor^hostvar; 6. If the statement was not a SELECT statement, execute the statement: If there were input parameters:! Using a statement name: EXEC SQL EXECUTE s1 USING DESCRIPTOR :isqlda^ptr;! Using a statement host variable: EXEC SQL EXECUTE :statement^hostvar USING DESCRIPTOR :isqlda^ptr; 7-13

Dynamic NonStop SQL Operations Dynamically Allocating Memory If there were no input parameters:! Using a statement name: EXEC SQL EXECUTE s1;! Using a statement host variable: EXEC SQL EXECUTE :statement^hostvar; 7. End the TMF transaction (for both SELECT and other statements): EXEC SQL COMMIT WORK; 8. If you do not want to reexecute the statement, call PUTPOOL to deallocate the memory for the SQLDAs and names buffers and for the values. The following paragraphs describe some of these steps in detail. Dynamically Allocating Memory A program can dynamically allocate memory for input parameters and output variables at run time when the parameters and variables are known. To dynamically allocate memory, follow these steps: 1. Declare a structure template for the SQLDA by issuing the INCLUDE SQLDA directive, and for the names buffer by specifying your own template (Refer to page 7-14.) 2. Declare an SQLSA by issuing the INCLUDE SQLSA directive. 3. PREPARE the input statement. 4. Use the information in the SQLSA to determine the number of input parameters and output variables in the statement. 5. Allocate space for the required number of SQLDA entries to describe the parameters and output variables, using the GETPOOL system procedure. 6. Allocate space for the values input to the program or output from the database, again using GETPOOL. These steps are described in order on the following pages. Declaring the SQLDA Structure Template and the Names Buffer Template To use the INCLUDE SQLDA directive, you must supply both the number of input parameters or output variables and a size for the names buffer. You can specify large numbers to ensure that any data you might obtain at run time will fit. If you are not concerned about memory use, this is the simplest course to take. A more memory-efficient method is to use INCLUDE SQLDA to generate a template for the structure and later allocate memory dynamically both for the SQLDA structure itself and for the variables and names contained in the input statement. 7-14

Dynamic NonStop SQL Operations Dynamically Allocating Memory Dynamic allocation of the names buffer is somewhat different, because INCLUDE SQLDA causes an actual string (not a template) to be declared for the names buffer. If you want to allocate this memory dynamically, you should omit the name-string-size parameter from the INCLUDE SQLDA statement. You can then declare a names buffer template with a large value, and use the template to allocate memory. In the names buffer template, use a number that is greater than any possible size your names buffer could be; otherwise, DESCRIBE INPUT and DESCRIBE might stop describing parameter or variable names too soon. Remember also that indicator variable names appear in the names buffer; if the names are long and you use many indicator variables, you will need to accommodate the indicator variable names. To estimate the names buffer size, use this formula, also accounting for indicator variable names: size = (name-string-size + 11) * sqlvar-count To access the SQLDA, you declare pointers that you later pass to a procedure that allocates the memory. Sample declarations are: EXEC SQL BEGIN DECLARE SECTION; INT.EXT isqlda^ptr (sqlda^type); INT.EXT osqlda^ptr (sqlda^type); EXEC SQL END DECLARE SECTION; After GETPOOL executes, ISQLDA^PTR will point to the memory for the input SQLDA structure, and OSQLDA^PTR will point to the memory for the output SQLDA structure. Declaring the SQLSA Structure Declare an SQLSA structure using the INCLUDE SQLSA directive: EXEC SQL INCLUDE SQLSA; Compiling the Input Statement with PREPARE Use PREPARE to dynamically compile the statement that was input to the program. The code shown in Figure 7-1 gives an overview of the sequence you can follow. The statement is prepared with the name S1. 7-15

Dynamic NonStop SQL Operations Dynamically Allocating Memory Figure 7-1. Using a PREPARE Statement to Compile a Statement EXEC SQL BEGIN DECLARE SECTION;... STRING.statement^buffer[0:511];... EXEC SQL END DECLARE SECTION;... --Prompt for a new statement. Pass statement^buffer --to a procedure that reads and interprets the input.... EXEC SQL PREPARE s1 FROM :statement^buffer; VST0701.vsd Using the SQLSA Structure After the input statement is dynamically compiled with the PREPARE statement, the SQLSA contains this information: The number of input parameters in the statement is in sqlsa.prepare.input^num; use this information to decide how many parameter values to solicit from the user. The length of the buffer that is required to contain the names of the input parameters is in sqlsa.prepare.input^names^len. The number of output variables in the statement is in sqlsa.prepare.output^num; use this information to decide how many column values to report. The length of the buffer that is required to contain the names of the output variables is in sqlsa.prepare.output^names^len. The type of statement being prepared is in sqlsa.prepare.sql^statement^type; use this information to decide what type of statement was entered. Literals defined for the values are shown with INCLUDE SQLSA in Table 3-1 on page 3-4. Because some SQL statements that execute after the PREPARE reset the SQLSA, you should save the values from the sqlsa.prepare fields in separate variables immediately after the PREPARE statement. You can pass these values to a procedure that allocates memory for the required number of input parameters and output variables as well as for the required input and output names buffer length. 7-16

Dynamic NonStop SQL Operations Dynamically Allocating Memory Allocating Memory for the SQLDA Structures and Names Buffers In preparation for allocating memory to store the SQLDA structure, you must get the number of input parameters or output variables from the SQLSA structure. Similarly, to allocate memory for the names buffer, you must get the length of the input or output names buffer from the SQLSA structure. For example: -- Save the SQLSA values immediately after PREPARE: inum := sqlsa.prepare.input^num; inameslen := sqlsa.prepare.input^names^len; IF ( inum > 0) THEN CALL allocate^sqlda(inum);... IF ( inameslen > 0) THEN CALL allocate^namesbuf(inameslen); To allocate memory for the SQLDAs and names buffers for the input and output variables, use the GETPOOL system procedure. GETPOOL allocates a block of memory, and returns the address of that block. Before calling GETPOOL, initialize the pool using the system procedure DEFINEPOOL. For example: -- In global declarations: LITERAL pool^size^in^bytes = 8192d; INT.EXT pool^head[0:18]; INT.EXT pool[0 : pool^size^in^bytes/2d - 1d]; -- In setup or main procedure code: error := DEFINEPOOL(pool^head, pool, pool^size^in^bytes); After calling GETPOOL, your program should put the values returned by GETPOOL into pointers to the SQLDA and names buffer variables that were defined earlier. Caution. If your program uses more than one extended segment, you must ensure that the memory in which you place the SQLDA structure is visible when the SQL statement that uses the SQLDA executes. The is code shows declaring an SQLDA template and using the template to calculate the memory required for the SQLDA structure: -- Global variable declarations: EXEC SQL INCLUDE SQLDA (sqlda^type, 1); -- Code in allocate^sqlda procedure: mem^needed := $LEN(sqlda^type) + (num^entries -1) * $LEN(sqlda^type.sqlvar); -- Call to GETPOOL: @sqlda^ptr := GETPOOL(pool^head, mem^needed); 7-17

Dynamic NonStop SQL Operations Dynamically Allocating Memory Initializing EYE^CATCHER and IND^PTR When you allocate the SQLDA, you must explicitly initialize the EYE^CATCHER and IND^PTR fields. You must initialize IND^PTR even if your program is not using indicator variables to handle null values. Your program must initialize the EYE^CATCHER field in the SQLDA. TAL provides the SQLDA^EYE^CATCHER literal declaration, which you use as follows: sqlda^name.eye^catcher ':=' SQLDA^EYE^CATCHER; where sqlda^name is the SQLDA in your program. You must also initialize the IND^PTR field for each SQLVAR entry. This example shows a recommended literal for initializing IND^PTR -- a 32-bit address that is guaranteed invalid. When you use this literal, it is equivalent to initializing IND^PTR to null: LITERAL NULL^ADDR = %HFFFC0000%D;... FOR i := 0 TO isqlda^ptr.num^entries - 1 DO isqlda^ptr.sqlvar[i].ind^ptr := NULL^ADDR; The ALLOCATE^SQLDA procedure, which will also be called to allocate the output SQLDA, could contain code like that shown in Figure 7-2. This procedure also initializes the EYE^CATCHER and IND^PTR fields. 7-18

Dynamic NonStop SQL Operations Dynamically Allocating Memory Figure 7-2. Allocating the SQLDA Structure -- SQLDA^TYPE and SQLVAR were generated by INCLUDE SQLDA -- LITERAL pool^size^in^bytes = 8192d; -- INT.pool^head[0:18]; -- INT.pool[0:pool^size^in^bytes/2d - 1d]; -- Pool must be initialized using DEFINEPOOL before this -- procedure is called INT(32) PROC allocate^sqlda (num^entries); INT num^entries; -- number of input or output -- variables -- Compute amount of memory needed for the SQLDA. Formula -- used here is recommended. sqlda^mem is explained -- earlier in this section. mem^reqd := $LEN(sqlda^mem) + (num^entries - 1) * $LEN(sqlda^mem.sqlvar); -- call GETPOOL to allocate memory (error checking omitted) @sqlda^ptr := GET (pool^head, $DBL(mem^reqd) ); sqlda^ptr.num^entries := num^entries; -- Initialize EYE^CATCHER (code shown earlier) -- If you are not handling null values, initialize IND^PTR -- to null (code shown earlier in this section) -- return the pointer to newly allocated memory: return @sqlda^ptr; END; BEGIN INT.EXT sqlda^ptr(sqlda^type); INT mem^reqd; -- number of bytes INT i; -- pointer to be -- returned -- required for -- the SQLDA -- loop counter VST0702.vsd To allocate memory for the names buffer, you call GETPOOL using the saved value from sqlsa.prepare.input^names^len. In this call, INAMESBUF^PTR is a pointer to the memory allocated for an input names buffer. IF inameslen > 0 THEN @inamesbuf^ptr := GETPOOL(pool^head, $DBL(inameslen) ); 7-19

Dynamic NonStop SQL Operations Dynamically Allocating Memory Allocating Memory for the Values. After the descriptions of the input parameters and output variables are specified, the program must allocate space for the actual values. The user might enter these values for input parameters, or the system might return them for columns (output variables). The following paragraphs describe how to handle input parameters. The program uses the DESCRIBE INPUT statement to fill in the SQLDA and names buffer with the descriptions of the input parameters in the SQL statement. If you specify NAMES INTO, the names of the parameters are also returned in the names buffer. The DESCRIBE INPUT statement is as follows. Notice that the names are placed in the STRING field of the names buffer template declared for dynamic memory allocation. EXEC SQL DESCRIBE INPUT : statement or :statement-hostvar INTO :isqlda^ptr NAMES INTO :inamesbuf^ptr.namestr; The DESCRIBE INPUT statement places the descriptions for the parameters into the location pointed to by ISQLDA^PTR, (the input SQLDA) and the names of the parameters into the location pointed to by INAMESBUF^PTR. Immediately after DESCRIBE INPUT executes, the VAR^PTR field in the SQLDA points to the first entry in the names buffer. You can use VAR^PTR to read the names from the names buffer only if you access the names buffer immediately following DESCRIBE INPUT. After you have set VAR^PTR to point to the data, you can no longer use VAR^PTR to access the names buffer and must loop through the names buffer to get the names. The program can now allocate memory for the parameter values to be entered. Handling Scale. If your program must handle numeric values with scale, you will need to read scale information from the input SQLDA structure. The DESCRIBE INPUT statement places this information in bits 0 through 7 of the DATA^LEN field in the SQLVAR array. For handling input parameters, these possibilities exist: The program can ignore scale entirely: set bits 0 through 7 of DATA^LEN to 0 and send integers to SQL. The program can ignore scale but accept scaled values from the user: set bits 0 through 7 of DATA^LEN to 0, truncate digits to the right of the decimal point in the user-entered value, and send the resulting integers to SQL. The program can handle scale: write a procedure that scales the user-entered value to match the value in bits 0 through 7 of DATA^LEN. Similar considerations apply if your program must handle precision for date-time, INTERVAL, FLOAT, or binary numeric values. The precision information is in the PRECISION field of the SQLVAR entry. 7-20

Dynamic NonStop SQL Operations Dynamically Allocating Memory Literal Declarations Your program will need to check DATA^TYPE to make sure that the type of the value to be placed in the buffer pointed to by VAR^PTR matches the type expected by SQL. Table 7-1 shows the literal declarations that represent various data types that you can use in your program. Table 7-1. Literal Declarations for Data Types Literal Declaration _SQLDT_ASCII_F _SQLDT_ASCII_V _SQLDT_16BIT_S _SQLDT_16BIT_U _SQLDT_32BIT_S _SQLDT_32BIT_U _SQLDT_REAL _SQLDT_DOUBLE _SQLDT_64BIT_S _SQLDT_DEC_U _SQLDT_DEC_LSS _SQLDT_DEC_LSE _SQLDT_DEC_TSS _SQLDT_DEC_TSE _SQLDT_DATETIME Data Type Fixed-length character string Variable-length character string 16-bit signed integer 16-bit unsigned integer 32-bit signed integer 32-bit unsigned integer 32-bit floating point 64-bit floating point 64-bit signed integer Unsigned ASCII numeric (DECIMAL) number DECIMAL number, leading sign separate DECIMAL number, leading sign embedded DECIMAL number, trailing sign separate DECIMAL number, trailing sign embedded DATETIME item Other literal declarations have been defined to represent PRECISION values for numeric and date-time values and to be used with the PRECISION field of the SQLDA. For a complete list of data type and PRECISION literal declarations, see the INCLUDE SQLDA statement in Section 6. To include the declarations for these literals, use the SOURCE directive to include the TALDECS file:?source $system.system.taldecs Figure 7-3 shows sample code for allocating memory for input parameter values. You can use the same code later to allocate memory for output variables. 7-21

Dynamic NonStop SQL Operations Dynamically Allocating Memory Figure 7-3. Allocating Memory for Values (page 1 of 2) INT PROC setupvarbuffers (sqlda^ptr); STRUCT.EXT sqlda^ptr (sqlda^type); BEGIN INT i; INT mem^reqd; FOR i := 0 TO sqlda^ptr.num^entries-1 DO BEGIN -- Determine the amount of memory needed by this entry's -- data type. Note that for binary and decimal numeric -- items, the byte length is extracted from bits 8-15. -- The upper 8 bits store the scale of the item. CASE sqlda.sqlvar[i].data^type OF BEGIN _SQLDT_ASCII_F, _SQLDT_ASCII_F_UP -> mem_reqd := sqlda.sqlvar[i].data_len; _SQLDT_ASCII_V, _SQLDT_ASCII_V_UP -> mem_reqd := sqlda.sqlvar[i].data_len + 2; _SQLDT_16BIT_S, _SQLDT_16BIT_U, _SQLDT_32BIT_U, _SQLDT_32BIT_S, _SQLDT_64BIT_S, _SQLDT_REAL, _SQLDT_DOUBLE -> mem_reqd := sqlda.sqlvar[i].data_len.<8:15>; _SQLDT_DEC_U, _SQLDT_DEC_LSS, _SQLDT_DEC_LSE, _SQLDT_DEC_TSS, mem_reqd := sqlda.sqlvar[i].data_len.<8:15>; _SQLDT_DEC_TSE -> -- Other DATETIME data types except DAY TO FRACTION _SQLDT_DATETIME, _SQLDT_INT_D_F -> mem^reqd := sqlda.sqlvar[i].data^len.<8:15>; OTHERWISE -> -- Print "Data type not supported" message and -- display sqlda.sqlvar[i].data^len END; -end of case - - CHAR - - VARCHAR - - SMALLINT - - SMALLINT UNSIGNED - - INTEGER UNSIGNED - - INTEGER - - LARGEINT - - REAL - - DOUBLE PRECISION - - DECIMAL UNSIGNED - - DECIMAL LSS - - DECIMAL LSE - - DECIMAL TSS - - DECIMAL TSE - - DATETIME - - DAY TO FRACTION VST0703.vsd 7-22

Dynamic NonStop SQL Operations Using the Names Buffer Figure 7-3. Allocating Memory for Values (page 2 of 2) --Allocate memory for the data value and assign the byte --address of the newly allocated data buffer to VAR^PTR: sqlda.sqlvar[i].var^ptr := GETPOOL(pool^head, $DBL(mem^reqd)); IF sqlda.sqlvar[i].var^ptr = -1d THEN -- Display "Getpool memory management error" message -- and call ABEND... VST0703.vsd The program can now prompt the user for the input parameter values, set the pointer to the first SQLVAR element in the input SQLDA, and read through the SQLVAR array, storing each value the user enters into the appropriate position in memory. Using the Names Buffer If you specified NAMES INTO in your DESCRIBE INPUT statement, the names buffer contains the names of the parameters, which you can use to prompt the user for parameter values. If indicator parameters were specified, the names of the indicator parameters are also in the names buffer (for more information on this section, see Handling Null Values on page 7-36). The data returned to the names buffer is in this form: len-1 name-1 len-2 name-2... len- n name- n where name-1 represents the first name, name-2 the second, and name-n the last. The name length information is a 2-byte integer (SQL data type PIC S9(4) COMP; TAL data type INT). All names with a length of an odd number of characters are padded with a blank to make the length an even number; when you display the names, you might want to check for this blank padding. Expressions appear as a null string with a length of 0. For the program to determine the names in the names buffer, you can write a routine to return the VARCHAR structure for a name when given the index of the parameter information desired. After the DESCRIBE INPUT statement executes, the information for each parameter is in the SQLVAR array; the VAR^PTR field contains the address of the length field for each parameter name in the names buffer. 7-23

Dynamic NonStop SQL Operations Using the Names Buffer Some examples of entries in the names buffer are: Complete Entry Entry Part Description 04 ABCD 04 ABCD 06 ABCDE 06 ABCDE 00 00 2-byte length 4-character string with value = 4 4-character string 2-byte length 4-character string with value = 6 5-character string padded with 1 trailing blank 2-byte length with value = 0 Null string A complete names buffer with the names shown in this example might look like this: 04 ABCD 06 ABCDE 00 Note. If the SQL statement includes indicator parameters, the indicator parameter names are included in the names buffer. For more information, see Handling Null Values on page 7-36. To prompt the user with the parameter names in the input names buffer, you must read the length of the name and then position a pointer past the length field and onto the name. Figure 7-4 shows code to use the names buffer, prompt for input, and read parameter values input by the user. 7-24

Dynamic NonStop SQL Operations Using the Names Buffer Figure 7-4. Getting Parameter Values (page 1 of 2) INT PROC request^invars(sqlda^ptr, inamesbuf^ptr); STRUCT.EXT sqlda^ptr(sqlda^type);! input SQLDA pointer STRING.EXT inamesbuf^ptr;! points to buffer BEGIN! with parameter names! Define template of TAL types that correspond to SQL types STRUCT sql^types (*); BEGIN STRING v^char[0:max^sql^char^length]; STRUCT v^varchar = v^char; BEGIN INT len; STRING VAL[0:MAX^SQL^CHAR^LENGTH-2]; END; INT v^smallint = v^char; INT(32) v^int = v^char; FIXED v^largeint = v^char; FIXED(3) v^numeric = v^char; REAL v^float = v^char; REAL(64) v^double = v^char; STRING v^decimal[0:18] = v^char; STRING v^datetime[0:25] = v^char; END; STRING.param^name[0:39];! current parameter name! (40 is the maximum size! of a column name). INT namelen;! number of bytes in a! parameter name INT nameix;! index into parameter names! string INT input^num; INT.EXT param^(sql^types); INT maxlen;! number of input parameters! pointer to parameter value! maximum length of a string! parameter INT count^read;! number of bytes of input! value actually read INT i;! loop counter! Prompt user for input parameter values...! Get number of input parameters: input^num := sqlda^ptr.num^entries;... VST0704.vsd 7-25

Dynamic NonStop SQL Operations Using the Names Buffer Figure 7-4. Getting Parameter Values (page 2 of 2) nameix := 1; FOR i := 0 TO (input^num - 1) DO BEGIN! Read the length for a parameter name, starting at! the second byte in the length field (assumes no! name ever contains more than 255 characters). namelen := inamesbuf^ptr[nameix];! If parameter has a name, save the name in PARAM^NAME: IF namelen THEN param^name ':=' inamesbuf^ptr[nameix + 1] FOR namelen;! Move index to next length field: nameix := namelen + 2 + nameix;! Request input value based on data type:! Set pointer to storage for current parameter value: @param^ := sqlda.sqlvar[i].var^ptr; maxlen := sqlda.sqlvar[i].data^len; CASE sqlda.sqlvar[i].data^type OF BEGIN SQLDT^ASCII^F, SQLDT^ASCII^F^UP ->! Prompt for value for a string! of maximum MAXLEN characters! Read the parameter value into the memory pointed to by! VAR^PTR, the address of which is in param^.param^.v^char! references the character field in struct sql^types. CALL READX(term, param^.v^char, maxlen);! Read values for other data types. Sample calls are:! For VARCHAR: CALL READX (term, param^.v^varchar.val,! maxlen,param^.varchar.len);! For NUMERIC: 1.Prompt and CALL WRITEREAD! (term, buf, $INT(@next^buf - @sbuf),! 25, count^read);! 2.Call DNUMIN to convert input to numeric.! For DATETIME CALL READX (term, param^.v^datetime! FOR $OCCURS(param^.v^datetime) ); END;! end CASE END; VST0704.vsd 7-26

Dynamic NonStop SQL Operations Allocating and Filling in Output Variables Allocating and Filling in Output Variables To allocate space for output variables, you perform essentially the same set of operations described for allocating space for input parameters except that the pointers point to the output SQLDA and names buffer. To get the descriptions of the output variables into the output SQLDA, you use the DESCRIBE statement instead of DESCRIBE INPUT: EXEC SQL DESCRIBE statement or :statement-hostvar INTO :osqlda^ptr NAMES INTO :onamesbuf^ptr.namestr; DESCRIBE places the descriptions of the column values to be output from the database into the location in memory pointed to by OSQLDA^PTR and the names of the columns into the location pointed to by ONAMESBUF^PTR. For code to allocate memory, see Allocating Memory for the Values. on page 7-20. Handling Scale If your program must handle numeric values with scale, you will need to read scale information from the output SQLDA. DESCRIBE places this information in bits 0:7 of the DATA^LEN field in the SQLVAR array. If you can ignore scale, you can set the DATA^LEN field to 0, causing data truncation; otherwise, you will need to save the scale information and write a procedure to handle scale. The same considerations apply if your program must handle precision for date-time, INTERVAL, FLOAT, or binary numeric values. The precision information is in the PRECISION field of the SQLVAR entry. Displaying Output To display output from the database after the cursor FETCH, you perform these tasks: 1. Set pointers to the beginning of the first SQLVAR array and to the beginning of the names buffer. 2. Get the number of output columns from the SQLDA. 3. Write the column name to the output file using the names buffer pointer (only if you are doing a repetitive display of the column names). 4. Read the DATA^TYPE field from the SQLVAR array to get the data type of the column value to be written. 5. Retrieve the value from the location pointed to by the VAR^PTR field in the SQLVAR array. Format the value and write it to output. The steps to use depend on the data type of the value. 7-27

Dynamic NonStop SQL Operations Allocating and Filling in Output Variables The sequence just described displays names and values repetitively. For example: EMPNUM EMPNAME EMPNUM EMPNAME EMPNUM EMPNAME 2000 JANE ROBERTS 1566 CATHERINE WILLIAMS 1890 RICHARD SMITH You can also display the column names as headings (similar to SQLCI) by executing the following loop. Assume that the value in sqlsa.prepare.output^num was saved in variable OUTNUM. Loop OUTNUM times: 1. Get the length of the column name. 2. Advance to the name. 3. Display the name with some blank space. 4. Advance to the next length field. If you use this second method, you will need to execute a second loop to interpret and display the values, including enough blank space for each value to fall under its column heading. You can use data type literals (listed and described under Allocating Memory for the Values. on page 7-20) to decide how to display output column values. Figure 7-5 shows sample code for displaying the current row output by a SELECT statement. 7-28

Dynamic NonStop SQL Operations Allocating and Filling in Output Variables Figure 7-5. Displaying Output (page 1 of 3) -- Declare, open, fetch, and close the cursor. -- before executing this code. -- Global declarations used in printing output: STRING.EXT next^buf; --ptr to end of data in buffer --Put a string into the line, starting at beginning: DEFINE PUT^STR(s) = @next^buf := @sbuf; next^buf ':=' s -> @next^buf #; --Put an integer into the line, starting at beginning: DEFINE PUT^INT(n) = @next^buf := @sbuf; @next^buf := @next^buf + $DBL(DNUMOUT(next^buf, $DBL(n),10)) #; --Put an integer into the line, starting after the --beginning: DEFINE PUT^INT^MID(n) = @next^buf := @next^buf + $DBL(DNUMOUT(next^buf, $DBL(n),10)) #; --Put an INT(32) into the line, starting at beginning: DEFINE PUT^DBL(n) = @next^buf := @sbuf; @next^buf := @next^buf + $DBL(DNUMOUT(next^buf, n,10)) #; PROC display^result(osqlda^ptr, onamesbuf^ptr); STRUCT.EXT osqlda^ptr(sqlda^type); --output SQLDA ptr STRING.EXT onamesbuf^ptr; -- ptr to buffer with column -- names of table BEGIN INT length; INT nameix; --index into column names buffer INT output^num; --number of columns output by SELECT INT datalen; --length of a column value INT.EXT param^(sql^types); -- ptr to where to put -- column value -- SQL^TYPES is a structure with fields of different -- SQL data types equivalenced to each other INT i; --loop counter -- Get number of columns to output in current row: output^num := osqlda^ptr.num^entries; VST0705.vsd 7-29

Dynamic NonStop SQL Operations Allocating and Filling in Output Variables Figure 7-5. Displaying Output (page 2 of 3) FOR i := 0 to (output^num - 1) DO BEGIN @param^ := osqlda^ptr.sqlvar[i].var^ptr; datalen := osqlda^ptr.sqlvar[i].data^len; -- Position onamesbuf^ptr to the length prefix in -- the names buffer, save the length, move -- the pointer past the prefix and onto a name, and save -- the column name. Code is the same as that used for -- input parameter names (see "Getting Parameter Values"). -- If you want to display the column names once (as SQLCI -- display all the names at this point. The remaining -- does), rather than repetitively with each FETCH, -- code here assumes a repetitive display of column names -- and their associated values. CASE osqlda^ptr.sqlvar[i].data^type OF BEGIN _SQLDT_ASCII_F, _SQLDT_ASCII_F_UP -> -- display first 38 characters: PUT^STR^MID (param^.v^char for $MIN(38,datalen); _SQLDT_16BIT_S -> -- handle sign for smallint signed: IF param^.v^smallint >= 0 THEN BEGIN PUT^INT^MID (param^.v^smallint); END ELSE BEGIN PUT^STR^MID("-"); PUT^INT^MID(-param^.v^smallint); END; _SQLDT_16BIT_U -> PUT^DBL^MID ($UDBL(param^.v^smallint) ); VST0705.vsd 7-30

Dynamic NonStop SQL Operations Using Dynamic Cursors Figure 7-5. Displaying Output (page 3 of 3) -- Proceed to handle all the possible data types for -- output values and write the data pointed to by -- the VAR^PTR field in the output SQLDA in a format -- depending on the data type. For complete code, see -- the detailed sample program END; --end CASE --Call WRITE to print the contents of the output buffer END; -- end FOR loop, traversing sqlvar array END; VST0705.vsd Using Dynamic Cursors Dynamic SQL statements use cursors to process SELECT statements in the same way static SQL statements use cursors. The program reads rows from a table, one by one, and sends the column values to output data buffers specified in the program. This subsection provides some guidelines when you use cursors. The order for executing statements to use a cursor with dynamic SQL operations is: Operation PREPARE statement-name FROM :host-variable Issue the DESCRIBE INPUT and DESCRIBE statements DECLARE cursor-name CURSOR FOR statement-name OPEN cursor-name USING DESCRIPTOR input-sqlda Loop until end-of-file FETCH cursor-name USING DESCRIPTOR output-sqlda CLOSE cursor-name Description Dynamically compiles the SELECT statement defining the cursor Declares the cursor Opens the cursor and gets parameter values from input data buffer in the program Retrieves data and outputs column values to output data buffer in the program Closes the cursor Follow these guidelines when you declare and use a cursor: You can use a host variable wherever you can use the cursor-name and statement-name parameters. For each new statement and cursor, you store the name in the host variable before executing the statements. The DECLARE CURSOR, PREPARE, OPEN, FETCH, CLOSE, DELETE WHERE CURRENT, UPDATE WHERE CURRENT, DESCRIBE INPUT, and DESCRIBE statements for a particular cursor and its associated statement must all appear in the same procedure. 7-31

Dynamic NonStop SQL Operations Using Dynamic Cursors The PREPARE statement does not have to precede the other statements in the program listing order; however, the PREPARE statement must be executed after DECLARE CURSOR and before DESCRIBE, DESCRIBE INPUT, OPEN, FETCH, and CLOSE. Using Cursors with a USING DESCRIPTOR Clause If the program is handling input parameters with values entered at run time, you use the USING DESCRIPTOR clause with the OPEN statement to specify values for the parameters in the SELECT statement. The input SQLDA specifies the address of program data buffers that contain the input parameter values. You also use the USING DESCRIPTOR clause with the FETCH statement to write column values to an output buffer specified in the program s variable declarations. The output SQLDA specifies the address of program data buffers into which FETCH copies the data. Using Cursors with an UPDATE WHERE CURRENT Clause To use UPDATE WHERE CURRENT with a static cursor, you specify a FOR UPDATE OF clause with a column list in the DECLARE CURSOR statement. In contrast, to use UPDATE WHERE CURRENT with a dynamic SQL cursor, you must specify a FOR UPDATE OF clause in the SELECT statement associated with the cursor. This example shows an UPDATE WHERE CURRENT operation with a dynamic SQL cursor. In the example, the host variable HOSTVAR contains the SELECT statement to define the cursor. The host variable :SALVAR receives the selected values. --Copy the string: --"SELECT salary FROM =employee FOR UPDATE OF salary" --into host variable hostvar... EXEC SQL PREPARE s1 FROM :hostvar; EXEC SQL DECLARE c1 CURSOR FOR s1; EXEC SQL OPEN c1; EXEC SQL FETCH c1 INTO :salvar; EXEC SQL UPDATE =employee SET salary = salary * 1.20 WHERE CURRENT OF c1; 7-32

Dynamic NonStop SQL Operations Using Statement and Cursor Host Variables Using Statement and Cursor Host Variables TAL supports using statement and cursor host variables in dynamic SQL operations. You can use host variables instead of statement and cursor names, with the DECLARE CURSOR, PREPARE, OPEN, FETCH, and CLOSE statements. For each new statement or cursor name, you store the name in the host variable before executing the statements. Thus, you must code the statements only once. The example program in Figure 7-6 shows one method to use statement and cursor host variables. 7-33

Dynamic NonStop SQL Operations Using Statement and Cursor Host Variables Figure 7-6. Statement and Cursor Host Variables (page 1 of 2)?SQL?INSPECT?SYMBOLS?NOCODE, NOMAP, NOLMAP?DATAPAGES 64 STRING.buf^end; INT.home^term[0:11]; INT home^term^fnum; INT.ibuf[0:19]; STRING.sbuf := @ibuf '<<' 1; INT i; INT sqlcode; EXEC SQL BEGIN DECLARE SECTION; INT(32) STRUCT BEGIN answer;.curs[0:2]; - - Table of 3 cursor names STRING name[0:1]; END; STRUCT.stmt[0:2]; - - Table of 3 statement names BEGIN STRING name[0:1]; END; LITERAL TEXT^LEN = 80; STRUCT.text[0:2]; - - Table of text for 3 statements BEGIN STRING str[0:text^len-1]; END; EXEC SQL END DECLARE SECTION;? NOLIST? SOURCE $SYSTEM.SYSTEM.EXTDECS (? CLOSE,? DNUMOUT,? INITIALIZER,? MYTERM,? OPEN,? WRITE? )? LIST VST0706.vsd 7-34

Dynamic NonStop SQL Operations Using Statement and Cursor Host Variables Figure 7-6. Statement and Cursor Host Variables (page 2 of 2) PROC p MAIN; BEGIN CALL INITIALIZER; CALL MYTERM (home^term); CALL OPEN (home^term, home^term^fnum); curs[0].name ':=' "c1"; curs[1].name ':=' "c2"; curs[2].name ':=' "c3"; stmt[0].name ':=' "s1"; stmt[1].name ':=' "s2"; stmt[2].name ':=' "s3"; - - Blank fill text buffer: FOR i := 0 to 2 DO text[i].str ':=' " " & text[i].str FOR TEXT^LEN - 1; text[0].str ':=' "select empnum from =employee where salary > 100000"; text[1].str ':=' "select salary from =employee where jobcode = 400"; text[2].str ':=' "select deptnum from =dept where location = ""NEW YORK""";! Use statement and cursor host variables to PREPARE the statements! and associate successive cursors with the statements. FOR i := 0 to 2 DO BEGIN EXEC SQL PREPARE :stmt[i].name FROM :text[i].str; EXEC SQL DECLARE :curs[i].name CURSOR FOR :stmt[i].name; END; - - end FOR loop -- FETCH rows using the cursors and display the results. FOR i := 0 to 2 DO BEGIN EXEC SQL BEGIN WORK; EXEC SQL OPEN :curs[i].name; WHILE sqlcode >= 0 AND sqlcode <> 100 DO BEGIN EXEC SQL FETCH :curs[i].name INTO :answer; IF sqlcode >= 0 AND sqlcode <> 100 THEN BEGIN sbuf ':=' "answer = " -> @buf^end; @buf^end := @buf^end '+' dnumout (buf^end, answer, 10); CALL WRITE (home^term^fnum, ibuf, @buf^end '-' @sbuf); END; END; EXEC SQL CLOSE :curs[i].name; CALL WRITE (home^term^fnum, ibuf, 0); EXEC SQL COMMIT WORK; END; -- end FOR loop CALL CLOSE (home^term^fnum); END; -- end proc p VST0706.vsd The program in Figure 7-6 on page 7-34 produces this output when run with the data in the sample database: answer = 1 answer = 23 answer = 29 7-35

Dynamic NonStop SQL Operations Handling Null Values answer = 32 answer = 65 answer = 89000 answer = 69000 answer = 68000 answer = 96000 answer = 65000 answer = 3000 answer = 4000 answer = 4100 Example of an Application In a possible application for statement and cursor host variables, a server could use a loop to initialize the arrays of statement and cursor host variable names and the array of statements and to execute the PREPARE and DECLARE CURSOR statements. The program could then use the cursors as follows: -- Read $RECEIVE -- Examine a flag in the request message to determine -- which cursor to use CASE flag OF BEGIN -- Assign appropriate name to cursor-host-variable -- according to flag END; EXEC SQL OPEN : cursor-host-variable; -- Loop until SQLCODE = 100: BEGIN EXEC SQL FETCH : cursor-host-variable INTO : column -host-variables; -- Display column values END; EXEC SQL CLOSE : cursor-host-variable; Handling Null Values The input and output SQLDA structures have two fields, NULL^INFO and IND^PTR, that are used for handling null values. Your program accesses these fields in the SQLVAR array, in the same way in which you access VAR^PTR. NULL^INFO IND^PTR indicates whether the input parameter or output variable can contain a null value. If NULL^INFO is 0, IND^PTR has no meaning. If NULL^INFO is less than 0, your program should access IND^PTR before each access of VAR^PTR in order to handle null values correctly. points to a flag that indicates whether the input parameter or output variable actually is null. If the parameter or output variable is not null, the VAR^PTR field specifies the value. 7-36

Dynamic NonStop SQL Operations Handling Null Values Allocating Memory for a Possible Null Value You can allocate memory for indicator variables at the same time you allocate memory for other values. If NULL^INFO is -1, you allocate a buffer for the indicator value and assign its address to the IND^PTR field of the appropriate SQLVAR entry. This example shows code for this allocation. The statements take place within a FOR loop to handle each input parameter or output column. --After allocating memory for the data value and assigning --the address of the memory to VAR^PTR: IF sqlda^ptr.sqlvar[i].null^info = -1 THEN BEGIN sqlda^ptr.sqlvar[i].ind^ptr := GETPOOL (pool^head, $DBL(2) ); -- Get 2 bytes --for the indicator variable IF sqlda^ptr.sqlvar[i].ind^ptr = -1D THEN --(print error message and call ABEND) END; Handling Null Values in Input Parameters If your program is to handle null values on input, each parameter in the statement entered by the user or constructed by your program must have a corresponding indicator parameter, or a run-time error will occur when a null value is encountered. After DESCRIBE INPUT executes and for each input parameter described in an SQLVAR array in the input SQLDA, SQL sets NULL^INFO to -1 if the input parameter in the prepared statement allows a null value (that is, if the prepared statement included a null indicator). If NULL^INFO contains a value of -1 and you are allocating memory dynamically, you can now allocate 2 bytes of memory for a null indicator value, and then set IND^PTR to point to the memory. Allocate this memory at the same time you allocate memory for a possible nonnull parameter value. If the user specifies a null value for the parameter, you assign a -1 to the location pointed to by IND^PTR. NonStop SQL checks this value and assumes a null value for the parameter. If instead the user does not enter a null value for the input parameter, you can assign a 0 to the location pointed to by IND^PTR. NonStop SQL checks IND^PTR, sees that IND^PTR indicates a nonnull value, and gets the parameter value from the location pointed to by VAR^PTR. This example handles a possible null value in an input parameter. In this example, the user is supposed to type in a question mark to signify a null value. The datatype-field refers to the equivalenced data type field in the SQL^TYPES structure on which PARAM^ is based. --Variable declarations: INT.EXT ind^; --pointer used to set null indicator 7-37

Dynamic NonStop SQL Operations Handling Null Values INT.EXT param^(sql^types); --pointer to buffer that --will receive parameter value --Procedure code: --Set pointer to storage for current parameter value: @param^ := isqlda^ptr.sqlvar[i].var^ptr; -- call READX or WRITEREAD, depending on data type... IF (isqlda^ptr.sqlvar[i].null^info = -1) AND (param^. datatype-field = "?") THEN BEGIN @ind^ := isqlda^ptr.sqlvar[i].ind^ptr; ind^ := -1; END; Handling Null Values in Output Variables DESCRIBE sets NULL^INFO to -1 if the output variable can be null (that is, if the prepared statement included a null indicator). If the value returned is null, SQL checks NULL^INFO and moves a -1 into the location pointed to by IND^PTR. (Errors are returned if the value is null but NULL^INFO is 0 or if IND^PTR is an invalid address.) Your program must check NULL^INFO to determine whether the value returned can be null. If NULL^INFO contains a -1, then your program checks the location pointed to by IND^PTR. If that location contains a -1, then a null value was returned. If the location contains 0, then a nonnull value was returned and your program should get the value from the location pointed to by VAR^PTR. This example handles null values in output variables. BUF is a globally defined output buffer. NEXT^BUF is a pointer to the end of data in the buffer. SBUF is a string buffer. This example prints the string NULL to represent a null value. @param^ := osqlda^ptr.sqlvar[i].var^ptr; @ind^ := osqlda^ptr.sqlvar[i].ind^ptr; IF osqlda^ptr.sqlvar[i].null^info = -1 AND ind^ = -1 THEN BEGIN buf ':=' "NULL" -> @next^buf; CALL WRITE(term,buf,$INT(@next^buf - @sbuf)); END ELSE --display values according to data type Null Values and the Names Buffer If your program processes indicator parameters, the names of the indicator parameters are included in the names buffer after DESCRIBE INPUT executes. The IND^PTR field points to the length field for the parameter name in the names buffer. This behavior is parallel to that of VAR^PTR after DESCRIBE INPUT or DESCRIBE. This diagram illustrates the structure of the names buffer immediately after DESCRIBE INPUT when indicator parameters are present for two parameters, where len is a 2-7-38

Dynamic NonStop SQL Operations Handling Null Values byte length, name is a parameter name, ind-len is the length of an indicator parameter name, and ind-name is an indicator parameter name. Each instance of IND^PTR points to the length field for the corresponding indicator parameter name. SQLVAR[1].VAR^PTR SQLVAR[1].IND^PTR SQLVAR[2].VAR^PTR SQLVAR[2].IND^PTR len1 name1 ind-len-1 ind-name-1 len2 name2 ind-len-2 ind-name-2 VST0707.vsd Like input parameter and output variable names, indicator variable names are padded with blanks to even lengths. When you are reading through the names buffer to prompt the user for parameter names, you might need to be aware of the indicator fields and perform tasks such as: 1. Check the NULL^INFO field. 2. If NULL^INFO is -1, read the length field for the indicator. 3. Add this length field plus 2 to the pointer or index to skip to the next name in the names buffer. 7-39

Dynamic NonStop SQL Operations Handling Null Values 7-40

A Sample NonStop SQL Database This appendix describes the sample NonStop SQL database used by some of the examples in this manual. There is one node, the \SYS1 system. The $VOL1 volume on this system contains the PERSNL, SALES, and INVENT subvolumes. Each subvolume contains a catalog and tables relating to a specific operation in the organization: PERSNL SALES INVENT Contains the EMPLOYEE, JOB, and DEPT tables, which hold personnel data. Contains the CUSTOMER, ORDERS, ODETAIL, and PARTS tables, which are used for order data. Contains the SUPPLIER, PARTSUPP, PARTLOC, and ERRORS tables, which hold inventory data. The PARTLOC table is partitioned over three volumes. The other two volumes are $WHS2 and $WHS3 (indicating the data relates to the parts stored at two different warehouses). Figure A-1 on page A-2 shows the names of columns and tables and the relations between the tables in the sample database. Figure A-2 on page A-3 shows the source file containing the record descriptions of database tables. This source file was generated using INVOKE directives executed from SQLCI. For example, the INVOKE directive used to generate the DEPT table is: INVOKE persnl.dept FORMAT TAL TO srcfile (dept); A-1

Sample NonStop SQL Database For more information about SQLCI, see the SQL/MP Version Management Guide. Figure A-1. Sample NonStop SQL Database Relations empnum first_name last_name deptnum jobcode salary custnum custname street city state postcode credit errors_date errors_time errors_id errors_sql errors_text 1 errors_text 2 deptnum deptname manager rptdept location ordernum order_date deliv_date salesrep custnum suppnum suppname street city state postcode jobcode jobdesc ordernum partnum unit_price qty_ordered partnum suppnum partcost qty_received Legend * One to one One to many The PARTLOC table is partitioned by the value of LOC_CODE. partnum partdesc price qty_available loc_code partnum qty_on_hand VSTA01.vsd A-2

Sample NonStop SQL Database Figure A-2. Sample Database Source File (page 1 of 4)!! Personnel (PERSNL)!!?SECTION EMPLOYEE! Record Definition for table \SYS.$VOL.PERSNL.EMPLOYEE! Definition current at 17:10:47-04/20/90 struct employee^type(*); BEGIN int empnum; string first^name[ 0: 14 ]; string last^name[ 0: 19 ]; int deptnum; int jobcode; int(32) salary;! scale is 2 END;?SECTION DEPT! Record Definition for table \SYS.$VOL.PERSNL.DEPT! Definition current at 17:10:59-04/20/90 struct dept^type(*); BEGIN int deptnum; string deptname[ 0: 11 ]; int manager; int rptdept; struct location; begin int string end; END; len; val[ 0:17 ]; VSTA02.vsd A-3

Sample NonStop SQL Database Figure A-2. Sample Database Source File (page 2 of 4)?SECTION JOB! Record Definition for table \SYS.$VOL.PERSNL.JOB! Definition current at 17:11:12-04/20/90 struct job^type(*); BEGIN int jobcode; struct jobdesc; begin int len; string val[ 0:17 ]; end; END;!!! Sales (SALES)!!?SECTION CUSTOMER! Record Definition for table \SYS.$VOL.SALES.CUSTOMER! Definition current at 17:11:21-04/20/90 struct customer^type(*); BEGIN int string string string string string string END; custnum; custname[ 0: 17 ]; street[ 0: 21 ]; city[ 0: 13 ]; state[ 0: 11 ]; postcode[ 0: 9 ]; credit[ 0: 1 ];?SECTION ORDERS! Record Definition for table \SYS.$VOL.SALES.ORDERS! Definition current at 17:11:32-04/20/90 struct orders^type(*); BEGIN int(32) ordernum; int(32) order^date; int(32) deliv^date; int salesrep; int custnum; END; VSTA02.vsd A-4

Sample NonStop SQL Database Figure A-2. Sample Database Source File (page 3 of 4)?SECTION ODETAIL! Record Definition for table \SYS.$VOL.SALES.ODETAIL! Definition current at 17:11:42-04/20/90 struct odetail^type(*); BEGIN int(32) int int(32) int(32) END; ordernum; partnum; unit^price;! scale is 2 qty^ordered;?section PARTS! Record Definition for table \SYS.$VOL.SALES.PARTS! Definition current at 17:11:50-04/20/90 struct parts^type(*); BEGIN int partnum; string partdesc[ 0: 17 ]; int(32) price;! scale is 2 int(32) qty^available; END;!!! Inventory (INVENT)!!?SECTION SUPPLIER! Record Definition for table \SYS.$VOL.INVENT.SUPPLIER! Definition current at 17:12:01-04/20/90 struct supplier^type(*); BEGIN int string string string string string END; suppnum; suppname[ 0: 17 ]; street[ 0: 21 ]; city[ 0: 13 ]; state[ 0: 11 ]; postcode[ 0: 9 ]; VSTA02.vsd A-5

Sample NonStop SQL Database Figure A-2. Sample Database Source File (page 4 of 4)?SECTION PARTSUPP! Record Definition for table \SYS.$VOL.INVENT.PARTSUPP! Definition current at 17:12:11-04/20/90 struct partsupp^type(*); BEGIN int partnum; int suppnum; int(32) partcost;! scale is 2 int(32) qty^received; END;?SECTION PARTLOC! Record Definition for table \SYS.$VOL.INVENT.PARTLOC! Definition current at 17:12:23-04/20/90 struct partloc^type(*); BEGIN string loc^code[ 0: 2 ]; int partnum; int(32) qty^on^hand; END;?SECTION ERRORS! Record Definition for table \SYS.$VOL.INVENT.ERRORS! Definition current at 17:12:23-04/20/90 struct errors^type(*); BEGIN int(32) int(32) int(32) int int string string END; errors^date; errors^time; errors^id; errors^sql; errors^fs; errors^text1 [ 0: 239 ]; errors^text2 [ 0: 239 ]; VSTA02.vsd A-6

B Examples of Static NonStop SQL Programs This appendix describes these sample static SQL programs: Insertion program (TALTEST) Date-time program (TALDT) Insertion Program The insertion program (TALTEST) uses the NonStop SQL sample database, which is described in Appendix A, Sample NonStop SQL Database. TALTEST inserts a part name, part number, and quantity into the PARTS table and then inserts a new part into the PARTLOC table. For database consistency, the program reads the SUPPLIER table to determine whether the supplier of the part is a record in the table. TALTEST reads the SUPPLIER table with a cursor, locking the row in the table. Then, it inserts a row in the PARTLOC and PARTS tables before committing the transaction. TALTEST uses values that are supplied by initializing variables. It performs error processing using the SQLCODE value (and not the SQLCA structure). TALTEST uses the =_DEFAULTS DEFINE for the default catalog in which the SQL compiler registers the program file and the TACL DEFINE names shown below for the table names. SET DEFMODE ON ALTER DEFINE =_DEFAULTS, CATALOG INVENT SET DEFINE CLASS MAP ADD DEFINE =PARTS, FILE SALES.PARTS ADD DEFINE =SUPPLIER, FILE INVENT.SUPPLIER ADD DEFINE =PARTLOC, FILE INVENT.PARTLOC Figure B-1 shows the TALTEST program output. The object file name is TALTESTO. B-1

Examples of Static NonStop SQL Programs Insertion Program Figure B-1. Insertion Program Output RUN TALTESTO OUTPUT: START PROGRAM NEWPART ****** SUPPLIER IS ATTRACTIVE CORP BEGIN INSERT ON PARTS ************ BEGIN INSERT ON PARTLOC ********** COMMIT TRANSACTION PART ADDED. PROGRAM ENDS VSTB01.vsd B-2

Examples of Static NonStop SQL Programs Insertion Program The TAL compiler listing for TALTEST is shown on the following pages. Page 1 [1] $VOL1.S04.TALTEST 1991-10-15 13:40:20 TAL - T9250C30 - (01NOV91) Copyright Tandem Computers Incorporated 1976, 1978, 1981-83, 1985, 1987-91 1. 000000 0 0?SQL NOWHENEVERLIST 2. 0000000 0?SYMBOLS, INSPECT, SAVEABEND, NOMAP, NOCODE, NOGMAP, NOLMAP, DATAPAGES 64 3. 000000 0 0?SEARCH \SYS1.$SYSTEM.SYSTEM.TALLIB Search file: \SYS1.$SYSTEM.SYSTEM.TALLIB 1991-08-30 11:14:19 4. 000000 0 0 5. 000000 0 0 -- Variables for writing to the terminal: 6. 000000 0 0 INT.home^term[0:11], 7. 000014 0 0 home^term^num, 8. 000014 0 0.ibuf[0:99]; 9. 000160 0 0 STRING.sbuf := @ibuf '<<' 1; 10. 000160 0 0 11. 000160 0 0 -- Pointer to end of the I/O buffer: 12. 000160 0 0 STRING.buf^end; 13. 000160 0 0 14. 000160 0 0 -- SQLCODE for error checking: 15. 000160 0 0 INT sqlcode; 16. 000160 0 0 17. 000160 0 0 -- Program variables: 18. 000160 0 0 19. 000160 0 0 STRUCT.in^data^rec; 20. 000160 0 0 BEGIN 21. 000160 0 1 INT in^partnum; 22. 000160 0 1 STRING in^loc^code[0:17]; 23. 000160 0 1 INT(32) in^price; 24. 000160 0 1 STRING in^partdesc[0:17]; 25. 000160 0 1 INT(32) in^qty; 26. 000160 0 1 END; 27. 000207 0 0 28. 000207 0 0 -- Host variables: 29. 000207 0 0 EXEC SQL BEGIN DECLARE SECTION; 30. 000207 0 0 31. 000207 0 0 INT supplier^of^parts; 32. 000207 0 0 33. 000207 0 0 EXEC SQL INVOKE =parts AS parts^type; 33. 000207 0 0 EXEC SQL INVOKE =parts AS parts^type; Source file: [2] $SYSTEM.#3184 1991-10-15 13:40:35 1. 000207 0 0! Record Definition for table \SYS1.$VOL1.SALES.PARTS 2. 000207 0 0! Definition current at 13:40:35-10/15/91 3. 000207 0 0 struct parts^type(*); 4. 000207 0 0 BEGIN 5. 000207 0 1 int partnum /SMALLINT UNSIGNED/; 6. 000207 0 1 string partdesc[0:17]; 7. 000207 0 1 int(32) price;! scale is 2 8. 000207 0 1 int(32) qty^available; 9. 000207 0 1 END; Source file: [1] $VOL1.S04.TALTEST 1991-10-15 13:35:30 34. 000207 0 0 EXEC SQL INVOKE =supplier AS supplier^type; 34. 000207 0 0 EXEC SQL INVOKE =supplier AS supplier^type; Source file: [3] $SYSTEM.#3185 1991-10-15 13:40:37 1. 000207 0 0! Record Definition for table \SYS1.$VOL1.INVENT.SUPPLIER 2. 000207 0 0! Definition current at 13:40:37-10/15/91 3. 000207 0 0 struct supplier^type(*); 4. 000207 0 0 BEGIN B-3

Examples of Static NonStop SQL Programs Insertion Program Page 2 [3] $SYSTEM.#3185 1991-10-15 13:40:20 5. 000207 0 1 int suppnum /SMALLINT UNSIGNED/; 6. 000207 0 1 string suppname[0:17]; 7. 000207 0 1 string street[0:21]; 8. 000207 0 1 string city[0:13]; 9. 000207 0 1 string state[0:11]; 10. 000207 0 1 string postcode[0:9]; 11. 000207 0 1 END; Source file: [1] $VOL1.S04.TALTEST 1991-10-15 13:35:30 35. 000207 0 0 EXEC SQL INVOKE =partloc AS partloc^type; 35. 000207 0 0 EXEC SQL INVOKE =partloc AS partloc^type; Source file: [4] $SYSTEM.#3186 1991-10-15 13:40:40 1. 000207 0 0! Record Definition for table \TSII.$BOOKS1.S04.PARTLOC 2. 000207 0 0! Definition current at 13:40:39-10/15/91 3. 000207 0 0 struct partloc^type(*); 4. 000207 0 0 BEGIN 5. 000207 0 1 string loc^code[0:2]; 6. 000207 0 1 int partnum /SMALLINT UNSIGNED/; 7. 000207 0 1 int(32) qty^on^hand; 8. 000207 0 1 END; Source file: [1] $VOL1.S04.TALTEST 1991-10-15 13:35:30 36. 000207 0 0 37. 000207 0 0 STRUCT.parts^rec(parts^type); 38. 000225 0 0 STRUCT.supplier^rec(supplier^type); 39. 000274 0 0 STRUCT.partloc^rec(partloc^type); 40. 000301 0 0 41. 000301 0 0 EXEC SQL END DECLARE SECTION; 42. 000301 0 0 44. 000301 0 0 -- Declare SQL cursors. 45. 000301 0 0 -- This cursor selects from the SUPPLIER table by supplier number 46. 000301 0 0 -- (SUPPNUM) 47. 000301 0 0 48. 000301 0 0 EXEC SQL DECLARE get_supplier_cursor CURSOR FOR 49. 000301 0 0 SELECT SUPPNUM, 50. 000301 0 0 SUPPNAME, 51. 000301 0 0 STREET, 52. 000301 0 0 CITY, 53. 000301 0 0 STATE, 54. 000301 0 0 POSTCODE 55. 000301 0 0 FROM =supplier 56. 000301 0 0 WHERE SUPPNUM = :supplier^of^parts 57. 000301 0 0 REPEATABLE ACCESS; 58. 000301 0 0 59. 000301 0 0 -- Forward declare error handling procedures: 60. 000301 0 0 PROC NOT^FOUND; FORWARD; 61. 000000 0 0 PROC SQLERROR; FORWARD; 62. 000000 0 0 PROC ABORT^TRANSACTION; FORWARD; 63. 000000 0 0 64. 000000 0 0 -- Copy declarations from EXTDECS file for: 65. 000000 0 0 -- MYTERM, INITIALIZER, OPEN, WRITE, DNUMOUT, and ABEND 66. 000000 0 0 67. 000000 0 0?NOLIST, SOURCE $SYSTEM.SYSTEM.EXTDECS ( 70. 000000 0 0 B-4

Examples of Static NonStop SQL Programs Insertion Program Page 3 [1] $VOL1.S04.TALTEST 1991-10-15 13:40:20 72. 000000 0 0 PROC START^OPERATIONS; 73. 000000 1 0 BEGIN 74. 000000 1 1 75. 000000 1 1 -- Blank out STRING fields in IN^DATA^REC: 76. 000000 1 1 in^data^rec.in^loc^code ':=' 77. 000001 1 1 [ $OCCURS(in^data^rec.in^loc^code) * [" "] ]; 78. 000013 1 1 in^data^rec.in^partdesc ':=' 79. 000013 1 1 [ $OCCURS(in^data^rec.in^partdesc) * [" "] ]; 80. 000025 1 1 81. 000025 1 1 -- Assign values to the variables in IN^DATA^REC: 82. 000025 1 1 in^data^rec.in^partnum := 4120; 83. 000030 1 1 in^data^rec.in^loc^code ':=' "A80"; 84. 000042 1 1 in^data^rec.in^price := 6000000D; 85. 000047 1 1 in^data^rec.in^partdesc ':=' "V8 DISK OPTION"; 86. 000061 1 1 in^data^rec.in^qty := 10D; 87. 000066 1 1 88. 000066 1 1 --Assign a value for supplier: 89. 000066 1 1 supplier^of^parts := 8; 90. 000070 1 1 91. 000070 1 1 -- Write first message to the terminal: 92. 000070 1 1 CALL MYTERM(home^term); 93. 000073 1 1 CALL OPEN(home^term, home^term^num); 94. 000103 1 1 sbuf ':=' "START PROGRAM NEWPART ***** "->@buf^end; 95. 000114 1 1 CALL WRITE(home^term^num,ibuf,@buf^end '-' @sbuf); 96. 000126 1 1 97. 000126 1 1 -- SQL error handling: 98. 000126 1 1 EXEC SQL WHENEVER SQLERROR CALL :SQLERROR; 99. 000126 1 1 EXEC SQL WHENEVER SQLWARNING CALL :SQLERROR; 100. 000126 1 1 EXEC SQL WHENEVER NOT FOUND CALL :NOT^FOUND; 101. 000126 1 1 102. 000126 1 1 -- Begin TMF transaction: 103. 000126 1 1 EXEC SQL BEGIN WORK; 104. 000165 1 1 105. 000165 1 1 END; -- end of START^OPERATIONS 106. 000000 0 0 B-5

Examples of Static NonStop SQL Programs Insertion Program J Page 4 [1] $VOL1.S04.TALTEST 1991-10-15 13:40:20 108. 000000 0 0 PROC CHECK^SUPPLIER; 109. 000000 1 0 BEGIN 110. 000000 1 1 -- Open the cursor at value of host variable SUPPLIER^OF^PARTS: 111. 000000 1 1 EXEC SQL OPEN get_supplier_cursor; 112. 000046 1 1 113. 000046 1 1 -- Perform cursor FETCH: 114. 000046 1 1 EXEC SQL 115. 000046 1 1 FETCH get_supplier_cursor INTO 116. 000046 1 1 :supplier^rec.suppnum, 117. 000046 1 1 :supplier^rec.suppname, 118. 000046 1 1 :supplier^rec.street, 119. 000046 1 1 :supplier^rec.city, 120. 000046 1 1 :supplier^rec.state, 121. 000046 1 1 :supplier^rec.postcode; 122. 000207 1 1 123. 000207 1 1 -- A not-found condition goes to abort^transaction; otherwise, 124. 000207 1 1 -- the supplier record is present. 125. 000207 1 1 126. 000207 1 1 sbuf ':=' "SUPPLIER IS "&supplier^rec.suppname 127. 000207 1 1 FOR $OCCURS(supplier^rec.suppname) ->@buf^end; 128. 000225 1 1 CALL WRITE(home^term^num,ibuf,@buf^end '-' @sbuf); 129. 000237 1 1 130. 000237 1 1 END; --end of CHECK^SUPPLIER 131. 000000 0 0 Page 5 [1] $VOL1.S04.TALTEST 1991-10-15 13:40:20 133. 000000 0 0 PROC DO^ADD^TO^PARTS; 134. 000000 1 0 BEGIN 135. 000000 1 1 parts^rec.partnum := in^data^rec.in^partnum; 136. 000003 1 1 parts^rec.partdesc ':=' in^data^rec.in^partdesc 137. 000003 1 1 FOR $OCCURS(parts^rec.partdesc); 138. 000013 1 1 parts^rec.price := in^data^rec.in^price; 139. 000016 1 1 parts^rec.qty^available := in^data^rec.in^qty; 140. 000023 1 1 141. 000023 1 1 sbuf ':=' "BEGIN INSERT ON PARTS *******"->@buf^end; 142. 000034 1 1 CALL WRITE(home^term^num,ibuf,@buf^end '-' @sbuf); 143. 000046 1 1 144. 000046 1 1 --Insert the record. Use SETSCALE to communicate a scale 145. 000046 1 1 --of 2 to SQL (SETSCALE is used because you are using the 146. 000046 1 1 --INVOKE generated descriptions; otherwise, you could define 147. 000046 1 1 --the PRICE column as FIXED(2). 148. 000046 1 1 EXEC SQL 149. 000046 1 1 INSERT INTO =PARTS 150. 000046 1 1 VALUES ( :parts^rec.partnum, 151. 000046 1 1 :parts^rec.partdesc, 152. 000046 1 1 SETSCALE (:parts^rec.price, 2), 153. 000046 1 1 :parts^rec.qty^available); 154. 000140 1 1 END; 155. 000000 0 0 --End of DO^ADD^TO^PARTS 156. 000000 0 0 B-6

Examples of Static NonStop SQL Programs Insertion Program Page 6 [1] $VOL1.S04.TALTEST 1991-10-15 13:40:20 158. 000000 0 0 PROC DO^ADD^TO^PARTLOC; 159. 000000 1 0 BEGIN 160. 000000 1 1 partloc^rec.loc^code ':=' in^data^rec.in^loc^code 161. 000001 1 1 FOR $OCCURS(partloc^rec.loc^code); 162. 000010 1 1 --Length of PARTLOC^REC.LOC^CODE is used because it's the smaller 163. 000010 1 1 --size. 164. 000010 1 1 165. 000010 1 1 partloc^rec.partnum := in^data^rec.in^partnum; 166. 000013 1 1 partloc^rec.qty^on^hand := in^data^rec.in^qty; 167. 000021 1 1 168. 000021 1 1 sbuf ':=' "BEGIN INSERT ON PARTLOC *******"->@buf^end; 169. 000032 1 1 CALL WRITE(home^term^num,ibuf,@buf^end '-' @sbuf); 170. 000044 1 1 171. 000044 1 1 EXEC SQL 172. 000044 1 1 INSERT INTO =PARTLOC 173. 000044 1 1 VALUES ( :partloc^rec.loc^code, 174. 000044 1 1 :partloc^rec.partnum, 175. 000044 1 1 :partloc^rec.qty^on^hand ); 176. 000127 1 1 177. 000127 1 1 END; --end of DO^ADD^TO^PARTLOC 178. 000000 0 0 179. 000000 0 0 Page 7 [1] $VOL1.S04.TALTEST 1991-10-15 13:40:20 181. 000000 0 0 PROC CLOSE^CURSOR; 182. 000000 1 0 BEGIN 183. 000000 1 1 EXEC SQL CLOSE get_supplier_cursor; 184. 000046 1 1 END; 185. 000000 0 0 186. 000000 0 0 187. 000000 0 0 PROC COMMIT^TRANSACTION; 188. 000000 1 0 BEGIN 189. 000000 1 1 EXEC SQL COMMIT WORK; 190. 000040 1 1 sbuf ':=' "COMMIT TRANSACTION"->@buf^end; 191. 000051 1 1 CALL WRITE(home^term^num,ibuf,@buf^end '-' @sbuf); 192. 000063 1 1 END; 193. 000000 0 0 B-7

Examples of Static NonStop SQL Programs Insertion Program Page 8 [1] $VOL1.S04.TALTEST 1991-10-15 13:40:20 195. 000000 0 0 PROC NOT^FOUND; 196. 000000 1 0 BEGIN 197. 000000 1 1 CALL CLOSE^CURSOR; 198. 000002 1 1 sbuf ':=' "SUPPLIER NOT FOUND: SUPPNUM IS "->@buf^end; 199. 000013 1 1 200. 000013 1 1 --Call DNUMOUT to convert INTeger supplier^of^parts value to 201. 000013 1 1 --ASCII characters for display on the terminal. DNUMOUT is 202. 000013 1 1 --used (with $DBL) instead of using NUMOUT because DNUMOUT 203. 000013 1 1 --suppresses leading zeroes while NUMOUT does not. 204. 000013 1 1 @buf^end := @buf^end '+' DNUMOUT(buf^end, 205. 000013 1 1 $DBL(supplier^of^parts), 10, -1); 206. 000034 1 1 CALL WRITE(home^term^num,ibuf,@buf^end '-' @sbuf); 207. 000046 1 1 CALL ABORT^TRANSACTION; 208. 000047 1 1 CALL ABEND; 209. 000054 1 1 210. 000054 1 1 END; --end of NOT^FOUND 211. 000000 0 0 212. 000000 0 0 213. 000000 0 0 PROC SQLERROR; 214. 000000 1 0 BEGIN 215. 000000 1 1 -- Local variable for SQLCODE. Since we might be changing 216. 000000 1 1 -- the sign of SQLCODE for display, we want to preserve the 217. 000000 1 1 -- global SQLCODE value for future debugging. 218. 000000 1 1 INT errcode; 219. 000000 1 1 errcode := sqlcode; 220. 000003 1 1 221. 000003 1 1 -- Test for negative value in SQLCODE. If the value is an SQL 222. 000003 1 1 -- error and not a warning, it will be negative. We must then 223. 000003 1 1 -- change the value to positive in order to display it with 224. 000003 1 1 -- DNUMOUT, because DNUMOUT expects an unsigned number. 225. 000003 1 1 IF errcode < 0 THEN 226. 000006 1 1 BEGIN 227. 000006 1 2 sbuf ':=' "SQL ERROR: -"->@buf^end; 228. 000017 1 2 errcode := -errcode; 229. 000022 1 2 END 230. 000022 1 1 ELSE IF errcode > 0 THEN 231. 000026 1 1 sbuf ':=' "SQL WARNING: "->@buf^end; 232. 000037 1 1 233. 000037 1 1 @buf^end := @buf^end '+' DNUMOUT(buf^end, $DBL(errcode), 10, -1); 234. 000060 1 1 CALL WRITE(home^term^num,ibuf,@buf^end '-' @sbuf); 235. 000072 1 1 CALL ABORT^TRANSACTION; 236. 000073 1 1 CALL ABEND; 237. 000100 1 1 END; 238. 000000 0 0 239. 000000 0 0 B-8

Examples of Static NonStop SQL Programs Insertion Program Page 9 [1] $VOL1.S04.TALTEST 1991-10-15 13:40:20 241. 000000 0 0 PROC ABORT^TRANSACTION; 242. 000000 1 0 BEGIN 243. 000000 1 1 EXEC SQL ROLLBACK WORK; 244. 000040 1 1 sbuf ':=' "TRANSACTION ABORTED"->@buf^end; 245. 000051 1 1 CALL WRITE(home^term^num,ibuf,@buf^end '-' @sbuf); 246. 000063 1 1 END; 247. 000000 0 0 248. 000000 0 0 249. 000000 0 0 PROC SUCCESSFUL^COMPLETION; 250. 000000 1 0 BEGIN 251. 000000 1 1 sbuf ':=' "PART ADDED. PROGRAM ENDS"->@buf^end; 252. 000012 1 1 CALL WRITE(home^term^num,ibuf,@buf^end '-' @sbuf); 253. 000024 1 1 END; 254. 000000 0 0 Page 10 [1] $VOL1.S04.TALTEST 1991-10-15 13:40:20 256. 000000 0 0 --Main program code: 257. 000000 0 0 PROC DRIVER MAIN; 258. 000000 1 0 BEGIN 259. 000000 1 1 260. 000000 1 1 --Read the system startup message: 261. 000000 1 1 CALL INITIALIZER; 262. 000006 1 1 263. 000006 1 1 CALL START^OPERATIONS; 264. 000007 1 1 CALL CHECK^SUPPLIER; 265. 000010 1 1 CALL DO^ADD^TO^PARTS; 266. 000011 1 1 CALL DO^ADD^TO^PARTLOC; 267. 000012 1 1 CALL CLOSE^CURSOR; 268. 000013 1 1 CALL COMMIT^TRANSACTION; 269. 000014 1 1 CALL SUCCESSFUL^COMPLETION; 270. 000015 1 1 271. 000015 1 1 END; --end of DRIVER B-9

Examples of Static NonStop SQL Programs Date-Time Program Page 11 [1] $VOL1.S04.TALTEST 1991-10-15 13:40:20 BINDER AND COMPILER STATISTICS BINDER - OBJECT FILE BINDER - T9621C30 - (01NOV91) SYSTEM \SYS1. Copyright Tandem Computers Incorporated 1982-1989, 1991 Object file $VOL1.S04.TALS1O TIMESTAMP 1991-10-15 13:40:20 1 Code page 11 Primary data words 193 Secondary data words 64 Data pages 0 Resident code pages 1 Extended data page 204 Top of stack location in words 1 Code segment 0 Binder Warnings 0 Binder Errors TAL - Transaction Application Language - T9250C30 - (01NOV91) Number of compiler errors = 0 Number of unsuppressed compiler warnings = 0 Number of warnings suppressed by NOWARN = 0 Maximum symbol table space used was = 24692 bytes Number of source lines = 3031 Compile cpu time = 00:00:03 Total Elapsed time = 00:00:40 Date-Time Program The date-time sample program (TALDT) inserts values into the PROJECTS table, which you can create using this CREATE TABLE statement.: CREATE TABLE PROJECTS ( PROJECT_NAME CHAR( 10 ) NO DEFAULT NOT NULL, START_DATE DATETIME YEAR TO MINUTE NO DEFAULT NOT NULL, END_DATE DATETIME YEAR TO MINUTE NO DEFAULT NOT NULL, WAIT_TIME INTERVAL DAY(2) NO DEFAULT NOT NULL ) CATALOG =PROJ ; TALDT refers to the PROJECTS table using the DEFINE name =PROJECTS and the catalog using the DEFINE name =PROJ. The commands to add these DEFINE names are: SET DEFINE CLASS MAP ADD DEFINE =PROJECTS, FILE PROJ.PROJECTS SET DEFINE CLASS CATALOG ADD DEFINE =PROJ, SUBVOL PROJ TALDT can perform these functions: B-10

Examples of Static NonStop SQL Programs Date-Time Program Insert a new project name, start date, end date, and wait time. Add more wait time to a project by updating the WAIT_TIME column in the PROJECTS table. The original dates in the START_DATE and END_DATE columns in the PROJECTS table remain unchanged. Print a report showing the original dates and the new dates. The report function computes the new dates by adding wait time to both the start date and end date. TALDT also shows these error handling techniques: A temporary variable to save the SQLCODE value within an error handling routine, which allows the program to use the value after handling the error The temporary disabling of WHENEVER SQLERROR checking to avoid a possible infinite loop if an error should occur in the error handling routine The temporary disabling of WHENEVER NOT FOUND checking for a cursor FETCH operation The use of the SQLCODE value to make processing decisions and to make certain operations conditional upon the absence of any errors Figure B-2 shows a sample run of TALDT. The object file is TALDTO. The data entered by the user is shown in bold type. Figure B-2 also includes SQLCI sessions, displaying the contents of the PROJECTS table before and after the program updates the table. B-11

Examples of Static NonStop SQL Programs Date-Time Program Figure B-2. Date-Time Program Run (page 1 of 3) 14> SQLCI >>select * from =projects; PROJECT_NAME START_DATE END_DATE WAIT_TIME 920 134 1988-02-21:20:30 1970-01-01:00:00 1989-03-21:20:30 1978-03-21:20:30 30 30 - - - 2 row(s) selected. >>exit; End of SQLCI Session 15> RUN TALDTO START PROJECTS UPDATE PROGRAM PLEASE ENTER: 1 - - to insert new project data 2 - - to add wait time to a project 3 - - to report original and new project dates 4 - - to exit the program Please enter selection:1 Enter a project name of up to 10 characters:777 Enter a start date-time as YYYY-MM-DD:HH:MM:1989-07-15:06:30 Enter an end date-time as YYYY-MM-DD:HH:MM:1989-10-31:23:58 Wait time for the new project is set at 0. ***** RECORD INSERTED ***** PLEASE ENTER: 1 - - to insert new project data 2 - - to add wait time to a project 3 - - to report original and new project dates 4 - - to exit the program Please enter selection:2 Enter a project name of up to 10 characters:777 Enter number of days of wait time to add:092 ***** WAIT TIME ADDED ***** VSTB02.vsd B-12

Examples of Static NonStop SQL Programs Date-Time Program Figure B-2. Date-Time Program Run (page 2 of 3) PLEASE ENTER: 1 - - to insert new project data 2 - - to add wait time to a project 3 - - to report original and new project dates 4 - - to exit the program Please enter selection:3 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ORIGINAL DATES: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * PROJECT NAME: 920 START DATE: 1988-02-21:20:30 END DATE: 1989-03-21:20:30 PROJECT NAME: 134 START DATE: 1970-01-01:00:00 END DATE: 1978-03-21:20:30 PROJECT NAME: 777 START DATE: 1989-07-15:06:30 END DATE: 1989-10-31:23:58 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * NEW DATES: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * PROJECT NAME: 920 START DATE: 1988-03-22:20:30 END DATE: 1989-04-20:20:30 WAIT TIME: 30 DAYS PROJECT NAME: 134 START DATE: 1970-01-31:00:00 END DATE: 1978-04-20:20:30 WAIT TIME: 30 DAYS PROJECT NAME: 777 START DATE: 1989-10-15:06:30 END DATE: 1990-01-31:23:58 WAIT TIME: 92 DAYS VSTB02.vsd B-13

Examples of Static NonStop SQL Programs Date-Time Program Figure B-2. Date-Time Program Run (page 3 of 3) PLEASE ENTER: 1 - - to insert new project data 2 - - to add wait time to a project 3 - - to report original and new project dates 4 - - to exit the program Please enter selection:4 TERMINATING PROJECTS UPDATE PROGRAM 16> SQLCI >>select * from =projects; PROJECT_NAME START_DATE END_DATE WAIT_TIME 920 134 777 1988-02-21:20:30 1970-01-01:00:00 1989-07-15:06:30 1989-03-21:20:30 1978-03-21:20:30 1989-10-31:23:58 30 30 92 --- 3 row(s) selected. VSTB02.vsd B-14

Examples of Static NonStop SQL Programs Date-Time Program The TAL compiler listing for TALDT is shown on the following pages. Page 1 [1] $VOL1.S04.TALDT 1991-10-15 13:41:07 TAL - T9250C30 - (01NOV91) Copyright Tandem Computers Incorporated 1976, 1978, 1981-83, 1985, 1987-91 1. 000000 0 0?SQL NOWHENEVERLIST 2. 000000 0 0?SYMBOLS, INSPECT, SAVEABEND, NOMAP, NOCODE, NOGMAP, NOLMAP, DATAPAGES 64 3. 000000 0 0?SEARCH \SYS1.$SYSTEM.SYSTEM.TALLIB Search file: \SYS1.$SYSTEM.XTALC30.TALLIB 1991-08-30 11:14:19 4. 000000 0 0 5. 000000 0 0 -- Variables for terminal I/O: 6. 000000 0 0 INT.HOME^TERM[0:11], 7. 000014 0 0 HOME^TERM^NUM, 8. 000014 0 0 NUM^READ, 9. 000014 0 0.IBUF[0:99]; 10. 000160 0 0 STRING.SBUF := @IBUF '<<' 1; 11. 000160 0 0 12. 000160 0 0 -- Pointer to end of the I/O buffer: 13. 000160 0 0 STRING.BUF^END; 14. 000160 0 0 15. 000160 0 0 16. 000160 0 0 -- Invoke the PROJECTS table into 3 record areas for: 17. 000160 0 0 -- -storing the current dates 18. 000160 0 0 -- -storing the original dates 19. 000160 0 0 -- -storing the values entered by the user as search criteria 20. 000160 0 0 -- The original dates will be used in the report function. 21. 000160 0 0 -- 22. 000160 0 0 -- The TYPE description for the PROJECTS table from INVOKE is: 23. 000160 0 0 -- 24. 000160 0 0 -- STRUCT PROJECTS^TYPE(*); 25. 000160 0 0 -- BEGIN 26. 000160 0 0 -- STRING PROJECT^NAME[0 : 9]; 27. 000160 0 0 -- STRING START^DATE[0 : 15]; 28. 000160 0 0 -- STRING END^DATE[0 : 15]; 29. 000160 0 0 -- STRING WAIT^TIME[0 : 2]; 30. 000160 0 0 -- END; 31. 000160 0 0 -- Note that INVOKE generates an extra byte for INTERVAL values, 32. 000160 0 0 -- to accommodate a possible negative sign. 33. 000160 0 0 34. 000160 0 0 EXEC SQL BEGIN DECLARE SECTION; 35. 000160 0 0 EXEC SQL INVOKE =PROJECTS AS PROJECTS^TYPE; 35. 000160 0 0 EXEC SQL INVOKE =PROJECTS AS PROJECTS^TYPE; Source file: [2] $SYSTEM.#3187 1991-10-15 13:41:24 1. 000160 0 0! Record Definition for table \TSII.$BOOKS1.S04.PROJECTS 2. 000160 0 0! Definition current at 13:41:24-10/15/91 3. 000160 0 0 struct projects^type(*); 4. 000160 0 0 BEGIN 5. 000160 0 1 string project^name[0:9]; 6. 000160 0 1 string start^date[0:15]; 7. 000160 0 1 string end^date[0:15]; 8. 000160 0 1 string wait^time[0:2]; 9. 000160 0 1 END; Source file: [1] $VOL1.S04.TALDT 1991-10-15 13:35:04 36. 000160 0 0 37. 000160 0 0 STRUCT.USER^PROJECTS^REC(PROJECTS^TYPE); 38. 000207 0 0 STRUCT.OLD^PROJECTS^REC(PROJECTS^TYPE); 39. 000236 0 0 STRUCT.NEW^PROJECTS^REC(PROJECTS^TYPE); 40. 000265 0 0 B-15

Examples of Static NonStop SQL Programs Date-Time Program Page 2 [1] $VOL1.S04.TALDT 1991-10-15 13:41:07 41. 000265 0 0 EXEC SQL END DECLARE SECTION; 42. 000265 0 0 43. 000265 0 0 INT SQLCODE; 44. 000265 0 0 45. 000265 0 0 STRING SEL^INDEX; 46. 000265 0 0 -- for user's choice from menu 47. 000265 0 0 48. 000265 0 0 EXEC SQL INCLUDE SQLCA; 48. 000265 0 0 EXEC SQL INCLUDE SQLCA; Source file: [3] $SYSTEM.#3188 1991-10-15 13:41:27 1. 000265 0 0 struct.sqlca; 2. 000265 0 0 BEGIN 3. 000265 0 1 STRING filler^[0:429]; 4. 000265 0 1 END; -- SQLCA Source file: [1] $VOL1.S04.TALDT 1991-10-15 13:35:04 49. 000614 0 0 -- for SQLCADISPLAY 50. 000614 0 0 51. 000614 0 0 -- Declare cursors for report function : 52. 000614 0 0 53. 000614 0 0 EXEC SQL 54. 000614 0 0 DECLARE OLD_DATES_CURSOR CURSOR FOR 55. 000614 0 0 SELECT PROJECT_NAME, 56. 000614 0 0 START_DATE, 57. 000614 0 0 END_DATE 58. 000614 0 0 FROM =PROJECTS; 59. 000614 0 0 60. 000614 0 0 EXEC SQL 61. 000614 0 0 DECLARE NEW_DATES_CURSOR CURSOR FOR 62. 000614 0 0 SELECT PROJECT_NAME, 63. 000614 0 0 START_DATE + WAIT_TIME, 64. 000614 0 0 END_DATE + WAIT_TIME, 65. 000614 0 0 WAIT_TIME 66. 000614 0 0 FROM =PROJECTS; 67. 000614 0 0 68. 000614 0 0 -- Copy declarations from EXTDECS file for: 69. 000614 0 0 -- MYTERM, INITIALIZER, SQLCADISPLAY, OPEN, WRITE, WRITEREAD, and STOP 70. 000614 0 0 71. 000614 0 0?NOLIST, SOURCE $SYSTEM.SYSTEM.EXTDECS ( 75. 000000 0 0 76. 000000 0 0 -- SQL error handling: 77. 000000 0 0 PROC SQL^ERROR; FORWARD; 78. 000000 0 0 PROC NOT^FOUND; FORWARD; 79. 000000 0 0 EXEC SQL WHENEVER NOT FOUND CALL :NOT^FOUND; 80. 000000 0 0 81. 000000 0 0 -- Treat warnings the same as errors for simplicity 82. 000000 0 0 EXEC SQL WHENEVER SQLWARNING CALL :SQL^ERROR; 83. 000000 0 0 84. 000000 0 0 EXEC SQL 85. 000000 0 0 WHENEVER SQLERROR CALL :SQL^ERROR; 86. 000000 0 0 -- Forward declaring these procedures for clarity in later calls 87. 000000 0 0 PROC FETCH^AND^DISPLAY^OLD; FORWARD; 88. 000000 0 0 PROC FETCH^AND^DISPLAY^NEW; FORWARD; 89. 000000 0 0 90. 000000 0 0 91. 000000 0 0 PROC NOT^FOUND; 92. 000000 1 0 93. 000000 1 0 BEGIN B-16

Examples of Static NonStop SQL Programs Date-Time Program Page 3 [1] $VOL1.S04.TALDT 1991-10-15 13:41:07 94. 000000 1 1 95. 000000 1 1 -- Temporary variable to save the value of SQLCODE for later 96. 000000 1 1 -- checking. ROLLBACK WORK sets SQLCODE to 0. 97. 000000 1 1 INT TEMP^SQLCODE; 98. 000000 1 1 99. 000000 1 1 TEMP^SQLCODE := SQLCODE; 100. 000003 1 1 101. 000003 1 1 SBUF ':=' " RECORD NOT FOUND ***** "->@BUF^END; 102. 000014 1 1 CALL WRITE(HOME^TERM^NUM,IBUF,@BUF^END '-' @SBUF); 103. 000026 1 1 104. 000026 1 1 EXEC SQL ROLLBACK WORK; 105. 000074 1 1 106. 000074 1 1 SBUF ':=' " TRANSACTION ABORTED ***** "->@BUF^END; 107. 000105 1 1 CALL WRITE(HOME^TERM^NUM,IBUF,@BUF^END '-' @SBUF); 108. 000117 1 1 109. 000117 1 1 SQLCODE := TEMP^SQLCODE; 110. 000121 1 1 END; 111. 000000 0 0 112. 000000 0 0 PROC SQL^ERROR; 113. 000000 1 0 BEGIN 114. 000000 1 1 115. 000000 1 1 -- Temporary variable to save the value of SQLCODE for later 116. 000000 1 1 -- checking. ROLLBACK WORK sets SQLCODE to 0. 117. 000000 1 1 INT TEMP^SQLCODE; 118. 000000 1 1 119. 000000 1 1 TEMP^SQLCODE := SQLCODE; 120. 000003 1 1 121. 000003 1 1 -- Turn off WHENEVER checking to avoid infinite loop: 122. 000003 1 1 EXEC SQL WHENEVER SQLERROR CONTINUE; 123. 000003 1 1 124. 000003 1 1 CALL SQLCADISPLAY( SQLCA ); 125. 000015 1 1 EXEC SQL ROLLBACK WORK; 126. 000057 1 1 127. 000057 1 1 SBUF ':=' " TRANSACTION ABORTED ***** "->@BUF^END; 128. 000070 1 1 CALL WRITE(HOME^TERM^NUM,IBUF,@BUF^END '-' @SBUF); 129. 000102 1 1 130. 000102 1 1 -- re-enable WHENEVER checking: 131. 000102 1 1 EXEC SQL WHENEVER SQLERROR CALL :SQL^ERROR; 132. 000102 1 1 133. 000102 1 1 SQLCODE := TEMP^SQLCODE; 134. 000104 1 1 END; 135. 000000 0 0 136. 000000 0 0 PROC INSERT^PROJECT; 137. 000000 1 0 BEGIN 138. 000000 1 1 139. 000000 1 1 EXEC SQL BEGIN WORK; 140. 000047 1 1 141. 000047 1 1 SBUF ':=' "Enter a project name of up to 10 characters: " ->@BUF^END; 142. 000060 1 1 CALL WRITEREAD(HOME^TERM^NUM,IBUF,@BUF^END '-' @SBUF,20, NUM^READ); 143. 000073 1 1 USER^PROJECTS^REC.PROJECT^NAME ':=' SBUF FOR NUM^READ; 144. 000100 1 1 145. 000100 1 1 SBUF ':=' "Enter a start date-time as YYYY-MM-DD:HH:MM " ->@BUF^END; 146. 000111 1 1 CALL WRITEREAD(HOME^TERM^NUM,IBUF,@BUF^END '-' @SBUF,26, NUM^READ); 147. 000124 1 1 USER^PROJECTS^REC.START^DATE ':=' SBUF FOR NUM^READ; 148. 000132 1 1 149. 000132 1 1 SBUF ':=' "Enter an end date-time as YYYY-MM-DD:HH:MM " ->@BUF^END; 150. 000143 1 1 CALL WRITEREAD(HOME^TERM^NUM,IBUF,@BUF^END '-' @SBUF,26, NUM^READ); B-17

Examples of Static NonStop SQL Programs Date-Time Program Page 4 [1] $VOL1.S04.TALDT 1991-10-15 13:41:07 151. 000156 1 1 USER^PROJECTS^REC.END^DATE ':=' SBUF FOR NUM^READ; 152. 000164 1 1 153. 000164 1 1 SBUF ':=' "Wait time for the new project is set at 0 "->@BUF^END; 154. 000175 1 1 CALL WRITE(HOME^TERM^NUM,IBUF,@BUF^END '-' @SBUF); 155. 000214 1 1 156. 000214 1 1 USER^PROJECTS^REC.WAIT^TIME ':=' "00"; 157. 000226 1 1 158. 000226 1 1 EXEC SQL 159. 000226 1 1 INSERT INTO =PROJECTS 160. 000226 1 1 (PROJECT_NAME, START_DATE, END_DATE, 161. 000226 1 1 WAIT_TIME) 162. 000226 1 1 VALUES 163. 000226 1 1 ( :USER^PROJECTS^REC.PROJECT^NAME, 164. 000226 1 1 :USER^PROJECTS^REC.START^DATE 165. 000226 1 1 TYPE AS DATETIME YEAR TO MINUTE, 166. 000226 1 1 :USER^PROJECTS^REC.END^DATE 167. 000226 1 1 TYPE AS DATETIME YEAR TO MINUTE, 168. 000226 1 1 :USER^PROJECTS^REC.WAIT^TIME 169. 000226 1 1 TYPE AS INTERVAL DAY(2) ); 170. 000327 1 1 171. 000327 1 1 IF SQLCODE = 0 THEN 172. 000331 1 1 BEGIN 173. 000331 1 2 SBUF ':=' "***** RECORD INSERTED ***** "->@BUF^END; 174. 000342 1 2 CALL WRITE(HOME^TERM^NUM,IBUF,@BUF^END '-' @SBUF); 175. 000354 1 2 EXEC SQL COMMIT WORK; 176. 000422 1 2 END; 177. 000422 1 1 178. 000422 1 1 179. 000422 1 1 END; -- insert^project 180. 000000 0 0 181. 000000 0 0 182. 000000 0 0 PROC ADD^WAIT^TIME; 183. 000000 1 0 -- 184. 000000 1 0 --"Wait time" is assumed to express a delay in starting the 185. 000000 1 0 -- project. The report function will add the wait time to the 186. 000000 1 0 -- start and end dates and report the new dates. Here, we 187. 000000 1 0 -- simply update the wait time column in the database. The 188. 000000 1 0 -- database always stores the original dates. 189. 000000 1 0 190. 000000 1 0 BEGIN 191. 000000 1 1 EXEC SQL BEGIN WORK; 192. 000047 1 1 193. 000047 1 1 SBUF ':=' "Enter a project name of up to 10 characters: "->@BUF^END; 194. 000060 1 1 CALL WRITEREAD(HOME^TERM^NUM,IBUF,@BUF^END '-' @SBUF,20, NUM^READ); 195. 000073 1 1 USER^PROJECTS^REC.PROJECT^NAME ':=' SBUF FOR NUM^READ; 196. 000100 1 1 197. 000100 1 1 SBUF ':=' "Enter number of days of wait time to add: " ->@BUF^END; 198. 000111 1 1 CALL WRITEREAD(HOME^TERM^NUM,IBUF,@BUF^END '-' @SBUF,20, NUM^READ); 199. 000124 1 1 USER^PROJECTS^REC.WAIT^TIME ':=' SBUF FOR NUM^READ; 200. 000132 1 1 201. 000132 1 1 EXEC SQL 202. 000132 1 1 UPDATE =PROJECTS 203. 000132 1 1 SET WAIT_TIME = WAIT_TIME 204. 000132 1 1 + :USER^PROJECTS^REC.WAIT^TIME TYPE AS INTERVAL DAY(2) 205. 000132 1 1 WHERE PROJECT_NAME = :USER^PROJECTS^REC.PROJECT^NAME; 206. 000232 1 1 207. 000232 1 1 IF SQLCODE = 0 THEN B-18

Examples of Static NonStop SQL Programs Date-Time Program Page 5 [1] $VOL1.S04.TALDT 1991-10-15 13:41:07 208. 000234 1 1 BEGIN 209. 000234 1 2 SBUF ':=' "***** WAIT TIME ADDED ***** "->@BUF^END; 210. 000245 1 2 CALL WRITE(HOME^TERM^NUM,IBUF,@BUF^END '-' @SBUF); 211. 000257 1 2 EXEC SQL COMMIT WORK; 212. 000325 1 2 END; 213. 000325 1 1 214. 000325 1 1 END; -- add^wait^time 215. 000000 0 0 216. 000000 0 0 -- Disable WHENEVER NOT FOUND checking so NOT^FOUND code 217. 000000 0 0 -- is not triggered at the end of the FETCH, and so 218. 000000 0 0 -- the program does not stop after fetching the old 219. 000000 0 0 -- records. 220. 000000 0 0 EXEC SQL WHENEVER NOT FOUND CONTINUE; 221. 000000 0 0 222. 000000 0 0 PROC PRINT^REPORT; 223. 000000 1 0 BEGIN 224. 000000 1 1 225. 000000 1 1 EXEC SQL BEGIN WORK; 226. 000043 1 1 227. 000043 1 1 EXEC SQL 228. 000043 1 1 OPEN OLD_DATES_CURSOR; 229. 000105 1 1 230. 000105 1 1 EXEC SQL 231. 000105 1 1 OPEN NEW_DATES_CURSOR; 232. 000147 1 1 233. 000147 1 1 IF SQLCODE = 0 THEN 234. 000151 1 1 BEGIN 235. 000151 1 2 SBUF ':=' "*********************************** " ->@BUF^END; 236. 000162 1 2 CALL WRITE(HOME^TERM^NUM,IBUF,@BUF^END '-' @SBUF); 237. 000174 1 2 SBUF ':=' "ORIGINAL DATES: "->@BUF^END; 238. 000222 1 2 CALL WRITE(HOME^TERM^NUM,IBUF,0); 239. 000232 1 2 CALL WRITE(HOME^TERM^NUM,IBUF,@BUF^END '-' @SBUF); 240. 000244 1 2 SBUF ':=' "*********************************** " ->@BUF^END; 241. 000255 1 2 CALL WRITE(HOME^TERM^NUM,IBUF,@BUF^END '-' @SBUF); 242. 000267 1 2 CALL WRITE(HOME^TERM^NUM,IBUF,0); 243. 000277 1 2 244. 000277 1 2 DO 245. 000277 1 2 CALL FETCH^AND^DISPLAY^OLD 246. 000277 1 2 UNTIL SQLCODE <> 0; 247. 000302 1 2 END; 248. 000302 1 1 249. 000302 1 1 -- Check for NOT FOUND -- came to the end of the records 250. 000302 1 1 IF SQLCODE = 100 THEN 251. 000305 1 1 BEGIN 252. 000305 1 2 253. 000305 1 2 SBUF ':=' "*********************************** " ->@BUF^END; 254. 000316 1 2 CALL WRITE(HOME^TERM^NUM,IBUF,@BUF^END '-' @SBUF); 255. 000330 1 2 SBUF ':=' "NEW DATES: "->@BUF^END; 256. 000341 1 2 CALL WRITE(HOME^TERM^NUM,IBUF,@BUF^END '-' @SBUF); 257. 000353 1 2 SBUF ':=' "*********************************** " ->@BUF^END; 258. 000364 1 2 CALL WRITE(HOME^TERM^NUM,IBUF,@BUF^END '-' @SBUF); 259. 000376 1 2 CALL WRITE(HOME^TERM^NUM,IBUF,0); 260. 000406 1 2 261. 000406 1 2 -- FETCH sets SQLCODE back to 0 262. 000406 1 2 DO 263. 000406 1 2 CALL FETCH^AND^DISPLAY^NEW 264. 000406 1 2 UNTIL SQLCODE <> 0; B-19

Examples of Static NonStop SQL Programs Date-Time Program Page 6 [1] $VOL1.S04.TALDT 1991-10-15 13:41:07 265. 000411 1 2 END; 266. 000411 1 1 267. 000411 1 1 IF SQLCODE = 100 THEN 268. 000414 1 1 EXEC SQL COMMIT WORK; 269. 000456 1 1 270. 000456 1 1 END; -- print^report 271. 000000 0 0 272. 000000 0 0 273. 000000 0 0 -- FETCH^AND^DISPLAY^OLD does not access WAIT^TIME, while 274. 000000 0 0 -- FETCH^AND^DISPLAY^NEW accesses and reports WAIT^TIME. 275. 000000 0 0 276. 000000 0 0 PROC FETCH^AND^DISPLAY^OLD; 277. 000000 1 0 BEGIN 278. 000000 1 1 EXEC SQL 279. 000000 1 1 FETCH OLD_DATES_CURSOR INTO 280. 000000 1 1 :OLD^PROJECTS^REC.PROJECT^NAME, 281. 000000 1 1 :OLD^PROJECTS^REC.START^DATE 282. 000000 1 1 TYPE AS DATETIME YEAR TO MINUTE, 283. 000000 1 1 :OLD^PROJECTS^REC.END^DATE 284. 000000 1 1 TYPE AS DATETIME YEAR TO MINUTE; 285. 000067 1 1 286. 000067 1 1 IF (SQLCODE <> 100) AND (SQLCODE >= 0) THEN 287. 000075 1 1 BEGIN 288. 000075 1 2 SBUF ':=' "PROJECT NAME: "->@BUF^END; 289. 000106 1 2 BUF^END ':=' OLD^PROJECTS^REC.PROJECT^NAME FOR 10 ->@BUF^END; 290. 000114 1 2 CALL WRITE(HOME^TERM^NUM,IBUF,@BUF^END '-' @SBUF); 291. 000126 1 2 CALL WRITE(HOME^TERM^NUM,IBUF,0); 292. 000136 1 2 293. 000136 1 2 SBUF ':=' "START DATE: "->@BUF^END; 294. 000147 1 2 BUF^END ':=' OLD^PROJECTS^REC.START^DATE FOR 16 ->@BUF^END; 295. 000156 1 2 CALL WRITE(HOME^TERM^NUM,IBUF,@BUF^END '-' @SBUF); 296. 000170 1 2 CALL WRITE(HOME^TERM^NUM,IBUF,0); 297. 000200 1 2 298. 000200 1 2 SBUF ':=' "END DATE: "->@BUF^END; 299. 000224 1 2 BUF^END ':=' OLD^PROJECTS^REC.END^DATE FOR 16 ->@BUF^END; 300. 000233 1 2 CALL WRITE(HOME^TERM^NUM,IBUF,@BUF^END '-' @SBUF); 301. 000245 1 2 CALL WRITE(HOME^TERM^NUM,IBUF,0); 302. 000255 1 2 303. 000255 1 2 CALL WRITE(HOME^TERM^NUM,IBUF,0); 304. 000265 1 2 305. 000265 1 2 END; 306. 000265 1 1 END; -- fetch^and^display^old 307. 000000 0 0 308. 000000 0 0 309. 000000 0 0 PROC FETCH^AND^DISPLAY^NEW; 310. 000000 1 0 BEGIN 311. 000000 1 1 EXEC SQL 312. 000000 1 1 FETCH NEW_DATES_CURSOR INTO 313. 000000 1 1 :NEW^PROJECTS^REC.PROJECT^NAME, 314. 000000 1 1 :NEW^PROJECTS^REC.START^DATE 315. 000000 1 1 TYPE AS DATETIME YEAR TO MINUTE, 316. 000000 1 1 :NEW^PROJECTS^REC.END^DATE 317. 000000 1 1 TYPE AS DATETIME YEAR TO MINUTE, 318. 000000 1 1 :NEW^PROJECTS^REC.WAIT^TIME 319. 000000 1 1 TYPE AS INTERVAL DAY(2); 320. 000076 1 1 321. 000076 1 1 IF (SQLCODE <> 100) AND (SQLCODE >= 0) THEN B-20

Examples of Static NonStop SQL Programs Date-Time Program Page 7 [1] $VOL1.S04.TALDT 1991-10-15 13:41:07 322. 000104 1 1 BEGIN 323. 000104 1 2 SBUF ':=' "PROJECT NAME: "->@BUF^END; 324. 000115 1 2 BUF^END ':=' NEW^PROJECTS^REC.PROJECT^NAME FOR 10 ->@BUF^END; 325. 000123 1 2 CALL WRITE(HOME^TERM^NUM,IBUF,@BUF^END '-' @SBUF); 326. 000135 1 2 CALL WRITE(HOME^TERM^NUM,IBUF,0); 327. 000145 1 2 328. 000145 1 2 SBUF ':=' "START DATE: "->@BUF^END; 329. 000156 1 2 BUF^END ':=' NEW^PROJECTS^REC.START^DATE FOR 16 ->@BUF^END; 330. 000165 1 2 CALL WRITE(HOME^TERM^NUM,IBUF,@BUF^END '-' @SBUF); 331. 000177 1 2 CALL WRITE(HOME^TERM^NUM,IBUF,0); 332. 000224 1 2 333. 000224 1 2 SBUF ':=' "END DATE: "->@BUF^END; 334. 000235 1 2 BUF^END ':=' NEW^PROJECTS^REC.END^DATE FOR 16 ->@BUF^END; 335. 000244 1 2 CALL WRITE(HOME^TERM^NUM,IBUF,@BUF^END '-' @SBUF); 336. 000256 1 2 CALL WRITE(HOME^TERM^NUM,IBUF,0); 337. 000266 1 2 338. 000266 1 2 SBUF ':=' "WAIT TIME: "->@BUF^END; 339. 000301 1 2 BUF^END ':=' NEW^PROJECTS^REC.WAIT^TIME FOR 3 ->@BUF^END; 340. 000310 1 2 BUF^END ':=' " "; 341. 000320 1 2 BUF^END ':=' "DAYS"; 342. 000330 1 2 CALL WRITE(HOME^TERM^NUM,IBUF,@BUF^END '-' @SBUF); 343. 000342 1 2 CALL WRITE(HOME^TERM^NUM,IBUF,0); 344. 000352 1 2 345. 000352 1 2 END; 346. 000352 1 1 END; -- fetch^and^display^new 347. 000000 0 0 348. 000000 0 0 349. 000000 0 0 -- Re-enable NOT FOUND checking: 350. 000000 0 0 EXEC SQL 351. 000000 0 0 WHENEVER NOT FOUND CALL :NOT^FOUND; 352. 000000 0 0 353. 000000 0 0 PROC TERMINATE^PROG; 354. 000000 1 0 BEGIN; 355. 000001 1 1 SBUF ':=' "TERMINATING PROJECTS UPDATE PROGRAM " ->@BUF^END; 356. 000012 1 1 CALL WRITE(HOME^TERM^NUM,IBUF,@BUF^END '-' @SBUF); 357. 000024 1 1 CALL STOP; 358. 000031 1 1 END; 359. 000000 0 0 360. 000000 0 0 361. 000000 0 0 PROC DRIVER MAIN; 362. 000000 1 0 363. 000000 1 0 BEGIN 364. 000000 1 1 --Read the system startup message: 365. 000000 1 1 CALL INITIALIZER; 366. 000006 1 1 367. 000006 1 1 -- Open the terminal for I/O: 368. 000006 1 1 CALL MYTERM(HOME^TERM); 369. 000011 1 1 CALL OPEN(HOME^TERM, HOME^TERM^NUM); 370. 000021 1 1 371. 000021 1 1 SBUF ':=' "START PROJECTS UPDATE PROGRAM "->@BUF^END; 372. 000032 1 1 CALL WRITE(HOME^TERM^NUM,IBUF,@BUF^END '-' @SBUF); 373. 000044 1 1 374. 000044 1 1 -- Blank out fields in USER^PROJECTS^REC: 375. 000044 1 1 USER^PROJECTS^REC.PROJECT^NAME ':=' 376. 000044 1 1 [ $OCCURS(USER^PROJECTS^REC.PROJECT^NAME) * [" "] ]; 377. 000055 1 1 USER^PROJECTS^REC.START^DATE ':=' 378. 000055 1 1 [ $OCCURS(USER^PROJECTS^REC.START^DATE) * [" "] ]; B-21

Examples of Static NonStop SQL Programs Date-Time Program Page 8 [1] $VOL1.S04.TALDT 1991-10-15 13:41:07 379. 000067 1 1 USER^PROJECTS^REC.END^DATE ':=' 380. 000067 1 1 [ $OCCURS(USER^PROJECTS^REC.END^DATE) * [" "] ]; 381. 000101 1 1 USER^PROJECTS^REC.WAIT^TIME ':=' 382. 000101 1 1 [ $OCCURS(USER^PROJECTS^REC.WAIT^TIME) * [" "] ]; 383. 000113 1 1 384. 000113 1 1 SEL^INDEX ':=' " "; 385. 000124 1 1 386. 000124 1 1 WHILE SEL^INDEX <> "4" DO 387. 000127 1 1 BEGIN 388. 000127 1 2 SBUF ':=' "PLEASE ENTER: "->@BUF^END; 389. 000140 1 2 CALL WRITE(HOME^TERM^NUM,IBUF,@BUF^END '-' @SBUF); 390. 000152 1 2 CALL WRITE(HOME^TERM^NUM,IBUF,0); 391. 000162 1 2 392. 000162 1 2 SBUF ':=' "1 -- to insert new project data: " ->@BUF^END; 393. 000173 1 2 CALL WRITE(HOME^TERM^NUM,IBUF,@BUF^END '-' @SBUF); 394. 000205 1 2 395. 000205 1 2 SBUF ':=' "2 -- to add wait time to a project: " ->@BUF^END; 396. 000216 1 2 CALL WRITE(HOME^TERM^NUM,IBUF,@BUF^END '-' @SBUF); 397. 000230 1 2 398. 000230 1 2 SBUF ':=' "3 -- to report original and new project dates: "->@BUF^END; 399. 000241 1 2 CALL WRITE(HOME^TERM^NUM,IBUF,@BUF^END '-' @SBUF); 400. 000253 1 2 401. 000253 1 2 SBUF ':=' "4 -- to exit the program "->@BUF^END; 402. 000264 1 2 CALL WRITE(HOME^TERM^NUM,IBUF,@BUF^END '-' @SBUF); 403. 000276 1 2 CALL WRITE(HOME^TERM^NUM,IBUF,0); 404. 000306 1 2 405. 000306 1 2 SBUF ':=' "Please enter selection: "->@BUF^END; 406. 000317 1 2 CALL WRITEREAD(HOME^TERM^NUM,IBUF,@BUF^END '-' @SBUF,10,NUM^READ); 407. 000334 1 2 SEL^INDEX ':=' SBUF FOR NUM^READ; 408. 000341 1 2 409. 000341 1 2 CASE SEL^INDEX OF 410. 000343 1 2 BEGIN 411. 000343 1 3 "1" -> CALL INSERT^PROJECT; 412. 000344 1 3 "2" -> CALL ADD^WAIT^TIME; 413. 000346 1 3 "3" -> CALL PRINT^REPORT; 414. 000350 1 3 "4" -> CALL TERMINATE^PROG; 415. 000352 1 3 OTHERWISE -> 416. 000353 1 3 SBUF ':=' "Incorrect entry "->@BUF^END; 417. 000364 1 3 CALL WRITE(HOME^TERM^NUM,IBUF,@BUF^END ' -' @SBUF); 418. 000376 1 3 END; -- case statement 419. 000415 1 2 420. 000415 1 2 END; -- while sel^index <> 4 421. 000416 1 1 422. 000416 1 1 END; -- end of main B-22

Examples of Static NonStop SQL Programs Date-Time Program Page 9 [1] $VOL1.S04.TALDT 1991-10-15 13:41:07 BINDER AND COMPILER STATISTICS BINDER - OBJECT FILE BINDER - T9621C30 - (01NOV91) SYSTEM \PRUNE Copyright Tandem Computers Incorporated 1982-1989, 1991 Object file $VOL1.S04.TALS2O TIMESTAMP 1991-10-15 13:41:07 3 Code pages 12 Primary data words 396 Secondary data words 64 Data pages 0 Resident code pages 1 Extended data page 408 Top of stack location in words 1 Code segment 0 Binder Warnings 0 Binder Errors TAL - Transaction Application Language - T9250C30 - (01NOV91) Number of compiler errors = 0 Number of unsuppressed compiler warnings = 0 Number of warnings suppressed by NOWARN = 0 Maximum symbol table space used was = 24512 bytes Number of source lines = 3186 Compile cpu time = 00:00:05 Total Elapsed time = 00:00:40 B-23

Examples of Static NonStop SQL Programs Date-Time Program B-24

C Examples of Dynamic NonStop SQL Programs This appendix describes these sample dynamic SQL programs: Simple program (TALDYNEZ) TALDYNEZ processes a SELECT statement that is partially coded into the program; the user supplies the WHERE clause. The SQLDA structures and data buffers are allocated at compile time using the INCLUDE SQLDA directive. Detailed program (TALDYN) TALDYN allows the user to enter any SQL statement from a terminal. The SQLDA structures and data buffers are allocated at run time. These programs use the NonStop SQL sample database, which is described in Appendix A, Sample NonStop SQL Database. Dynamic SQL Program The TALDYNEZ program uses a SELECT statement to find the average salary for a selection of rows in the employee table. The program prompts the user for the selection criteria and then constructs the statement by adding a WHERE clause. TALDYNEZ has no input parameters and only one output variable. The expression AVG(SALARY) is the only element described in the output SQLDA structure, and the average salary is the only value output. Because no parameter names or column headings are required, names buffers are not necessary. TALDYNEZ also assumes that the query will never return a null value. TALDYNEZ allocates memory during compilation using the INCLUDE SQLDA directive and specifying one output variable. You can specify one output variable because you know you are only reporting data for one column. You must still assign the memory location of the value to be output (in this case, the average) to the VAR^PTR field. TALDYNEZ uses the TACL DEFINE name =EMPLOYEE for the EMPLOYEE table in the sample database. The commands to add this DEFINE name are: SET DEFMODE ON SET DEFINE CLASS MAP ADD DEFINE =EMPLOYEE, FILE PERSNL.EMPLOYEE Figure C-1 shows the output for the TALDYNEZ program with the data entered by the user shown in bold type. The object file name is TALDEZO. C-1

Examples of Dynamic NonStop SQL Programs Dynamic SQL Program Figure C-1. Output for the Dynamic SQL Program 10> RUN TALDEZO PLEASE ENTER: 1 - - To find average salary based on employee # 2 - - To find average salary based on job code 3 - - To find average salary based on department # Please enter selection: 1 Please specify the comparison criteria: (for example: > 500, = 1000, <= 250) Enter the comparison criteria now: > 500 THE AVERAGE SALARY IS: 52250 11> VSTC01.vsd C-2

Examples of Dynamic NonStop SQL Programs Dynamic SQL Program The TAL compiler listing for TALDYNEZ is shown on the following pages. Page 1 [1] $VOL1.S04.TALDYNEZ 1991-10-15 13:41:54 TAL - T9250C30 - (01NOV91) Copyright Tandem Computers Incorporated 1976, 1978, 1981-83, 1985, 1987-91 1. 000000 0 0?SQL NOWHENEVERLIST 2. 000000 0 0?SYMBOLS, INSPECT, SAVEABEND, NOMAP, NOCODE, NOGMAP, NOLMAP, DATAPAGES 64 3. 000000 0 0?SEARCH \SYS1.$SYSTEM.SYSTEM.TALLIB Search file: \SYS1.$SYSTEM.SYSTEM.TALLIB 1991-08-30 11:14:19 4. 000000 0 0 5. 000000 0 0!-------------------------------------------------------- 6. 000000 0 0! This program finds the average salary for employees 7. 000000 0 0! according to criteria established by the user. The 8. 000000 0 0! program contains a SELECT statement for the EMPLOYEE 9. 000000 0 0! table; the user enters the selection criteria, which 10. 000000 0 0! the program concatenates to the SELECT statement as a 11. 000000 0 0! WHERE clause. 12. 000000 0 0!-------------------------------------------------------- 13. 000000 0 0 14. 000000 0 0 LITERAL MAXCMD = 1000; 15. 000000 0 0 LITERAL NULL^ADDR = %HFFFC0000%D; 16. 000000 0 0 17. 000000 0 0 -- Variables for terminal I/O: 18. 000000 0 0 INT.HOME^TERM[0:11], 19. 000014 0 0 HOME^TERM^NUM, 20. 000014 0 0 NUM^READ, 21. 000014 0 0.IBUF[0:99]; 22. 000160 0 0 STRING.SBUF := @IBUF '<<' 1; 23. 000160 0 0 24. 000160 0 0 -- Pointer to end of the I/O buffer: 25. 000160 0 0 STRING.BUF^END; 26. 000160 0 0 27. 000160 0 0 --Copy in declarations for data type literals: 28. 000160 0 0?NOLIST 31. 000160 0 0 32. 000160 0 0 -- Other necessary declarations: 33. 000160 0 0 34. 000160 0 0 INT SQLCODE; -- for error checking 35. 000160 0 0 INT(32) AVERAGE; -- for output value 36. 000160 0 0 STRING.CMD[0:MAXCMD - 1]; -- array for SQL statement user enters 37. 001144 0 0 STRING.CMD^END; -- ptr to end of command string 38. 001144 0 0 39. 001144 0 0 EXEC SQL INCLUDE SQLCA; 39. 001144 0 0 EXEC SQL INCLUDE SQLCA; Source file: [3] $SYSTEM.#3189 1991-10-15 13:42:05 1. 001144 0 0 struct.sqlca; 2. 001144 0 0 BEGIN 3. 001144 0 1 STRING filler^[0:429]; 4. 001144 0 1 END; -- SQLCA Source file: [1] $VOL1.S04.TALDYNEZ 1991-10-15 13:36:01 40. 001473 0 0 EXEC SQL INCLUDE SQLSA; 40. 001473 0 0 EXEC SQL INCLUDE SQLSA; Source file: [4] $SYSTEM.#3190 1991-10-15 13:42:07 1. 001473 0 0 STRUCT.sqlsa; 2. 001473 0 0 BEGIN 3. 001473 0 1 STRING eye^catcher[0:1]; 4. 001473 0 1 INT version; 5. 001473 0 1 STRUCT dml; C-3

Examples of Dynamic NonStop SQL Programs Dynamic SQL Program Page 2 [4] $SYSTEM.#3190 1991-10-15 13:41:54 6. 001473 0 1 BEGIN 7. 001473 0 2 INT num^tables; 8. 001473 0 2 STRUCT stats[0:15]; 9. 001473 0 2 BEGIN 10. 001473 0 3 STRING table^name[0:23]; 11. 001473 0 3 INT(32) records^accessed; 12. 001473 0 3 INT(32) records^used; 13. 001473 0 3 INT(32) disc^reads; 14. 001473 0 3 INT(32) messages; 15. 001473 0 3 INT(32) message^bytes; 16. 001473 0 3 INT waits; 17. 001473 0 3 INT escalations; 18. 001473 0 3 STRING sqlsa^reserved[0:3]; 19. 001473 0 3 END; -- stats 20. 001473 0 2 END; -- dml 21. 001473 0 1 STRUCT prepare = dml; 22. 001473 0 1 BEGIN 23. 001473 0 2 INT input^num; 24. 001473 0 2 INT input^names^len; 25. 001473 0 2 INT output^num; 26. 001473 0 2 INT output^names^len; 27. 001473 0 2 INT name^map^len; 28. 001473 0 2 INT sql^statement^type; 29. 001473 0 2 END; -- prepare 30. 001473 0 1 END; -- sqlsa Source file: [1] $VOL1.S04.TALDYNEZ 1991-10-15 13:36:01 41. 002336 0 0 42. 002336 0 0 -- The program will have only one output column, SALARY. Since 43. 002336 0 0 -- we will be generating its average, we do not need to print 44. 002336 0 0 -- the column name; we can therefore omit declaring a names 45. 002336 0 0 -- buffer. We do not plan to allocate memory dynamically, so we 46. 002336 0 0 -- use the INCLUDE SQLDA statement, specifying one output 47. 002336 0 0 -- variable for our output SQLDA. 48. 002336 0 0 49. 002336 0 0 EXEC SQL BEGIN DECLARE SECTION; 50. 002336 0 0 51. 002336 0 0 EXEC SQL INCLUDE SQLDA(osqlda^type,1); 51. 002336 0 0 EXEC SQL INCLUDE SQLDA(osqlda^type,1); Source file: [5] $SYSTEM.#3191 1991-10-15 13:42:08 1. 002336 0 0 LITERAL SQLDA^EYE^CATCHER = "D1"; 2. 002336 0 0 STRUCT osqlda^type (*) ; 3. 002336 0 0 BEGIN 4. 002336 0 1 STRING eye^catcher[0:1]; 5. 002336 0 1 INT num^entries; 6. 002336 0 1 struct sqlvar[0:0]; 7. 002336 0 1 BEGIN 8. 002336 0 2 INT data^type; 9. 002336 0 2 INT data^len; 10. 002336 0 2! fields for NUMBERS: 11. 002336 0 2! scale = data^len.<0:7> 12. 002336 0 2! length = data^len.<8:15> 13. 002336 0 2! fields for DATETIME or INTERVAL: 14. 002336 0 2! qualifier = data^len.<0:7> 15. 002336 0 2! length = data^len.<8:15> 16. 002336 0 2 INT precision; 17. 002336 0 2! fields for DATETIME or INTERVAL: 18. 002336 0 2! leading field precision = precision.<0:7> C-4

Examples of Dynamic NonStop SQL Programs Dynamic SQL Program Page 3 [5] $SYSTEM.#3191 1991-10-15 13:41:54 19. 002336 0 2! fraction precision = precision.<8:15> 20. 002336 0 2 INT null^info; 21. 002336 0 2 INT(32) var^ptr; 22. 002336 0 2 INT(32) ind^ptr; 23. 002336 0 2 FIXED reserved; 24. 002336 0 2 END; 25. 002336 0 1 END; Source file: [1] $VOL1.S04.TALDYNEZ 1991-10-15 13:36:01 52. 002336 0 0 STRUCT.OSQLDA(osqlda^type); 53. 002354 0 0 54. 002354 0 0 EXEC SQL END DECLARE SECTION; 55. 002354 0 0 56. 002354 0 0 -- Copy declarations from EXTDECS file for: 57. 002354 0 0 -- MYTERM,INITIALIZER,SQLCADISPLAY,OPEN,WRITE,WRITEREAD,STOP,DNUMOUT 58. 002354 0 0 59. 002354 0 0?NOLIST, SOURCE $SYSTEM.SYSTEM.EXTDECS ( 63. 000000 0 0 64. 000000 0 0 -- Declare WHENEVER clause for error checking: 65. 000000 0 0 PROC ERROR^HANDLER; FORWARD; 66. 000000 0 0 EXEC SQL WHENEVER SQLERROR CALL :ERROR^HANDLER; 67. 000000 0 0 68. 000000 0 0 69. 000000 0 0!-------------------------------------------------------- 70. 000000 0 0! PROC PROCESS^AND^EXECUTE; 71. 000000 0 0! 72. 000000 0 0! Prepares the command; issues DESCRIBE to get description of 73. 000000 0 0! the output variable; sets VAR^PTR to point to the memory for 74. 000000 0 0! the output variable (average salary); sets up and uses a 75. 000000 0 0! cursor to perform the SELECT and output the average. 76. 000000 0 0!-------------------------------------------------------- 77. 000000 0 0 78. 000000 0 0 PROC PROCESS^AND^EXECUTE (CMD); 79. 000000 1 0 80. 000000 1 0 STRING.CMD; 81. 000000 1 0 82. 000000 1 0 BEGIN 83. 000000 1 1 EXEC SQL BEGIN DECLARE SECTION; 84. 000000 1 1 85. 000000 1 1 -- Create an alternate version of CMD that is an array. 86. 000000 1 1 -- We must do this because you cannot put bounds on a parameter. 87. 000000 1 1 -- In order to pass CMD as a string, we must create this 88. 000000 1 1 -- equivalence. To use CMD as a host variable, we then reference 89. 000000 1 1 -- CMDX.VAL 90. 000000 1 1 91. 000000 1 1 STRUCT S(*); 92. 000000 1 1 BEGIN 93. 000000 1 2 STRING VAL [0:MAXCMD - 1]; 94. 000000 1 2 END; 95. 000000 1 1 96. 000000 1 1 STRING.CMDX(S) = CMD; 97. 000000 1 1 98. 000000 1 1 EXEC SQL END DECLARE SECTION; 99. 000000 1 1 100. 000000 1 1 EXEC SQL PREPARE DYNCMD FROM :CMDX.VAL; 101. 000050 1 1 102. 000050 1 1 OSQLDA.EYE^CATCHER ':=' SQLDA^EYE^CATCHER; 103. 000061 1 1 C-5

Examples of Dynamic NonStop SQL Programs Dynamic SQL Program Page 4 [1] $VOL1.S04.TALDYNEZ 1991-10-15 13:41:54 104. 000061 1 1 OSQLDA.NUM^ENTRIES := 1; 105. 000064 1 1 106. 000064 1 1 -- Initialize IND^PTR field to null. You must initialize 107. 000064 1 1 -- IND^PTR even if the program will not handle null values. 108. 000064 1 1 OSQLDA.SQLVAR[0].IND^PTR := NULL^ADDR; 109. 000070 1 1 110. 000070 1 1 EXEC SQL DESCRIBE DYNCMD INTO :OSQLDA; 111. 000140 1 1 112. 000140 1 1 -- SQL tells you what it has to work with; you then communicate 113. 000140 1 1 -- what your variable is like to SQL. You might want to look 114. 000140 1 1 -- at the DATA^TYPE field and adjust accordingly. Here, we are 115. 000140 1 1 -- using an INT32 and ignoring scale. 116. 000140 1 1 117. 000140 1 1 -- set DATA^TYPE to INT32: 118. 000140 1 1 OSQLDA.SQLVAR[0].DATA^TYPE := _SQLDT_32BIT_U; 119. 000143 1 1 120. 000143 1 1 121. 000143 1 1 -- set length to 4 bytes; leave scale as 0 in upper byte of DATA^LEN: 122. 000143 1 1 OSQLDA.SQLVAR[0].DATA^LEN := 4; 123. 000146 1 1 124. 000146 1 1 125. 000146 1 1 -- set VAR^PTR to point to memory where the average 126. 000146 1 1 -- will be output: 127. 000146 1 1 OSQLDA.SQLVAR[0].VAR^PTR := $XADR(AVERAGE); 128. 000153 1 1 129. 000153 1 1 EXEC SQL BEGIN WORK; 130. 000236 1 1 131. 000236 1 1 EXEC SQL DECLARE C1 CURSOR FOR DYNCMD; 132. 000236 1 1 EXEC SQL OPEN C1; 133. 000300 1 1 EXEC SQL FETCH C1 USING DESCRIPTOR :OSQLDA; 134. 000350 1 1 135. 000350 1 1 136. 000350 1 1 IF SQLCODE >= 0 THEN 137. 000353 1 1 BEGIN 138. 000353 1 2 CALL WRITE(HOME^TERM^NUM,IBUF,0); 139. 000363 1 2 SBUF ':=' "THE AVERAGE SALARY IS: "->@BUF^END; 140. 000374 1 2 -- Convert the average for display and place it into the buffer: 141. 000374 1 2 @BUF^END := @BUF^END '+' DNUMOUT (BUF^END, AVERAGE, 10); 142. 000413 1 2 CALL WRITE(HOME^TERM^NUM,IBUF,@BUF^END '-' @SBUF); 143. 000425 1 2 CALL WRITE(HOME^TERM^NUM,IBUF,0); 144. 000435 1 2 END; 145. 000435 1 1 146. 000435 1 1 EXEC SQL CLOSE C1; 147. 000512 1 1 148. 000512 1 1 EXEC SQL COMMIT WORK; 149. 000554 1 1 150. 000554 1 1 END; -- process^and^execute 151. 000000 0 0 152. 000000 0 0 153. 000000 0 0!-------------------------------------------------------- 154. 000000 0 0! PROC GET^CMD; 155. 000000 0 0! 156. 000000 0 0! Assigns a SELECT statement to the statement buffer. 157. 000000 0 0! Gets the WHERE clause from the user and concatenates it to 158. 000000 0 0! the SELECT statement. 159. 000000 0 0!-------------------------------------------------------- 160. 000000 0 0 C-6

Examples of Dynamic NonStop SQL Programs Dynamic SQL Program Page 5 [1] $VOL1.S04.TALDYNEZ 1991-10-15 13:41:54 161. 000000 0 0 PROC GET^CMD(CMD); 162. 000000 1 0 163. 000000 1 0 STRING.CMD; 164. 000000 1 0 165. 000000 1 0 BEGIN 166. 000000 1 1 STRING COLUMN [0:9]; -- column to be used in 167. 000000 1 1 -- WHERE clause 168. 000000 1 1 STRING SEL^INDEX; -- selects which column to 169. 000000 1 1 -- put in WHERE clause 170. 000000 1 1 STRING PREDICATE [0:9]; -- comparison predicate to 171. 000000 1 1 -- use in WHERE clause 172. 000000 1 1 INT COL^SIZE; -- size of column name 173. 000000 1 1 INT PRED^SIZE; -- size of predicate string 174. 000000 1 1 175. 000000 1 1 -- Pre-load command with blanks: 176. 000000 1 1 CMD ':=' " " & CMD FOR MAXCMD - 1; 177. 000015 1 1 178. 000015 1 1 CMD ':=' "SELECT AVG(SALARY) FROM =EMPLOYEE WHERE " -> @CMD^END; 179. 000026 1 1 180. 000026 1 1 -- Create a simple menu: 181. 000026 1 1 SBUF ':=' "PLEASE ENTER: "->@BUF^END; 182. 000037 1 1 CALL WRITE(HOME^TERM^NUM,IBUF,@BUF^END '-' @SBUF); 183. 000051 1 1 CALL WRITE(HOME^TERM^NUM,IBUF,0); 184. 000061 1 1 185. 000061 1 1 SBUF ':=' "1 -- To find average salary based on employee #"->@BUF^END; 186. 000072 1 1 CALL WRITE(HOME^TERM^NUM,IBUF,@BUF^END '-' @SBUF); 187. 000104 1 1 SBUF ':=' "2 -- To find average salary based on job code"->@buf^end; 188. 000115 1 1 CALL WRITE(HOME^TERM^NUM,IBUF,@BUF^END '-' @SBUF); 189. 000127 1 1 SBUF ':=' "3 -- To find average salary based on department #: "->@BUF^END; 190. 000140 1 1 CALL WRITE(HOME^TERM^NUM,IBUF,@BUF^END '-' @SBUF); 191. 000152 1 1 CALL WRITE(HOME^TERM^NUM,IBUF,0); 192. 000162 1 1 193. 000162 1 1 SBUF ':=' "Please enter selection: "->@BUF^END; 194. 000173 1 1 CALL WRITEREAD (HOME^TERM^NUM,IBUF,@BUF^END '-' @SBUF, 10, NUM^READ); 195. 000206 1 1 196. 000206 1 1 SEL^INDEX ':=' SBUF FOR NUM^READ; 197. 000213 1 1 198. 000213 1 1 CALL WRITE(HOME^TERM^NUM,IBUF,0); 199. 000223 1 1 200. 000223 1 1 CASE SEL^INDEX OF 201. 000225 1 1 BEGIN 202. 000225 1 2 "1" -> COLUMN ':=' "EMPNUM "; 203. 000236 1 2 COL^SIZE := 7; 204. 000240 1 2 "2" -> COLUMN ':=' "JOBCODE "; 205. 000252 1 2 COL^SIZE := 8; 206. 000254 1 2 "3" -> COLUMN ':=' "DEPTNUM "; 207. 000266 1 2 COL^SIZE := 8; 208. 000270 1 2 END; 209. 000313 1 1 210. 000313 1 1 CALL WRITE(HOME^TERM^NUM,IBUF,0); 211. 000323 1 1 212. 000323 1 1 SBUF ':=' "Please specify the comparison criteria:" ->@BUF^END; 213. 000334 1 1 CALL WRITE(HOME^TERM^NUM,IBUF,@BUF^END '-' @SBUF); 214. 000346 1 1 SBUF ':=' " (for example: > 500, = 1000, <= 250)" -> @BUF^END; 215. 000357 1 1 CALL WRITE(HOME^TERM^NUM,IBUF,@BUF^END '-' @SBUF); 216. 000371 1 1 CALL WRITE(HOME^TERM^NUM,IBUF,0); 217. 000401 1 1 C-7

Examples of Dynamic NonStop SQL Programs Dynamic SQL Program Page 6 [1] $VOL1.S04.TALDYNEZ 1991-10-15 13:41:54 218. 000401 1 1 SBUF ':=' "Enter the comparison criteria now: "->@BUF^END; 219. 000412 1 1 CALL WRITEREAD(HOME^TERM^NUM,IBUF,@BUF^END '-' @SBUF,20, PRED^SIZE); 220. 000425 1 1 221. 000425 1 1 PREDICATE ':=' SBUF FOR PRED^SIZE; 222. 000432 1 1 223. 000432 1 1 -- Construct the SQL statement: 224. 000432 1 1 CMD^END ':=' COLUMN FOR COL^SIZE -> @CMD^END; 225. 000440 1 1 CMD^END ':=' PREDICATE FOR PRED^SIZE -> @CMD^END; 226. 000446 1 1 227. 000446 1 1 END; --get^cmd 228. 000000 0 0 229. 000000 0 0 230. 000000 0 0!-------------------------------------------------------- 231. 000000 0 0! 232. 000000 0 0! ERROR HANDLER 233. 000000 0 0! 234. 000000 0 0!-------------------------------------------------------- 235. 000000 0 0 236. 000000 0 0 PROC ERROR^HANDLER; 237. 000000 1 0 238. 000000 1 0 BEGIN 239. 000000 1 1 CALL SQLCADISPLAY( SQLCA); 240. 000013 1 1 END; 241. 000000 0 0 242. 000000 0 0 243. 000000 0 0!-------------------------------------------------------- 244. 000000 0 0! 245. 000000 0 0! MAIN PROCEDURE 246. 000000 0 0! 247. 000000 0 0!-------------------------------------------------------- 248. 000000 0 0 249. 000000 0 0 PROC DRIVER MAIN; 250. 000000 1 0 251. 000000 1 0 BEGIN 252. 000000 1 1 CALL INITIALIZER; 253. 000006 1 1 CALL MYTERM(HOME^TERM); 254. 000011 1 1 CALL OPEN(HOME^TERM, HOME^TERM^NUM); 255. 000021 1 1 256. 000021 1 1 -- Get SQL statement from the user: 257. 000021 1 1 CALL GET^CMD(CMD); 258. 000024 1 1 259. 000024 1 1 -- Compile the statement, access the SQL database, and 260. 000024 1 1 -- report the result: 261. 000024 1 1 CALL PROCESS^AND^EXECUTE(CMD); 262. 000027 1 1 263. 000027 1 1 END; C-8

Examples of Dynamic NonStop SQL Programs Detailed Dynamic SQL Program Page 7 [1] $VOL1.S04.TALDYNEZ 1991-10-15 13:41:54 BINDER AND COMPILER STATISTICS BINDER - OBJECT FILE BINDER - T9621C30 - (01NOV91) SYSTEM \SYS1 Copyright Tandem Computers Incorporated 1982-1989, 1991 Object file $VOL1.S04.TALD1O TIMESTAMP 1991-10-15 13:41:54 2 Code pages 14 Primary data words 1260 Secondary data words 64 Data pages 0 Resident code pages 1 Extended data page 1274 Top of stack location in words 1 Code segment 0 Binder Warnings 0 Binder Errors TAL - Transaction Application Language - T9250C30 - (01NOV91) Number of compiler errors = 0 Number of unsuppressed compiler warnings = 0 Number of warnings suppressed by NOWARN = 0 Maximum symbol table space used was = 28620 bytes Number of source lines = 3165 Compile cpu time = 00:00:03 Total Elapsed time = 00:00:29 Detailed Dynamic SQL Program The TALDYN program allows a user to enter any SQL statement at run time. TALDYN prepares and executes the statement in a TMF transaction. The program is independent of a specific database because it does not use database definitions. Only the dynamic SQL statement refers to a particular database. TALDYN performs these functions: 1. Declares these SQL structures: An SQLSA to determine the number of input parameters or output variables. One SQLDA to describe input parameters and another SQLDA to describe output variables (Because the program allocates memory at run time, it declares the SQLDA as a template and then allocates the actual structures dynamically when the query is run.). 2. Defines these items: A buffer to store output variables, with storage for column values of different data types. A buffer to store input parameters, with storage for parameter values of different data types. C-9

Examples of Dynamic NonStop SQL Programs Detailed Dynamic SQL Program 3. Prepares the SQL statement and assigns it a statement name (statement and cursor host variables are not used). 4. Determines the data types of the: Input parameters and moves them to the host variables of the corresponding data types Output variables and moves them to the host variables of the corresponding data types 5. Sets up the SQLDA to point to the storage for the variables referenced by the query. The storage is allocated at run time. 6. If there are parameters, uses the input SQLDA either to perform a cursor FETCH for a SELECT statement or to execute a non-select statement. To run TALDYN, you must enter the TACL ADD DEFINE commands to associate the ORDERS and ODETAIL tables with the =ORDERS and =ODETAIL DEFINE names: SET DEFINE CLASS MAP ADD DEFINE =ORDERS, FILE SALES.ORDERS ADD DEFINE =ODETAIL, FILE SALES.ODETAIL Figure C-2 shows the TALDYN output. The prompt is two greater than characters (>>). The data entered by the user is shown in bold type. A semicolon is required to terminate the input from the user. The query shown selects order numbers and customer numbers from the ORDERS table, where the order includes part number 6400. The object file name is TALDYNO. C-10

Examples of Dynamic NonStop SQL Programs Detailed Dynamic SQL Program Figure C-2. Output for the Detailed Dynamic SQL Program 10> RUN TALDYNO This is DYNAMIC SQL test. Enter SQL statement or SAME to reuse last statement or END: >>select ordernum, custnum from =orders where ordernum in (select ordernum from =odetail where partnum = 6400); ORDERS.ORDERNUM ORDERS.CUSTNUM ORDERS.ORDERNUM ORDERS.CUSTNUM ORDERS.ORDERNUM ORDERS.CUSTNUM ORDERS.ORDERNUM ORDERS.CUSTNUM End of current session 11> 200320 21 300350 543 800660 3210 400410 7654 - - - 4 row(s) selected. Enter SQL statement or SAME to reuse last statement or END: >>end; VSTC02.vsd C-11

Examples of Dynamic NonStop SQL Programs Detailed Dynamic SQL Program The TAL compiler listing for TALDYN is shown on the following pages. Page 1 [1] $VOL1.S04.TALDYN 1991-10-15 13:42:28 TAL - T9250C30 - (01NOV91) Copyright Tandem Computers Incorporated 1976, 1978, 1981-83, 1985, 1987-91 1. 000000 0 0?SQL NOWHENEVERLIST 2. 000000 0 0?SYMBOLS, INSPECT, SAVEABEND, NOMAP, NOCODE, NOGMAP, NOLMAP, DATAPAGES 64 3. 000000 0 0?SEARCH \SYS1.$SYSTEM.SYSTEM.TALLIB Search file: \SYS1.$SYSTEM.SYSTEM.TALLIB 1991-08-30 11:14:19 4. 000000 0 0 5. 000000 0 0 LITERAL NULL^ADDR = %HFFFC0000%D;! Guaranteed invalid 32-bit address. 6. 000000 0 0 LITERAL MAX^COLUMN^NAME^SIZE = 40;! Maximum size of a SQL column name. 7. 000000 0 0 LITERAL MAX^SQL^CHAR^LENGTH = 255;! Maximum length of SQL char string. 8. 000000 0 0 LITERAL MAX^SQL^STMT^LENGTH = 512;! Maximum size of SQL statement we 9. 000000 0 0! will accept in this program. 10. 000000 0 0!-------------------------------------------------------- 11. 000000 0 0! Declare SQLCA and SQLSA 12. 000000 0 0!-------------------------------------------------------- 13. 000000 0 0 14. 000000 0 0 EXEC SQL INCLUDE SQLCA; 14. 000000 0 0 EXEC SQL INCLUDE SQLCA; Source file: [2] $SYSTEM.#3192 1991-10-15 13:42:37 1. 000000 0 0 struct.sqlca; 2. 000000 0 0 BEGIN 3. 000000 0 1 STRING filler^[0:429]; 4. 000000 0 1 END; -- SQLCA Source file: [1] $VOL1.S04.TALDYN 1991-10-15 13:33:55 15. 000327 0 0 16. 000327 0 0 EXEC SQL INCLUDE SQLSA; 16. 000327 0 0 EXEC SQL INCLUDE SQLSA; Source file: [3] $SYSTEM.#3193 1991-10-15 13:42:39 1. 000327 0 0 STRUCT.sqlsa; 2. 000327 0 0 BEGIN 3. 000327 0 1 STRING eye^catcher[0:1]; 4. 000327 0 1 INT version; 5. 000327 0 1 STRUCT dml; 6. 000327 0 1 BEGIN 7. 000327 0 2 INT num^tables; 8. 000327 0 2 STRUCT stats[0:15]; 9. 000327 0 2 BEGIN 10. 000327 0 3 STRING table^name[0:23]; 11. 000327 0 3 INT(32) records^accessed; 12. 000327 0 3 INT(32) records^used; 13. 000327 0 3 INT(32) disc^reads; 14. 000327 0 3 INT(32) messages; 15. 000327 0 3 INT(32) message^bytes; 16. 000327 0 3 INT waits; 17. 000327 0 3 INT escalations; 18. 000327 0 3 STRING sqlsa^reserved[0:3]; 19. 000327 0 3 END; -- stats 20. 000327 0 2 END; -- dml 21. 000327 0 1 STRUCT prepare = dml; 22. 000327 0 1 BEGIN 23. 000327 0 2 INT input^num; 24. 000327 0 2 INT input^names^len; 25. 000327 0 2 INT output^num; 26. 000327 0 2 INT output^names^len; 27. 000327 0 2 INT name^map^len; C-12

Examples of Dynamic NonStop SQL Programs Detailed Dynamic SQL Program Page 2 [3] $SYSTEM.#3193 1991-10-15 13:42:28 28. 000327 0 2 INT sql^statement^type; 29. 000327 0 2 END; -- prepare 30. 000327 0 1 END; -- sqlsa Source file: [1] $VOL1.S04.TALDYN 1991-10-15 13:33:55 17. 001172 0 0 18. 001172 0 0!------------------------------------------------------------ 19. 001172 0 0! Declare SQLDA for input parameters and output variables. 20. 001172 0 0! 21. 001172 0 0!------------------------------------------------------------ 22. 001172 0 0 23. 001172 0 0 EXEC SQL INCLUDE SQLDA (sqlda^type, 1); 23. 001172 0 0 EXEC SQL INCLUDE SQLDA (sqlda^type, 1); Source file: [4] $SYSTEM.#3194 1991-10-15 13:42:41 1. 001172 0 0 LITERAL SQLDA^EYE^CATCHER = "D1"; 2. 001172 0 0 STRUCT sqlda^type (*) ; 3. 001172 0 0 BEGIN 4. 001172 0 1 STRING eye^catcher[0:1]; 5. 001172 0 1 INT num^entries; 6. 001172 0 1 struct sqlvar[0:0]; 7. 001172 0 1 BEGIN 8. 001172 0 2 INT data^type; 9. 001172 0 2 INT data^len; 10. 001172 0 2! fields for NUMBERS: 11. 001172 0 2! scale = data^len.<0:7> 12. 001172 0 2! length = data^len.<8:15> 13. 001172 0 2! fields for DATETIME or INTERVAL: 14. 001172 0 2! qualifier = data^len.<0:7> 15. 001172 0 2! length = data^len.<8:15> 16. 001172 0 2 INT precision; 17. 001172 0 2! fields for DATETIME or INTERVAL: 18. 001172 0 2! leading field precision = precision.<0:7> 19. 001172 0 2! fraction precision = precision.<8:15> 20. 001172 0 2 INT null^info; 21. 001172 0 2 INT(32) var^ptr; 22. 001172 0 2 INT(32) ind^ptr; 23. 001172 0 2 FIXED reserved; 24. 001172 0 2 END; 25. 001172 0 1 END; Source file: [1] $VOL1.S04.TALDYN 1991-10-15 13:33:55 24. 001172 0 0 25. 001172 0 0 EXEC SQL BEGIN DECLARE SECTION; 26. 001172 0 0 27. 001172 0 0 INT.EXT sda^i (sqlda^type);! input SQLDA pointer 28. 001172 0 0 INT.EXT sda^o (sqlda^type);! output SQLDA pointer 29. 001172 0 0 30. 001172 0 0 STRUCT names^template(*);!template for names buffer 31. 001172 0 0 begin 32. 001172 0 1 string val[0:10000]; 33. 001172 0 1 end; 34. 001172 0 0 35. 001172 0 0 INT.EXT cname^i(names^template);! input names buffer pointer 36. 001172 0 0 INT.EXT cname^o(names^template);! output names buffer pointer 37. 001172 0 0 38. 001172 0 0 EXEC SQL END DECLARE SECTION; 39. 001172 0 0 40. 001172 0 0 INT sqlcode;! Required by SQL; stores SQL error codes. 41. 001172 0 0 C-13

Examples of Dynamic NonStop SQL Programs Detailed Dynamic SQL Program Page 3 [1] $VOL1.S04.TALDYN 1991-10-15 13:42:28 42. 001172 0 0 43. 001172 0 0!-------------------------------- 44. 001172 0 0! Global declarations for displaying output. 45. 001172 0 0!-------------------------------- 46. 001172 0 0 47. 001172 0 0 LITERAL buffer^size^in^bytes = 200, 48. 001172 0 0 buffer^limit = (buffer^size^in^bytes / 2) - 1; 49. 001172 0 0 50. 001172 0 0 INT.buf[0:buffer^limit];! print buffer (word address) 51. 001336 0 0 STRING.ext sbuf;! print buffer (byte address) 52. 001336 0 0 STRING.ext next^buf; 53. 001336 0 0 INT term;! file number of home terminal 54. 001336 0 0 55. 001336 0 0 56. 001336 0 0! Small pool of memory for dynamic allocation. 57. 001336 0 0! Using DEFINEPOOL/GETPOOL for individual variables in 58. 001336 0 0! the SQL statements can be somewhat inefficient, but not seriously 59. 001336 0 0! so. It should be suitable for most users. 60. 001336 0 0! See the Guardian Procedure Calls Reference Manual for limitations. 61. 001336 0 0 62. 001336 0 0 63. 001336 0 0 LITERAL POOL^SIZE^IN^BYTES = 8192d; 64. 001336 0 0 INT.pool^head[0:18]; 65. 001361 0 0 INT.pool[0:POOL^SIZE^IN^BYTES/2d - 1d]; 66. 011361 0 0 67. 011361 0 0 68. 011361 0 0 EXEC SQL BEGIN DECLARE SECTION; 69. 011361 0 0 70. 011361 0 0 STRUCT.host1;! holds query to be executed 71. 011361 0 0 BEGIN 72. 011361 0 1 INT len; 73. 011361 0 1 STRING str[0:max^sql^stmt^length]; 74. 011361 0 1 END; 75. 011763 0 0 76. 011763 0 0 STRUCT.host2;! save copy of query for recovery via SAME 77. 011763 0 0 BEGIN 78. 011763 0 1 INT len; 79. 011763 0 1 STRING str[0:max^sql^stmt^length]; 80. 011763 0 1 END; 81. 012365 0 0 82. 012365 0 0 EXEC SQL END DECLARE SECTION; 83. 012365 0 0 84. 012365 0 0!------------------------------------------------------------ 85. 012365 0 0! Define template of TAL types which correspond to SQL types 86. 012365 0 0!------------------------------------------------------------ 87. 012365 0 0 88. 012365 0 0 STRUCT sql^types (*); 89. 012365 0 0 BEGIN 90. 012365 0 1 STRING v^char[0:max^sql^char^length]; 91. 012365 0 1 STRUCT v^varchar = v^char; 92. 012365 0 1 BEGIN 93. 012365 0 2 INT len; 94. 012365 0 2 STRING VAL[0:MAX^SQL^CHAR^LENGTH-2]; 95. 012365 0 2 END; 96. 012365 0 1 INT v^smallint = v^char; 97. 012365 0 1 INT(32) v^int = v^char; 98. 012365 0 1 FIXED v^largeint = v^char; C-14

Examples of Dynamic NonStop SQL Programs Detailed Dynamic SQL Program Page 4 [1] $VOL1.S04.TALDYN 1991-10-15 13:42:28 99. 012365 0 1 FIXED(3) v^numeric = v^char; 100. 012365 0 1 REAL v^float = v^char; 101. 012365 0 1 REAL(64) v^double = v^char; 102. 012365 0 1 STRING v^decimal[0:18] = v^char; 103. 012365 0 1 STRING v^datetime[0:25] = v^char; 104. 012365 0 1 END; 105. 012365 0 0 106. 012365 0 0 --Copy in declarations for data type literals: 107. 012365 0 0?NOLIST, SOURCE $SYSTEM.SYSTEM.TALDECS(SQLDA) 109. 012365 0 0 111. 012365 0 0 -- Copy declarations from EXTDECS file for: 112. 012365 0 0 -- ABEND, CLOSE, DEBUG, DEFINEPOOL, DNUMIN, DNUMOUT, FILEINFO, 113. 012365 0 0 -- GETPOOL, INITIALIZER, MYTERM, NUMIN, OPEN, PUTPOOL, READ, 114. 012365 0 0 -- READX, SQLCADISPLAY, STOP, WRITE, WRITEX, WRITEREAD, WRITEREADX 115. 012365 0 0 116. 012365 0 0?NOLIST, SOURCE $SYSTEM.SYSTEM.EXTDECS ( 122. 000000 0 0 123. 000000 0 0! Declare WHENEVER clause for warnings. The WHENEVER clause for errors 124. 000000 0 0! is declared just before the MAIN procedure; the reason is explained 125. 000000 0 0! with that declaration. 126. 000000 0 0 PROC sql^warning^handler; FORWARD; 127. 000000 0 0 EXEC SQL WHENEVER SQLWARNING CALL :sql^warning^handler; 128. 000000 0 0 C-15

Examples of Dynamic NonStop SQL Programs Detailed Dynamic SQL Program Page 5 [1] $VOL1.S04.TALDYN 1991-10-15 13:42:28 Output formatting stuff 130. 000000 0 0! 131. 000000 0 0! Here are a few DEFINEs to make it a little easier to format 132. 000000 0 0! and print messages. 133. 000000 0 0! 134. 000000 0 0! put a string into the line, starting at beginning of the line 135. 000000 0 0 DEFINE PUT^STR (s) = @next^buf := @sbuf; 136. 000000 0 0 next^buf ':=' s -> @next^buf #; 137. 000000 0 0 138. 000000 0 0! put a string into the line, starting after the beginning 139. 000000 0 0 DEFINE PUT^STR^MID (s) = next^buf ':=' s -> @next^buf #; 140. 000000 0 0 141. 000000 0 0! put an integer into the line 142. 000000 0 0 DEFINE PUT^INT (n) = @next^buf := @sbuf; 143. 000000 0 0 @next^buf := @next^buf + 144. 000000 0 0 $DBL(DNUMOUT(next^buf,$DBL(n),10)) #; 145. 000000 0 0 146. 000000 0 0! put an integer into the line, starting after the beginning 147. 000000 0 0 DEFINE PUT^INT^MID (n)= @next^buf := @next^buf + 148. 000000 0 0 $DBL(DNUMOUT(next^buf,$DBL(n),10)) #; 149. 000000 0 0 150. 000000 0 0! put an INT(32) into the line 151. 000000 0 0 DEFINE PUT^DBL (n) = @next^buf := @sbuf; 152. 000000 0 0 @next^buf := @next^buf + 153. 000000 0 0 $DBL(DNUMOUT(next^buf,n,10)) #; 154. 000000 0 0 155. 000000 0 0! put an INT(32) into the line, starting after the beginning 156. 000000 0 0 DEFINE PUT^DBL^MID (n) = @next^buf := @next^buf + 157. 000000 0 0 $DBL(DNUMOUT(next^buf,n,10)) #; 158. 000000 0 0 159. 000000 0 0! print the line 160. 000000 0 0 DEFINE PRINT^LINE = call WRITE(term,buf,$INT(@next^buf - @sbuf)) #; 161. 000000 0 0 162. 000000 0 0! print a blank line 163. 000000 0 0 DEFINE PRINT^BLANK^LINE = call WRITE(term,buf,0) #; 164. 000000 0 0 165. 000000 0 0 C-16

Examples of Dynamic NonStop SQL Programs Detailed Dynamic SQL Program Page 6 [1] $VOL1.S04.TALDYN 1991-10-15 13:42:28 display^result 167. 000000 0 0 PROC display^result (sqlda, cnames); 168. 000000 1 0 169. 000000 1 0!*********************************************************! 170. 000000 1 0! PROC display^result! 171. 000000 1 0! displays the current row of a SELECT statement! 172. 000000 1 0!*********************************************************! 173. 000000 1 0 174. 000000 1 0 STRUCT.ext sqlda(sqlda^type);!in: Output SQLDA 175. 000000 1 0 STRING.ext cnames;!in: contains column names of table 176. 000000 1 0 177. 000000 1 0 BEGIN 178. 000000 1 1 INT length; 179. 000000 1 1 INT nameix;! index into column names string 180. 000000 1 1 INT output^num;! number of columns to be output 181. 000000 1 1 INT i; 182. 000000 1 1 INT.EXT ind^ptr^; 183. 000000 1 1 INT.EXT param^ (sql^types); 184. 000000 1 1 INT datalen;! length of column value 185. 000000 1 1 186. 000000 1 1 -- 187. 000000 1 1 -- Get number of columns to output in current row. 188. 000000 1 1 -- 189. 000000 1 1 190. 000000 1 1 output^num := sqlda.num^entries; 191. 000007 1 1 192. 000007 1 1 nameix := 1; 193. 000011 1 1 194. 000011 1 1 FOR i := 0 TO (output^num - 1) DO 195. 000013 1 1 BEGIN 196. 000013 1 2 -- 197. 000013 1 2 -- Get a column name (which are stored sequentially in array; 198. 000013 1 2 -- each column name is preceded in this array by its length) 199. 000013 1 2 -- and blank pad to 40 characters. 200. 000013 1 2 -- 201. 000013 1 2 @next^buf := @sbuf; 202. 000015 1 2 next^buf ':=' MAX^COLUMN^NAME^SIZE * [" "] & " "; 203. 000041 1 2 IF cnames[nameix] = 0 THEN 204. 000050 1 2 next^buf ':=' ["(EXPR)"] -- Use (EXPR) for the column name if no 205. 000050 1 2 -- column name appears, as SQLCI does. 206. 000050 1 2 ELSE 207. 000063 1 2 next^buf ':=' cnames[nameix+1] FOR cnames[nameix]; 208. 000077 1 2 @next^buf := @next^buf[max^column^name^size+1]; 209. 000104 1 2 210. 000104 1 2 nameix := cnames[nameix] + 2 + nameix; 211. 000115 1 2 212. 000115 1 2 @param^ := sqlda.sqlvar[i].var^ptr; 213. 000130 1 2 @ind^ptr^ := sqlda.sqlvar[i].ind^ptr; 214. 000143 1 2 datalen := sqlda.sqlvar[i].data^len; 215. 000156 1 2 216. 000156 1 2 IF sqlda.sqlvar[i].null^info = -1 AND ind^ptr^ = -1 THEN 217. 000176 1 2 BEGIN 218. 000176 1 3 PUT^STR^MID ("? (NULL)"); 219. 000214 1 3 END ELSE BEGIN 220. 000215 1 3 CASE sqlda.sqlvar[i].data^type OF 221. 000230 1 3 BEGIN 222. 000230 1 4!------------------------------------------- 223. 000230 1 4! data type is character; display first 38 characaters C-17

Examples of Dynamic NonStop SQL Programs Detailed Dynamic SQL Program Page 7 [1] $VOL1.S04.TALDYN 1991-10-15 13:42:28 display^result 224. 000230 1 4!------------------------------------------- 225. 000230 1 4 _SQLDT_ASCII_F, 226. 000230 1 4 _SQLDT_ASCII_F_UP -> 227. 000230 1 4 PUT^STR^MID (param^.v^char for $MIN(38,datalen)); 228. 000243 1 4 229. 000243 1 4!------------------------------------------- 230. 000243 1 4! data type is varchar 231. 000243 1 4!------------------------------------------- 232. 000243 1 4 _SQLDT_ASCII_V, 233. 000244 1 4 _SQLDT_ASCII_V_UP -> 234. 000244 1 4 PUT^STR^MID (param^.v^varchar.val 235. 000244 1 4 FOR $MIN(38,param^.v^varchar.len)); 236. 000263 1 4 237. 000263 1 4!------------------------------------------- 238. 000263 1 4! data type is smallint 239. 000263 1 4!------------------------------------------- 240. 000263 1 4 _SQLDT_16BIT_S -> 241. 000264 1 4 if param^.v^smallint >= 0 then 242. 000270 1 4 begin 243. 000270 1 5 PUT^INT^MID (param^.v^smallint); 244. 000311 1 5 end else begin 245. 000312 1 5 PUT^STR^MID ("-"); 246. 000326 1 5 PUT^INT^MID (-param^.v^smallint); 247. 000350 1 5 end; 248. 000350 1 4 249. 000350 1 4 _SQLDT_16BIT_U -> 250. 000351 1 4 PUT^DBL^MID ($UDBL(param^.v^smallint)); 251. 000371 1 4 252. 000371 1 4!------------------------------------------- 253. 000371 1 4! data type is integer 254. 000371 1 4!------------------------------------------- 255. 000371 1 4 _SQLDT_32BIT_S -> 256. 000372 1 4 if param^.v^int >= 0D then 257. 000377 1 4 begin 258. 000377 1 5 PUT^DBL^MID (param^.v^int); 259. 000422 1 5 end else begin 260. 000424 1 5 PUT^STR^MID ("-"); 261. 000440 1 5 PUT^DBL^MID (-param^.v^int); 262. 000461 1 5 end; 263. 000461 1 4 264. 000461 1 4 _SQLDT_32BIT_U -> 265. 000462 1 4 PUT^DBL^MID (param^.v^int); 266. 000502 1 4 267. 000502 1 4!------------------------------------------- 268. 000502 1 4! data type is datetime or interval 269. 000502 1 4!------------------------------------------- 270. 000502 1 4 _SQLDT_DATETIME.. _SQLDT_INT_D_F -> 271. 000503 1 4 PUT^STR^MID (param^.v^datetime FOR datalen.<8:15>); 272. 000512 1 4 273. 000512 1 4 OTHERWISE -> 274. 000513 1 4 PUT^STR^MID ("This data type is not supported: "); 275. 000527 1 4 PUT^INT^MID (sqlda.sqlvar[i].data^type); 276. 000560 1 4 277. 000560 1 4 END;!end of case 278. 001117 1 3 END;! end of if 279. 001117 1 2 280. 001117 1 2 PRINT^LINE; C-18

Examples of Dynamic NonStop SQL Programs Detailed Dynamic SQL Program Page 8 [1] $VOL1.S04.TALDYN 1991-10-15 13:42:28 display^result 281. 001132 1 2 282. 001132 1 2 END;! end FOR loop 283. 001141 1 1 284. 001141 1 1! blank line to separate rows 285. 001141 1 1 PRINT^BLANK^LINE; 286. 001151 1 1 END;! end of proc display^result 287. 000000 0 0 288. 000000 0 0 289. 000000 0 0 C-19

Examples of Dynamic NonStop SQL Programs Detailed Dynamic SQL Program Page 9 [1] $VOL1.S04.TALDYN 1991-10-15 13:42:28 request^invars 291. 000000 0 0 INT PROC request^invars (sqlda, cnames); 292. 000000 1 0 293. 000000 1 0!******************************************************! 294. 000000 1 0! PROC request^invars:! 295. 000000 1 0! This proc prompts for a value for each input parameter.! 296. 000000 1 0!! 297. 000000 1 0! Returns 0 if successful, -1 otherwise! 298. 000000 1 0!*******************************************************! 299. 000000 1 0 300. 000000 1 0 STRUCT.EXT sqlda(sqlda^type);!in: Input SQLDA 301. 000000 1 0 STRING.EXT cnames;!in: contains parameter names 302. 000000 1 0 303. 000000 1 0 BEGIN 304. 000000 1 1 305. 000000 1 1 STRING.param^name[0:MAX^COLUMN^NAME^SIZE];! current parameter name 306. 000000 1 1 INT namelen;! length of current parameter name 307. 000000 1 1 INT nameix;! index into parameter names string 308. 000000 1 1 INT input^num;! number of parameters to be obtained 309. 000000 1 1 INT count^read; 310. 000000 1 1 INT i; 311. 000000 1 1 INT.EXT param^ (sql^types);! pointer to parameter value 312. 000000 1 1 INT maxlen;! maximum length of string parameter 313. 000000 1 1 INT.EXT ind^;! pointer used to set null indicator 314. 000000 1 1 INT(32) temp;! hold result from DNUMIN for 16-bit case 315. 000000 1 1! (NUMIN will not accept an extended address) 316. 000000 1 1 317. 000000 1 1 PRINT^BLANK^LINE; 318. 000015 1 1 PUT^STR ("Please provide data for input params"); 319. 000033 1 1 PRINT^LINE; 320. 000046 1 1 321. 000046 1 1 PUT^STR ("------------------------------------"); 322. 000064 1 1 PRINT^LINE; 323. 000077 1 1 324. 000077 1 1 PRINT^BLANK^LINE; 325. 000107 1 1 326. 000107 1 1 -- 327. 000107 1 1 -- Get number of input variables. 328. 000107 1 1 -- 329. 000107 1 1 330. 000107 1 1 input^num := sqlda.num^entries; 331. 000115 1 1 332. 000115 1 1 nameix := 1; 333. 000117 1 1 334. 000117 1 1 335. 000117 1 1 FOR i := 0 TO (input^num - 1) DO 336. 000121 1 1 BEGIN 337. 000121 1 2! 338. 000121 1 2! Get a parameter name 339. 000121 1 2! 340. 000121 1 2 341. 000121 1 2 namelen := cnames[nameix]; 342. 000127 1 2 IF namelen THEN -- Is the parameter named? 343. 000131 1 2 param^name ':=' cnames[nameix+1] FOR namelen; 344. 000142 1 2 345. 000142 1 2 nameix := cnames[nameix] + 2 + nameix; 346. 000153 1 2 347. 000153 1 2!**********************************************************! C-20

Examples of Dynamic NonStop SQL Programs Detailed Dynamic SQL Program Page 10 [1] $VOL1.S04.TALDYN 1991-10-15 13:42:28 request^invars 348. 000153 1 2! Request input value based on data type! 349. 000153 1 2!***************************************************! 350. 000153 1 2 351. 000153 1 2 @param^ := sqlda.sqlvar[i].var^ptr;! pointer to storage for current 352. 000166 1 2! parameter 353. 000166 1 2 maxlen := sqlda.sqlvar[i].data^len; 354. 000201 1 2 355. 000201 1 2 CASE sqlda.sqlvar[i].data^type OF 356. 000214 1 2 BEGIN 357. 000214 1 3 _SQLDT_ASCII_F, 358. 000214 1 3 _SQLDT_ASCII_F_UP -> 359. 000214 1 3 PUT^STR ("Please enter max "); 360. 000232 1 3 PUT^INT^MID (maxlen); 361. 000252 1 3 PUT^STR^MID (" characters"); 362. 000266 1 3 if namelen then 363. 000270 1 3 begin 364. 000270 1 4 PUT^STR^MID (" for " & param^name for namelen); 365. 000311 1 4 end; 366. 000311 1 3 PUT^STR^MID (": "); 367. 000327 1 3 PRINT^LINE; 368. 000342 1 3 369. 000342 1 3 param^.v^char ':=' " " & param^.v^char for maxlen-1; 370. 000361 1 3 call READX(term,param^.v^char,maxlen); 371. 000372 1 3 372. 000372 1 3 IF (sqlda.sqlvar[i].null^info = -1) AND 373. 000372 1 3 (param^.v^char = "?") THEN 374. 000414 1 3 begin! got a null value; set null indicator 375. 000414 1 4 @ind^ := sqlda.sqlvar[i].ind^ptr; 376. 000427 1 4 ind^ := -1; 377. 000432 1 4 end; 378. 000432 1 3 379. 000432 1 3 _SQLDT_ASCII_V, 380. 000433 1 3 _SQLDT_ASCII_V_UP -> 381. 000433 1 3 PUT^STR ("Please enter max "); 382. 000451 1 3 PUT^INT^MID (maxlen); 383. 000471 1 3 PUT^STR^MID(" characters"); 384. 000505 1 3 if namelen then 385. 000507 1 3 begin 386. 000507 1 4 PUT^STR^MID (" for " & param^name for namelen); 387. 000530 1 4 end; 388. 000530 1 3 PUT^STR^MID (": "); 389. 000544 1 3 PRINT^LINE; 390. 000557 1 3 391. 000557 1 3 callreadx(term,param^.v^varchar.val,maxlen, param^.v^varchar.len); 392. 000574 1 3 393. 000574 1 3 IF (sqlda.sqlvar[i].null^info = -1) AND 394. 000574 1 3 (param^.v^varchar.val = "?") THEN 395. 000614 1 3 begin! got a null value; set null indicator 396. 000614 1 4 @ind^ := sqlda.sqlvar[i].ind^ptr; 397. 000627 1 4 ind^ := -1; 398. 000634 1 4 end; 399. 000634 1 3 400. 000634 1 3 _SQLDT_16BIT_S, 401. 000635 1 3 _SQLDT_16BIT_U, 402. 000635 1 3 _SQLDT_32BIT_S, 403. 000635 1 3 _SQLDT_32BIT_U -> 404. 000635 1 3 PUT^STR ("Please enter a numeric value"); C-21

Examples of Dynamic NonStop SQL Programs Detailed Dynamic SQL Program Page 11 [1] $VOL1.S04.TALDYN 1991-10-15 13:42:28 request^invars 405. 000653 1 3 if namelen then 406. 000655 1 3 begin 407. 000655 1 4 PUT^STR^MID (" for " & param^name for namelen); 408. 000676 1 4 end; 409. 000676 1 3 PUT^STR^MID (": "); 410. 000712 1 3 call WRITEREAD(term,buf,$INT(@next^buf - @sbuf),25,count^read); 411. 000726 1 3 sbuf[count^read] := 0;! terminator for DNUMIN and scan 412. 000731 1 3 @next^buf := @sbuf; 413. 000733 1 3 while next^buf <> 0 and next^buf = " " do @next^buf := @next^buf[1]; 414. 000750 1 3 415. 000750 1 3 IF (sqlda.sqlvar[i].null^info = -1) AND 416. 000750 1 3 (next^buf = "?") THEN 417. 000770 1 3 begin! got a null value; set null indicator 418. 000770 1 4 @ind^ := sqlda.sqlvar[i].ind^ptr; 419. 001003 1 4 ind^ := -1; 420. 001006 1 4 421. 001006 1 4 end else begin 422. 001007 1 4 423. 001007 1 4 CASE sqlda.sqlvar[i].data^type OF 424. 001022 1 4 begin 425. 001022 1 5 _SQLDT_16BIT_S, 426. 001022 1 5 _SQLDT_16BIT_U -> 427. 001022 1 5 call DNUMIN(next^buf,temp,10); 428. 001036 1 5! Problems: 429. 001036 1 5! Unsigned should not allow minus sign. 430. 001036 1 5! Should check status for error. 431. 001036 1 5! Should check that whole string was consumed. 432. 001036 1 5! Should check that value fits in 16-bits 433. 001036 1 5 param^.v^smallint := $INT(temp); 434. 001042 1 5 _SQLDT_32BIT_S, 435. 001043 1 5 _SQLDT_32BIT_U -> 436. 001043 1 5 call DNUMIN(next^buf,param^.v^int,10); 437. 001055 1 5! This isn't completely right for unsigned 438. 001055 1 5! should check status for error and should 439. 001055 1 5! check that whole string was consumed. 440. 001055 1 5 end; 441. 001101 1 4 end; 442. 001101 1 3 443. 001101 1 3 _SQLDT_DATETIME -> 444. 001102 1 3 PUT^STR ("Please enter a date/time value"); 445. 001120 1 3 if namelen then 446. 001122 1 3 begin 447. 001122 1 4 PUT^STR^MID (" for " & param^name for namelen); 448. 001143 1 4 end; 449. 001143 1 3 PUT^STR^MID (": "); 450. 001157 1 3 PRINT^LINE; 451. 001172 1 3 param^.v^datetime ':=' " " & param^.v^datetime 452. 001172 1 3 for $OCCURS(param^.v^datetime)-1; 453. 001210 1 3 call READX (term, param^.v^datetime, $OCCURS (param^.v^datetime)); 454. 001221 1 3 455. 001221 1 3 IF (sqlda.sqlvar[i].null^info = -1) AND 456. 001221 1 3 (param^.v^datetime = "?") THEN 457. 001241 1 3 begin! got a null value; set null indicator 458. 001241 1 4 @ind^ := sqlda.sqlvar[i].ind^ptr; 459. 001254 1 4 ind^ := -1; 460. 001257 1 4 end; 461. 001257 1 3 C-22

Examples of Dynamic NonStop SQL Programs Detailed Dynamic SQL Program Page 12 [1] $VOL1.S04.TALDYN 1991-10-15 13:42:28 request^invars 462. 001257 1 3 _SQLDT_INT_Y_Y.. _SQLDT_INT_D_F -> 463. 001260 1 3 PUT^STR ("Please enter a date/time interval"); 464. 001276 1 3 if namelen then 465. 001302 1 3 begin 466. 001302 1 4 PUT^STR^MID (" for " & param^name for namelen); 467. 001323 1 4 end; 468. 001323 1 3 PUT^STR^MID (": "); 469. 001337 1 3 PRINT^LINE; 470. 001352 1 3 param^.v^datetime ':=' " " & param^.v^datetime 471. 001352 1 3 for $OCCURS(param^.v^datetime)-1; 472. 001370 1 3 call READX(term,param^.v^datetime,$OCCURS (param^.v^datetime)); 473. 001401 1 3 474. 001401 1 3 IF (sqlda.sqlvar[i].null^info = -1) AND 475. 001401 1 3 (param^.v^datetime = "?") THEN 476. 001421 1 3 begin! got a null value; set null indicator 477. 001421 1 4 @ind^ := sqlda.sqlvar[i].ind^ptr; 478. 001434 1 4 ind^ := -1; 479. 001437 1 4 end; 480. 001437 1 3 481. 001437 1 3 OTHERWISE -> 482. 001440 1 3 PUT^STR ("This data type is not supported: "); 483. 001456 1 3 PUT^INT^MID(sqlda.sqlvar[i].data^type); 484. 001507 1 3 PRINT^LINE; 485. 001522 1 3 END;!end of case 486. 002063 1 2 487. 002063 1 2 END;!for 488. 002072 1 1 489. 002072 1 1 return 0; 490. 002074 1 1 END;! end of proc request^invars 491. 000000 0 0 492. 000000 0 0 493. 000000 0 0 C-23

Examples of Dynamic NonStop SQL Programs Detailed Dynamic SQL Program Page 13 [1] $VOL1.S04.TALDYN 1991-10-15 13:42:28 read^query 495. 000000 0 0 INT PROC read^query ; 496. 000000 1 0 497. 000000 1 0!*********************************************************! 498. 000000 1 0! PROC read^query! 499. 000000 1 0! reads in a complete SQL statement from the input file.! 500. 000000 1 0! A SQL statement is terminated by putting a ";" at! 501. 000000 1 0! the end of a line.! 502. 000000 1 0!**********************************************************! 503. 000000 1 0 504. 000000 1 0 BEGIN 505. 000000 1 1 INT count^read;! number of bytes read 506. 000000 1 1 INT i;! index variable 507. 000000 1 1 508. 000000 1 1 host1.len := 0; 509. 000003 1 1 host1.str := 0; 510. 000010 1 1 511. 000010 1 1 PRINT^BLANK^LINE; 512. 000020 1 1 513. 000020 1 1 PUT^STR ("Enter SQL statement or SAME to reuse last statement or END:"); 514. 000036 1 1 PRINT^LINE; 515. 000051 1 1 516. 000051 1 1! 517. 000051 1 1! Loop until an entire SQL statement has been found. 518. 000051 1 1! 519. 000051 1 1 520. 000051 1 1 while host1.str[host1.len-1] <> ";" 521. 000051 1 1 and host1.len < MAX^SQL^STMT^LENGTH do 522. 000066 1 1 begin 523. 000066 1 2 host1.str[host1.len] ':=' ">>"; 524. 000102 1 2 call WRITEREADX(term,host1.str[host1.len],2, 525. 000102 1 2 MAX^SQL^STMT^LENGTH-host1.len,count^read); 526. 000131 1 2 if count^read > 0 then 527. 000134 1 2 begin 528. 000134 1 3 while host1.str[host1.len+count^read-1] = " " do! trim trailing blanks 529. 000147 1 3 count^read := count^read - 1; 530. 000152 1 3 host1.len := host1.len + count^read; 531. 000154 1 3 end; 532. 000154 1 2 end; 533. 000155 1 1 534. 000155 1 1! Drop the semicolon terminator 535. 000155 1 1 536. 000155 1 1 host1.len := host1.len - 1; 537. 000157 1 1 538. 000157 1 1! Note: to preserve simplicity, this program does only skeleton 539. 000157 1 1! checking on the contents of the input string. Because the 540. 000157 1 1! same buffer is used for the SQL statement and for the exit/repeat 541. 000157 1 1! commands, we cannot UPSHIFT before checking the string. Actual 542. 000157 1 1! programs would copy the input string into a separate buffer, loop 543. 000157 1 1! through the string, and check the contents for correctness. 544. 000157 1 1 545. 000157 1 1 if host1.str = "E" or host1.str = "e" then return -1; 546. 000175 1 1 547. 000175 1 1 if host1.str = "SAME" or host1.str = "same" then 548. 000223 1 1 begin 549. 000223 1 2 host1.str ':=' host2.str for host2.len bytes;! retrieve saved query 550. 000233 1 2 host1.len := host2.len; 551. 000235 1 2 PRINT^BLANK^LINE; C-24

Examples of Dynamic NonStop SQL Programs Detailed Dynamic SQL Program Page 14 [1] $VOL1.S04.TALDYN 1991-10-15 13:42:28 read^query 552. 000245 1 2 PUT^STR ("Re-executing query >> "); 553. 000263 1 2 PRINT^LINE; 554. 000276 1 2 call WRITEX(term,host1.str,host1.len); 555. 000312 1 2 556. 000312 1 2 end else begin 557. 000313 1 2 558. 000313 1 2 host2.str ':=' host1.str for host1.len bytes;! save query for reuse 559. 000323 1 2 host2.len := host1.len; 560. 000325 1 2 end; 561. 000325 1 1 562. 000325 1 1 return 0; 563. 000327 1 1 END;!end of proc read^query 564. 000000 0 0 565. 000000 0 0 566. 000000 0 0 567. 000000 0 0 C-25

Examples of Dynamic NonStop SQL Programs Detailed Dynamic SQL Program Page 15 [1] $VOL1.S04.TALDYN 1991-10-15 13:42:28 adjust^sqlda^scale^types 569. 000000 0 0 PROC adjust^sqlda^scale^types(sqlda); 570. 000000 1 0 571. 000000 1 0!******************************************************! 572. 000000 1 0! PROC adjust^sqlda^scale^types:! 573. 000000 1 0! This function takes an SQLDA as a parameter and! 574. 000000 1 0! adjusts the recommended (by SQL) data types and! 575. 000000 1 0! scales to what TAL supports.! 576. 000000 1 0!! 577. 000000 1 0! Adjusting for supported data types involves modifying! 578. 000000 1 0! the data^len and data^type of the SQLVAR entry to! 579. 000000 1 0! reflect the data attributes that TAL can support.! 580. 000000 1 0!! 581. 000000 1 0! For example, an input parameter or output variable with! 582. 000000 1 0! data^type = _SQLDT_DEC_LSS and! 583. 000000 1 0! data^len = 7 (assuming scale = 0)! 584. 000000 1 0! can be modified to have! 585. 000000 1 0! data^type = _SQLDT_32BIT_S and! 586. 000000 1 0! data^len = 4.! 587. 000000 1 0!! 588. 000000 1 0! Independently of the data type change, the scale is! 589. 000000 1 0! set to 0. This will cause the TAL program to deal! 590. 000000 1 0! only with the integer part of the value. More! 591. 000000 1 0! sophisticated programs could note the scale value! 592. 000000 1 0! from the SQLDA and take it into account in their! 593. 000000 1 0! computations.! 594. 000000 1 0!! 595. 000000 1 0! Although TAL does support scaled values in FIXED! 596. 000000 1 0! variables, there are no convenient formatting! 597. 000000 1 0! procedures for FIXED values, so this program does! 598. 000000 1 0! not used FIXED data.! 599. 000000 1 0!! 600. 000000 1 0!*******************************************************! 601. 000000 1 0 602. 000000 1 0 STRUCT.ext sqlda (sqlda^type);! IN -- pointer to the SQLDA 603. 000000 1 0 604. 000000 1 0 BEGIN 605. 000000 1 1 INT i; 606. 000000 1 1 607. 000000 1 1 FOR i := 0 TO sqlda.num^entries-1 DO 608. 000003 1 1 BEGIN 609. 000003 1 2 CASE sqlda.sqlvar[i].data^type OF 610. 000016 1 2 BEGIN 611. 000016 1 3 _SQLDT_16BIT_S,! SMALLINT 612. 000016 1 3 _SQLDT_16BIT_U,! UNSIGNED SMALLINT 613. 000016 1 3 _SQLDT_32BIT_S,! INTEGER 614. 000016 1 3 _SQLDT_32BIT_U ->! UNSIGNED INTEGER 615. 000016 1 3! set scale to 0 616. 000016 1 3 sqlda.sqlvar[i].data^len.<0:7> := 0; 617. 000031 1 3 618. 000031 1 3 _SQLDT_64BIT_S ->! LARGEINT 619. 000032 1 3! set scale to 0 and change type to 32-bit integer 620. 000032 1 3 sqlda.sqlvar[i].data^len.<0:7> := 0; 621. 000045 1 3 sqlda.sqlvar[i].data^type := _SQLDT_32BIT_S; 622. 000060 1 3 sqlda.sqlvar[i].data^len.<8:15> := 4;! length of 32 bits 623. 000074 1 3 624. 000074 1 3 _SQLDT_DEC_U,! DECIMAL unsigned 625. 000075 1 3 _SQLDT_DEC_LSS,! DECIMAL LSS C-26

Examples of Dynamic NonStop SQL Programs Detailed Dynamic SQL Program Page 16 [1] $VOL1.S04.TALDYN 1991-10-15 13:42:28 adjust^sqlda^scale^types 626. 000075 1 3 _SQLDT_DEC_LSE,! DECIMAL LSE 627. 000075 1 3 _SQLDT_DEC_TSS,! DECIMAL TSS 628. 000075 1 3 _SQLDT_DEC_TSE ->! DECIMAL TSE 629. 000075 1 3! change DECIMAL type to 32-bit integer and set scale to 0 630. 000075 1 3 sqlda.sqlvar[i].data^len.<0:7> := 0; 631. 000110 1 3 sqlda.sqlvar[i].data^type := _SQLDT_32BIT_S; 632. 000123 1 3 sqlda.sqlvar[i].data^len.<8:15> := 4;! length of 32 bits 633. 000137 1 3 634. 000137 1 3 otherwise -> ;! nothing to do for other types 635. 000140 1 3 end; 636. 000206 1 2 end; 637. 000221 1 1 END;! of proc adjust^sqlda^scale^types 638. 000000 0 0 639. 000000 0 0 640. 000000 0 0 641. 000000 0 0 C-27

Examples of Dynamic NonStop SQL Programs Detailed Dynamic SQL Program Page 17 [1] $VOL1.S04.TALDYN 1991-10-15 13:42:28 setupvarbuffers 643. 000000 0 0 INT PROC setupvarbuffers(sqlda); 644. 000000 1 0 645. 000000 1 0!********************************************************! 646. 000000 1 0! PROC setupvarbuffers:! 647. 000000 1 0! This function takes an SQLDA as a parameter and! 648. 000000 1 0! allocates the data and indicator value buffers.! 649. 000000 1 0! For each sqlvar, var^ptr is set to point to the! 650. 000000 1 0! data buffer and if null^info is set, ind^ptr is! 651. 000000 1 0! set to point to the indicator value.! 652. 000000 1 0!! 653. 000000 1 0! The sqlda is also changed by altering unsupported! 654. 000000 1 0! data types to the nearest equivalent data types! 655. 000000 1 0! and by setting the scale information to 0.! 656. 000000 1 0!! 657. 000000 1 0! sqlda.num^entries is assumed to have a valid value.! 658. 000000 1 0!! 659. 000000 1 0! Returns: 0 if successful! 660. 000000 1 0! -1 if failure! 661. 000000 1 0!! 662. 000000 1 0!********************************************************! 663. 000000 1 0 664. 000000 1 0 STRUCT.ext sqlda (sqlda^type);! IN -- pointer to the SQLDA 665. 000000 1 0 666. 000000 1 0 BEGIN 667. 000000 1 1 INT i; 668. 000000 1 1 INT.EXT ind^ptr^;! temporary pointer for initializing IND^PTR 669. 000000 1 1! to 0 670. 000000 1 1 INT mem^reqd; 671. 000000 1 1 672. 000000 1 1!********************************************************! 673. 000000 1 1! Handle unsupported types; set scale information to 0.! 674. 000000 1 1!********************************************************! 675. 000000 1 1 call adjust^sqlda^scale^types(sqlda); 676. 000004 1 1 677. 000004 1 1 FOR i := 0 TO sqlda.num^entries-1 DO 678. 000006 1 1 BEGIN 679. 000006 1 2!***************************************************! 680. 000006 1 2! Determine the amount of memory needed by this entry's data type.! 681. 000006 1 2!******************************************************! 682. 000006 1 2 CASE sqlda.sqlvar[i].data^type OF 683. 000021 1 2 BEGIN 684. 000021 1 3 _SQLDT_ASCII_F,! CHAR datatype 685. 000021 1 3 _SQLDT_ASCII_F_UP -> 686. 000021 1 3 mem^reqd := sqlda.sqlvar[i].data^len; 687. 000034 1 3 _SQLDT_ASCII_V,! VARCHAR 688. 000035 1 3 _SQLDT_ASCII_V_UP -> 689. 000035 1 3 mem^reqd := sqlda.sqlvar[i].data^len + 2; 690. 000051 1 3 _SQLDT_16BIT_S,! SMALLINT 691. 000052 1 3 _SQLDT_16BIT_U,! UNSIGNED SMALLINT 692. 000052 1 3 _SQLDT_32BIT_S,! INTEGER 693. 000052 1 3 _SQLDT_32BIT_U,! UNSIGNED INTEGER 694. 000052 1 3 _SQLDT_64BIT_S,! LARGEINT 695. 000052 1 3 _SQLDT_REAL,! REAL 696. 000052 1 3 _SQLDT_DOUBLE ->! DOUBLE PRECISION 697. 000052 1 3 mem^reqd := sqlda.sqlvar[i].data^len.<8:15>; 698. 000066 1 3 _SQLDT_DEC_U,! DECIMAL unsigned 699. 000067 1 3 _SQLDT_DEC_LSS,! DECIMAL LSS C-28

Examples of Dynamic NonStop SQL Programs Detailed Dynamic SQL Program Page 18 [1] $VOL1.S04.TALDYN 1991-10-15 13:42:28 setupvarbuffers 700. 000067 1 3 _SQLDT_DEC_LSE,! DECIMAL LSE 701. 000067 1 3 _SQLDT_DEC_TSS,! DECIMAL TSS 702. 000067 1 3 _SQLDT_DEC_TSE ->! DECIMAL TSE 703. 000067 1 3 mem^reqd := sqlda.sqlvar[i].data^len.<8:15>; 704. 000103 1 3 _SQLDT_DATETIME.. _SQLDT_INT_D_F ->! Date-time 705. 000104 1 3 mem^reqd := sqlda.sqlvar[i].data^len.<8:15>; 706. 000120 1 3 OTHERWISE -> 707. 000121 1 3 PUT^STR ("This data type is not supported: "); 708. 000137 1 3 PUT^INT^MID (sqlda.sqlvar[i].data^len); 709. 000170 1 3 PRINT^LINE; 710. 000203 1 3 return -1; 711. 000210 1 3 END;!end of case 712. 000550 1 2 713. 000550 1 2!*******************************************************! 714. 000550 1 2! Allocate memory for the data value and assign the byte address! 715. 000550 1 2! of the data buffer to var^ptr of sqlvar[i].! 716. 000550 1 2!*******************************************************! 717. 000550 1 2 sqlda.sqlvar[i].var^ptr := GETPOOL(pool^head, $DBL(mem^reqd)); 718. 000571 1 2 IF sqlda.sqlvar[i].var^ptr = -1d THEN 719. 000606 1 2 BEGIN 720. 000606 1 3 PUT^STR ("Getpool memory management error"); 721. 000624 1 3 PRINT^LINE; 722. 000637 1 3 CALL ABEND; 723. 000644 1 3 END; 724. 000644 1 2 725. 000644 1 2!*******************************************************! 726. 000644 1 2! If null^info is set, allocate a buffer for the indicator value! 727. 000644 1 2! and assign its address to ind^ptr of sqlvar[i].! 728. 000644 1 2!*******************************************************! 729. 000644 1 2 IF sqlda.sqlvar[i].null^info = -1 THEN 730. 000660 1 2 BEGIN 731. 000660 1 3 sqlda.sqlvar[i].ind^ptr := GETPOOL(pool^head, $DBL(2)); 732. 000701 1 3 IF sqlda.sqlvar[i].ind^ptr = -1d THEN 733. 000716 1 3 BEGIN 734. 000716 1 4 PUT^STR ("Getpool memory management error"); 735. 000734 1 4 PRINT^LINE; 736. 000747 1 4 CALL ABEND; 737. 000754 1 4 END; 738. 000754 1 3 @ind^ptr^ := sqlda.sqlvar[i].ind^ptr; 739. 000767 1 3 ind^ptr^ := 0;! set memory IND^PTR points at to 0 740. 000771 1 3 END; 741. 000771 1 2 END;! end of for 742. 001004 1 1 743. 001004 1 1 return 0; 744. 001006 1 1 END;! of proc setupvarbuffers 745. 000000 0 0 746. 000000 0 0 747. 000000 0 0 748. 000000 0 0 C-29

Examples of Dynamic NonStop SQL Programs Detailed Dynamic SQL Program Page 19 [1] $VOL1.S04.TALDYN 1991-10-15 13:42:28 allocate^sqlda 750. 000000 0 0 INT(32) PROC allocate^sqlda (num^entries); 751. 000000 1 0 752. 000000 1 0!******************************************************! 753. 000000 1 0! PROC allocate^sqlda:! 754. 000000 1 0! This proc allocates an sqlda structure with num^entries entries.! 755. 000000 1 0! It also initializes the sqlda and the sqlvars.! 756. 000000 1 0! A names buffer is also allocated.! 757. 000000 1 0!! 758. 000000 1 0! Returns: address of the sqlda created if successful! 759. 000000 1 0! NULL^ADDR if unsuccessful! 760. 000000 1 0!******************************************************! 761. 000000 1 0 762. 000000 1 0 INT num^entries;! IN -- number of parameters or columns 763. 000000 1 0 BEGIN 764. 000000 1 1 INT.EXT sqlda(sqlda^type);! sqlda pointer to return 765. 000000 1 1 INT mem^reqd;! gets amount of space needed for the sqlda 766. 000000 1 1 INT i;! loop counter 767. 000000 1 1 768. 000000 1 1! Return null if zero entries requested 769. 000000 1 1 770. 000000 1 1 if num^entries = 0 then return NULL^ADDR; 771. 000006 1 1 772. 000006 1 1! Compute amount of memory needed for the sqlda 773. 000006 1 1 774. 000006 1 1 mem^reqd := $LEN(sqlda^type) + (num^entries- 1)*$LEN(sqlda^type.sqlvar); 775. 000015 1 1 776. 000015 1 1! Allocate the space. If error allocating, return null address. 777. 000015 1 1 778. 000015 1 1 @sqlda := GETPOOL(pool^head,$DBL(mem^reqd)); 779. 000025 1 1 if @sqlda = -1D then return NULL^ADDR; 780. 000034 1 1 781. 000034 1 1! Initialize the sqlda eye catcher and number of entries. 782. 000034 1 1 783. 000034 1 1 sqlda.eye^catcher ':=' SQLDA^EYE^CATCHER; 784. 000046 1 1 sqlda.num^entries := num^entries; 785. 000051 1 1 786. 000051 1 1! Initialize the pointers to the variable value and to the 787. 000051 1 1! null indicator in each sqlvar entry to the null address. 788. 000051 1 1 789. 000051 1 1 for i := 0 to num^entries-1 do 790. 000053 1 1 begin 791. 000053 1 2 sqlda.sqlvar[i].var^ptr := NULL^ADDR; 792. 000067 1 2 sqlda.sqlvar[i].ind^ptr := NULL^ADDR; 793. 000103 1 2 end; 794. 000112 1 1 795. 000112 1 1! Return the address of the sqlda allocated. 796. 000112 1 1 797. 000112 1 1 return @sqlda; 798. 000114 1 1 END;! of proc allocate^sqlda 799. 000000 0 0 800. 000000 0 0 801. 000000 0 0 802. 000000 0 0 C-30

Examples of Dynamic NonStop SQL Programs Detailed Dynamic SQL Program Page 20 [1] $VOL1.S04.TALDYN 1991-10-15 13:42:28 free^sqlda 804. 000000 0 0 PROC free^sqlda (sqlda); 805. 000000 1 0 806. 000000 1 0!*******************************************************! 807. 000000 1 0! PROC free^sqlda:! 808. 000000 1 0! This proc accepts an sqlda as a parameter and! 809. 000000 1 0! frees all memory that was allocated for the data! 810. 000000 1 0! buffers (pointed to as sqlvar[i].var^ptr), the! 811. 000000 1 0! indicator variables (pointed to as sqlvar[i].ind^ptr),! 812. 000000 1 0! and for the sqlda and sqlvar entries.! 813. 000000 1 0!! 814. 000000 1 0! The proc assumes that if a nonnull sqlda address! 815. 000000 1 0! is passed, then sqlda.num^entries has a valid value.! 816. 000000 1 0!! 817. 000000 1 0!******************************************************! 818. 000000 1 0 819. 000000 1 0 STRUCT.ext sqlda (sqlda^type);! IN--Pointer to SQLDA 820. 000000 1 0 821. 000000 1 0 BEGIN 822. 000000 1 1 INT i; 823. 000000 1 1 INT.EXT ptr;! temporary pointer for freeing memory pointed 824. 000000 1 1! at by var^ptr or ind^ptr 825. 000000 1 1 826. 000000 1 1 if @sqlda = NULL^ADDR then return; 827. 000007 1 1 828. 000007 1 1 FOR i := 0 TO sqlda.num^entries-1 DO 829. 000011 1 1 BEGIN 830. 000011 1 2 @ptr := sqlda.sqlvar[i].var^ptr; 831. 000024 1 2 if @ptr <> NULL^ADDR then 832. 000031 1 2 begin 833. 000031 1 3 CALL PUTPOOL(pool^head, ptr); 834. 000037 1 3 if <> then 835. 000040 1 3 begin 836. 000040 1 4 PUT^STR ("PUTPOOL memmory management error"); 837. 000056 1 4 PRINT^LINE; 838. 000071 1 4 call ABEND; 839. 000076 1 4 end; 840. 000076 1 3 end; 841. 000076 1 2 @ptr := sqlda.sqlvar[i].ind^ptr; 842. 000111 1 2 if @ptr >= 0D then! ***** don't know why <> NULL^ADDR doesn't work **** 843. 000114 1 2 begin 844. 000114 1 3 CALL PUTPOOL(pool^head, ptr); 845. 000122 1 3 if <> then 846. 000123 1 3 begin 847. 000123 1 4 PUT^STR ("PUTPOOL memory management error"); 848. 000141 1 4 PRINT^LINE; 849. 000154 1 4 call ABEND; 850. 000161 1 4 end; 851. 000161 1 3 end; 852. 000161 1 2 END; 853. 000174 1 1 854. 000174 1 1 call PUTPOOL (pool^head, sqlda); 855. 000202 1 1 if <> then 856. 000203 1 1 begin 857. 000203 1 2 PUT^STR ("PUTPOOL memory management error"); 858. 000221 1 2 PRINT^LINE; 859. 000234 1 2 call ABEND; 860. 000241 1 2 end; C-31

Examples of Dynamic NonStop SQL Programs Detailed Dynamic SQL Program Page 21 [1] $VOL1.S04.TALDYN 1991-10-15 13:42:28 free^sqlda 861. 000241 1 1 862. 000241 1 1 END;! of proc free^sqlda 863. 000000 0 0 Page 22 [1] $VOL1.S04.TALDYN 1991-10-15 13:42:28 cleanup 865. 000000 0 0 PROC cleanup; 866. 000000 1 0!***************************************************! 867. 000000 1 0! PROC cleanup:! 868. 000000 1 0! This proc frees up the allocated memory for the input and! 869. 000000 1 0! output sqldas and names buffers and the data buffers allocated! 870. 000000 1 0! for the sqldas.! 871. 000000 1 0!***************************************************! 872. 000000 1 0 BEGIN 873. 000000 1 1 call free^sqlda(sda^i); 874. 000004 1 1 call free^sqlda(sda^o); 875. 000007 1 1 @sda^i := @sda^o := NULL^ADDR; 876. 000014 1 1 877. 000014 1 1 if @cname^i <> NULL^ADDR then 878. 000021 1 1 begin 879. 000021 1 2 call PUTPOOL(pool^head,cname^i); 880. 000027 1 2 if <> then 881. 000030 1 2 begin 882. 000030 1 3 PUT^STR ("PUTPOOL memory management error"); 883. 000046 1 3 PRINT^LINE; 884. 000061 1 3 call ABEND; 885. 000066 1 3 end; 886. 000066 1 2 @cname^i := NULL^ADDR; 887. 000071 1 2 end; 888. 000071 1 1 if @cname^o <> NULL^ADDR then 889. 000076 1 1 begin 890. 000076 1 2 call PUTPOOL(pool^head,cname^o); 891. 000104 1 2 if <> then 892. 000105 1 2 begin 893. 000105 1 3 PUT^STR ("PUTPOOL memory management error"); 894. 000123 1 3 PRINT^LINE; 895. 000136 1 3 call ABEND; 896. 000143 1 3 end; 897. 000143 1 2 @cname^o := NULL^ADDR; 898. 000146 1 2 end; 899. 000146 1 1 END; 900. 000000 0 0 901. 000000 0 0 C-32

Examples of Dynamic NonStop SQL Programs Detailed Dynamic SQL Program Page 23 [1] $VOL1.S04.TALDYN 1991-10-15 13:42:28 startup^and^define^pool 903. 000000 0 0 PROC startup^and^define^pool; 904. 000000 1 0 905. 000000 1 0!******************************************************! 906. 000000 1 0! PROC startup^and^define^pool! 907. 000000 1 0! reads startup message, opens terminal, and defines memory pool! 908. 000000 1 0!********************************************************! 909. 000000 1 0 910. 000000 1 0 BEGIN 911. 000000 1 1 INT error;! definepool error 912. 000000 1 1 INT termname[0:11];! gets home terminal name from MYTERM 913. 000000 1 1 914. 000000 1 1! 915. 000000 1 1! Read startup message. 916. 000000 1 1! 917. 000000 1 1 918. 000000 1 1 call INITIALIZER; 919. 000006 1 1 920. 000006 1 1! 921. 000006 1 1! Open terminal for output. 922. 000006 1 1! 923. 000006 1 1 924. 000006 1 1 CALL MYTERM(termname); 925. 000011 1 1 CALL OPEN(termname, term); 926. 000021 1 1 IF <> THEN CALL DEBUG; 927. 000023 1 1 928. 000023 1 1! 929. 000023 1 1! Initialize memory pool. 930. 000023 1 1! 931. 000023 1 1 932. 000023 1 1 error := DEFINEPOOL(pool^head, pool, POOL^SIZE^IN^BYTES); 933. 000036 1 1 IF error <> 0 THEN 934. 000040 1 1 BEGIN 935. 000040 1 2 PUT^STR ("Definepool error: "); 936. 000056 1 2 PUT^INT^MID (error); 937. 000076 1 2 PRINT^LINE; 938. 000111 1 2 CALL ABEND; 939. 000116 1 2 END; 940. 000116 1 1 END;!end of proc startup^and^define^pool 941. 000000 0 0 C-33

Examples of Dynamic NonStop SQL Programs Detailed Dynamic SQL Program Page 24 [1] $VOL1.S04.TALDYN 1991-10-15 13:42:28 sql^warning^handler 943. 000000 0 0 PROC sql^warning^handler; 944. 000000 1 0!******************************************************! 945. 000000 1 0! Displays an SQL warning. 946. 000000 1 0!******************************************************! 947. 000000 1 0 BEGIN 948. 000000 1 1 PRINT^BLANK^LINE; 949. 000011 1 1 call SQLCADISPLAY (sqlca); 950. 000023 1 1 END; 951. 000000 0 0 Page 25 [1] $VOL1.S04.TALDYN 1991-10-15 13:42:28 memory^error^handler 953. 000000 0 0 PROC memory^error^handler(rollback^flag); 954. 000000 1 0!******************************************************! 955. 000000 1 0! Prints a message and either terminates or returns. Called! 956. 000000 1 0! on failure of memory allocation for SQLDAs or names buffers.! 957. 000000 1 0!******************************************************! 958. 000000 1 0 INT rollback^flag;! IN: 0--no ROLLBACK WORK, program should stop. 959. 000000 1 0! 1--ROLLBACK WORK, program will re-enter 960. 000000 1 0! the input loop (outside this procedure). 961. 000000 1 0 BEGIN 962. 000000 1 1 PRINT^BLANK^LINE; 963. 000011 1 1 PUT^STR^MID ("**** memory allocation failure *** "); 964. 000025 1 1 965. 000025 1 1 if rollback^flag then 966. 000027 1 1 EXEC SQL ROLLBACK WORK! when we return from here, the 967. 000027 1 1! program re-enters the input loop. 968. 000027 1 1 else 969. 000075 1 1 begin 970. 000075 1 2 PRINT^LINE; 971. 000110 1 2 PUT^STR (" Process stopped."); 972. 000126 1 2 PRINT^LINE; 973. 000141 1 2 PRINT^BLANK^LINE; 974. 000151 1 2 PUT^STR^MID ("End of current session"); 975. 000165 1 2 PRINT^LINE; 976. 000200 1 2 call STOP; 977. 000205 1 2 end; 978. 000205 1 1 END; 979. 000000 0 0 980. 000000 0 0 C-34

Examples of Dynamic NonStop SQL Programs Detailed Dynamic SQL Program Page 26 [1] $VOL1.S04.TALDYN 1991-10-15 13:42:28 dyn^tal main procedure 982. 000000 0 0 983. 000000 0 0! Declare WHENEVER clauses for error checking on SQL statements. 984. 000000 0 0! Note: Code that allocates memory and checks the input query must 985. 000000 0 0! do separate error checking, because such code does not involve 986. 000000 0 0! statements that set the SQLCODE variable. 987. 000000 0 0 988. 000000 0 0! Errors are handled at a label within the main procedure because 989. 000000 0 0! the error handling code itself uses GO TO to return to 990. 000000 0 0! enter^input. 991. 000000 0 0! We use GO TO for errors because it makes the example 992. 000000 0 0! easier to read than the alternative (boolean variable with 993. 000000 0 0! IF checking); however, using GO TO makes it necessary to 994. 000000 0 0! put the WHENEVER clause here instead of in the global variable 995. 000000 0 0! declarations, to avoid inserting an implicit GO TO in code that 996. 000000 0 0! appears before sql^error^handler. 997. 000000 0 0 998. 000000 0 0 EXEC SQL WHENEVER SQLERROR GO TO :sql^error^handler; 999. 000000 0 0 1000. 000000 0 0 PROC dyn^tal MAIN; 1001. 000000 1 0 1002. 000000 1 0!*****************************************************! 1003. 000000 1 0! PROC dyn^tal MAIN! 1004. 000000 1 0! Interactively reads SQL statements and dynamically processes! 1005. 000000 1 0! them. Result is sent to the home terminal.! 1006. 000000 1 0!*****************************************************! 1007. 000000 1 0 1008. 000000 1 0 BEGIN 1009. 000000 1 1 INT in^numvars;! Number of parameters 1010. 000000 1 1 INT in^nameslen;! Size of input names buffer 1011. 000000 1 1 INT out^numvars;! Number of output columns 1012. 000000 1 1 INT out^nameslen;! Size of output names buffer 1013. 000000 1 1 INT(32) num^fetches;! count number of fetches per query 1014. 000000 1 1 INT status; 1015. 000000 1 1 INT temp^sqlcode;! Saves the value of SQLCODE for later 1016. 000000 1 1! in cases where SQLCODE is set to 0. 1017. 000000 1 1! See sql^error^handler at the end 1018. 000000 1 1! of this main procedure 1019. 000000 1 1 1020. 000000 1 1 INT rollback^flag;! boolean for passing to memory- 1021. 000000 1 1! allocation error handler -- decides 1022. 000000 1 1! whether we want to re-enter the 1023. 000000 1 1! input loop or terminate the program 1024. 000000 1 1 1025. 000000 1 1 rollback^flag := 0;! initialize to FALSE 1026. 000003 1 1 1027. 000003 1 1 CALL startup^and^define^pool; 1028. 000004 1 1 1029. 000004 1 1 @sbuf := $XADR(buf); 1030. 000010 1 1 @sda^i := @sda^o := NULL^ADDR; 1031. 000015 1 1 @cname^i := @cname^o := NULL^ADDR; 1032. 000022 1 1 C-35

Examples of Dynamic NonStop SQL Programs Detailed Dynamic SQL Program 1033. 000022 1 1 PUT^STR ("This is DYNAMIC SQL test."); 1034. 000040 1 1 PRINT^LINE; 1035. 000053 1 1 1036. 000053 1 1!*****************************************************! 1037. 000053 1 1! Input SQL query from terminal.! 1038. 000053 1 1!*****************************************************! Page 27 [1] $VOL1.S04.TALDYN 1991-10-15 13:42:28 dyn^tal main procedure 1039. 000053 1 1 1040. 000053 1 1 enter^input: 1041. 000053 1 1! 1042. 000053 1 1! Free the memory taken by the sda^i, sda^o, cname^i, and cname^o 1043. 000053 1 1! 1044. 000053 1 1 call cleanup; 1045. 000054 1 1 1046. 000054 1 1 status := read^query ;! READ^QUERY gets the SQL statement and 1047. 000056 1 1! stores the statement in variable HOST1 1048. 000056 1 1 1049. 000056 1 1 if status < 0 then 1050. 000061 1 1 begin 1051. 000061 1 2 PRINT^BLANK^LINE; 1052. 000071 1 2 PUT^STR ("End of current session"); 1053. 000107 1 2 PRINT^LINE; 1054. 000122 1 2 call STOP; 1055. 000127 1 2 end; 1056. 000127 1 1 1057. 000127 1 1!*****************************************************! 1058. 000127 1 1! BEGIN TRANSACTION! 1059. 000127 1 1!*****************************************************! 1060. 000127 1 1 EXEC SQL BEGIN WORK; 1061. 000200 1 1 1062. 000200 1 1!*****************************************************! 1063. 000200 1 1! PREPARE the SQL statement! 1064. 000200 1 1!*****************************************************! 1065. 000200 1 1 1066. 000200 1 1 EXEC SQL PREPARE s1 FROM :host1;! HOST1 is a global variable that 1067. 000271 1 1! contains the SQL statement obtained 1068. 000271 1 1! in READ^QUERY 1069. 000271 1 1 1070. 000271 1 1! Save the values of some useful SQLSA fields. We must save these values 1071. 000271 1 1! because each SQL statement clears the SQLSA. 1072. 000271 1 1 1073. 000271 1 1 in^numvars := sqlsa.prepare.input^num; 1074. 000274 1 1 in^nameslen := sqlsa.prepare.input^names^len; 1075. 000277 1 1 out^numvars := sqlsa.prepare.output^num; 1076. 000302 1 1 out^nameslen := sqlsa.prepare.output^names^len; 1077. 000305 1 1 1078. 000305 1 1!*****************************************************! 1079. 000305 1 1! Allocate input and output sqlda and names buffers.! 1080. 000305 1 1!*****************************************************! 1081. 000305 1 1 1082. 000305 1 1 if in^numvars > 0 then 1083. 000310 1 1 begin 1084. 000310 1 2 @sda^i := allocate^sqlda (in^numvars); 1085. 000314 1 2 if @sda^i = NULL^ADDR then 1086. 000321 1 2 begin 1087. 000321 1 3 PUT^STR ("Input SQLDA "); 1088. 000337 1 3 call memory^error^handler(rollback^flag); 1089. 000342 1 3 end; 1090. 000342 1 2 end; 1091. 000342 1 1 1092. 000342 1 1 if out^numvars > 0 then C-36

Examples of Dynamic NonStop SQL Programs Detailed Dynamic SQL Program 1093. 000345 1 1 begin 1094. 000345 1 2 @sda^o := allocate^sqlda (out^numvars); 1095. 000351 1 2 if @sda^o = NULL^ADDR then Page 28 [1] $VOL1.S04.TALDYN 1991-10-15 13:42:28 dyn^tal main procedure 1096. 000356 1 2 begin 1097. 000356 1 3 PUT^STR ("Output SQLDA "); 1098. 000376 1 3 call memory^error^handler(rollback^flag); 1099. 000401 1 3 end; 1100. 000401 1 2 end; 1101. 000401 1 1 1102. 000401 1 1 if in^nameslen > 0 then 1103. 000404 1 1 begin 1104. 000404 1 2 @cname^i := GETPOOL (pool^head, $DBL(in^nameslen)); 1105. 000414 1 2 if <> then 1106. 000415 1 2 begin 1107. 000415 1 3 PUT^STR ("Input names buffer "); 1108. 000433 1 3 call memory^error^handler(rollback^flag); 1109. 000436 1 3 end; 1110. 000436 1 2 end; 1111. 000436 1 1 1112. 000436 1 1 if out^nameslen > 0 then 1113. 000441 1 1 begin 1114. 000441 1 2 @cname^o := GETPOOL (pool^head, $DBL(out^nameslen)); 1115. 000451 1 2 if <> then 1116. 000452 1 2 begin 1117. 000452 1 3 PUT^STR ("Output names buffer "); 1118. 000470 1 3 call memory^error^handler(rollback^flag); 1119. 000473 1 3 end; 1120. 000473 1 2 end; 1121. 000473 1 1 1122. 000473 1 1!----------------------------------------------- 1123. 000473 1 1! Get information on input variables. 1124. 000473 1 1!----------------------------------------------- 1125. 000473 1 1 1126. 000473 1 1 IF in^numvars > 0 THEN 1127. 000476 1 1 BEGIN 1128. 000476 1 2 EXEC SQL DESCRIBE INPUT s1 INTO :sda^i 1129. 000476 1 2 NAMES INTO :cname^i.val; 1130. 000557 1 2 1131. 000557 1 2!-------------------------------------------------------! 1132. 000557 1 2! Initialize SQLDA var^ptr to point to input data buffer.! 1133. 000557 1 2! Input parameter values from terminal.! 1134. 000557 1 2!-------------------------------------------------------! 1135. 000557 1 2 1136. 000557 1 2 if setupvarbuffers(sda^i) then 1137. 000563 1 2 begin 1138. 000563 1 3 rollback^flag := 1; 1139. 000565 1 3 PUT^STR("Input parameter buffers "); 1140. 000603 1 3 call memory^error^handler(rollback^flag); 1141. 000606 1 3 goto enter^input; 1142. 000607 1 3 end; 1143. 000607 1 2 1144. 000607 1 2 if request^invars (sda^i, cname^i) then 1145. 000614 1 2 begin 1146. 000614 1 3 EXEC SQL ROLLBACK WORK; 1147. 000702 1 3 goto enter^input; 1148. 000703 1 3 end; 1149. 000703 1 2 END; C-37

Examples of Dynamic NonStop SQL Programs Detailed Dynamic SQL Program 1150. 000703 1 1 1151. 000703 1 1!--------------------------------------! 1152. 000703 1 1! Get information on output variables.! Page 29 [1] $VOL1.S04.TALDYN 1991-10-15 13:42:28 dyn^tal main procedure 1153. 000703 1 1!--------------------------------------! 1154. 000703 1 1 1155. 000703 1 1 IF out^numvars > 0 THEN 1156. 000706 1 1 BEGIN 1157. 000706 1 2 EXEC SQL DESCRIBE s1 INTO :sda^o NAMES INTO :cname^o.val; 1158. 001000 1 2 1159. 001000 1 2!*******************************************************! 1160. 001000 1 2! Allocate output data buffers and update output SQLDA.! 1161. 001000 1 2! Initialize SQLDA var^ptr to point to output data buffers! 1162. 001000 1 2!*******************************************************! 1163. 001000 1 2 1164. 001000 1 2 if setupvarbuffers(sda^o) then 1165. 001004 1 2 begin 1166. 001004 1 3 rollback^flag := 1; 1167. 001006 1 3 PUT^STR("Output buffers "); 1168. 001024 1 3 call memory^error^handler(rollback^flag); 1169. 001027 1 3 goto enter^input; 1170. 001030 1 3 end; 1171. 001030 1 2 END; 1172. 001030 1 1 1173. 001030 1 1 if out^numvars > 0 then 1174. 001033 1 1 begin 1175. 001033 1 2!*****************************************************! 1176. 001033 1 2! SELECT statement! 1177. 001033 1 2!*****************************************************! 1178. 001033 1 2 1179. 001033 1 2!------------------------------------------------------ 1180. 001033 1 2! Define a cursor name for the statement S1, to be 1181. 001033 1 2! used later in OPEN, FETCH, and CLOSE statements. 1182. 001033 1 2!------------------------------------------------------ 1183. 001033 1 2 1184. 001033 1 2 EXEC SQL DECLARE c1 CURSOR FOR s1; 1185. 001033 1 2 1186. 001033 1 2!------------------------------------------------------ 1187. 001033 1 2! Open the cursor. By this point, all input 1188. 001033 1 2! parameters must have valid values. 1189. 001033 1 2!------------------------------------------------------ 1190. 001033 1 2 IF in^numvars > 0 THEN 1191. 001036 1 2 EXEC SQL OPEN c1 USING DESCRIPTOR :sda^i 1192. 001036 1 2 ELSE 1193. 001122 1 2 EXEC SQL OPEN c1; 1194. 001201 1 2 1195. 001201 1 2!*****************************************************! 1196. 001201 1 2! FETCH loop! 1197. 001201 1 2!*****************************************************! 1198. 001201 1 2 1199. 001201 1 2 sqlcode := 0; 1200. 001203 1 2 num^fetches := 0D; C-38

Examples of Dynamic NonStop SQL Programs Detailed Dynamic SQL Program Page 30 [1] $VOL1.S04.TALDYN 1991-10-15 13:42:28 dyn^tal main procedure 1210. 001267 1 3 begin 1211. 001267 1 4 PRINT^BLANK^LINE; 1212. 001277 1 4 PUT^STR ("--- "); 1213. 001315 1 4 PUT^DBL^MID (num^fetches); 1214. 001334 1 4 PUT^STR^MID (" row(s) selected."); 1215. 001350 1 4 PRINT^LINE; 1216. 001363 1 4 EXEC SQL CLOSE C1; 1217. 001435 1 4 EXEC SQL COMMIT WORK; 1218. 001506 1 4 goto enter^input; 1219. 001507 1 4 end; 1220. 001507 1 3 1221. 001507 1 3! Re-enable warning checking: 1222. 001507 1 3 EXEC SQL WHENEVER SQLWARNING CALL :sql^warning^handler; 1223. 001507 1 3 1224. 001507 1 3 CALL display^result (sda^o, cname^o);!display one row 1225. 001513 1 3 num^fetches := num^fetches + 1D; 1226. 001517 1 3 1227. 001517 1 3 end;! end WHILE loop 1228. 001520 1 2 1229. 001520 1 2!*****************************************************! 1230. 001520 1 2! Not a SELECT statement.! 1231. 001520 1 2! EXECUTE the statement with USING DESCRIPTOR if there were input! 1232. 001520 1 2! parameters; otherwise, EXECUTE the statement.! 1233. 001520 1 2!*****************************************************! 1234. 001520 1 2 1235. 001520 1 2 IF in^numvars > 0 THEN 1236. 001523 1 2 EXEC SQL EXECUTE s1 USING DESCRIPTOR :sda^i 1237. 001523 1 2 ELSE 1238. 001601 1 2 EXEC SQL EXECUTE s1; 1239. 001664 1 2 1240. 001664 1 2 PRINT^BLANK^LINE; 1241. 001674 1 2 PUT^STR ("--- SQL Operation Complete."); 1242. 001715 1 2 PRINT^LINE; 1243. 001730 1 2 end; 1244. 001730 1 1 1245. 001730 1 1 EXEC SQL COMMIT WORK; 1246. 002001 1 1 goto enter^input;! Get the next query 1247. 002002 1 1 1248. 002002 1 1 1249. 002002 1 1 sql^error^handler: 1250. 002002 1 1!*****************************************************! 1251. 002002 1 1! The WHENEVER SQLERROR clause sends the program to this code if an! 1252. 002002 1 1! SQL error is encountered.! 1253. 002002 1 1!*****************************************************! 1254. 002002 1 1 1255. 002002 1 1! Save the value of SQLCODE. ROLLBACK WORK sets SQLCODE to 0. 1256. 002002 1 1 temp^sqlcode := sqlcode; 1257. 002004 1 1 1258. 002004 1 1! Disable WHENEVER checking to avoid an infinite loop if an error 1259. 002004 1 1! should occur in this code. See discussion under WHENEVER 1260. 002004 1 1! in Section 3. 1261. 002004 1 1 EXEC SQL WHENEVER SQLERROR CONTINUE; 1262. 002004 1 1 PRINT^BLANK^LINE; 1263. 002014 1 1 call SQLCADISPLAY (sqlca); 1264. 002026 1 1 EXEC SQL ROLLBACK WORK; 1265. 002073 1 1 goto enter^input; 1266. 002104 1 1 C-39

Examples of Dynamic NonStop SQL Programs Detailed Dynamic SQL Program 1201. 001205 1 2 1202. 001205 1 2! Disable SQL warning checking 1203. 001205 1 2 EXEC SQL WHENEVER SQLWARNING CONTINUE; 1204. 001205 1 2 1205. 001205 1 2 WHILE sqlcode >= 0 do! continue fetching rows as long as 1206. 001210 1 2! there are no errors or only warnings 1207. 001210 1 2 begin 1208. 001210 1 3 EXEC SQL FETCH c1 USING DESCRIPTOR :sda^o; 1209. 001264 1 3 if sqlcode = 100 then! We've fetched all the rows Page 31 [1] $VOL1.S04.TALDYN 1991-10-15 13:42:28 dyn^tal main procedure 1267. 002104 1 1 sqlcode := temp^sqlcode; 1268. 002106 1 1 1269. 002106 1 1! Re-enable WHENEVER checking: 1270. 002106 1 1 EXEC SQL WHENEVER SQLERROR GO TO :sql^error^handler; 1271. 002106 1 1 1272. 002106 1 1 END;!main Page 32 [1] $VOL1.S04.TALDYN 1991-10-15 13:42:28 BINDER AND COMPILER STATISTICS BINDER - OBJECT FILE BINDER - T9621C30 - (01NOV91) SYSTEM \SYS1 Copyright Tandem Computers Incorporated 1982-1989, 1991 Object file $VOL1.S04.TALD2O TIMESTAMP 1991-10-15 13:42:28 5 Code pages 21 Primary data words 5365 Secondary data words 64 Data pages 0 Resident code pages 1 Extended data page 5386 Top of stack location in words 1 Code segment 0 Binder Warnings 0 Binder Errors TAL - Transaction Application Language - T9250C30 - (01NOV91) Number of compiler errors = 0 Number of unsuppressed compiler warnings = 0 Number of warnings suppressed by NOWARN = 0 Maximum symbol table space used was = 40902 bytes Number of source lines = 4184 Compile cpu time = 00:00:08 Total Elapsed time = 00:00:38 C-40

D NonStop SQL Version Issues NonStop SQL release C30 includes features that are incompatible with NonStop SQL release C10. Usually, these features provide compatibility with ANSI and ISO SQL standards. This appendix describes these topics: Definitions of Version 1 (C10) and Version 2 (C30) catalogs and objects Changes in release C30 that are incompatible with release C10 Migrating a release C10 program to: Run on a release C30 system Access Version 2 (C30) objects Installing migrated programs SQL component compatibility Programmatic features for handling version control Programming techniques for mixed versions For more information about version issues for NonStop SQL release C10 and NonStop SQL release C30, see the NonStop SQL Installation and Management Manual. Version 1 and Version 2 Definitions NonStop SQL associates a version number with each SQL feature and database object. NonStop SQL uses this version number to determine whether it can support a feature or an object. If it cannot support a feature or an object, NonStop SQL also uses the version number to return an appropriate message. NonStop SQL Version 1 and Version 2 features and objects are described in the following paragraphs. The Version 2 data types are: FLOAT (includes REAL and DOUBLE PRECISION) DATETIME (includes DATE, TIME, and TIMESTAMP) INTERVAL UPSHIFT CHARACTER or VARCHAR The Version 2 functions are: Exponentiation Date-time functions UPSHIFT function The Version 2 features are: Version 2 data types and functions (shown above) D-1

NonStop SQL Version Issues Version 1 and Version 2 Definitions Columns that can contain null values Clustering keys Constraints with constants using any Version 2 feature NO AUDITCOMPRESS, HEADING, and HELP TEXT attributes UNION and JOIN clauses of the SELECT statement Table D-1 shows the Version 2 entities and their descriptions. Table D-1. Version 2 Items and Descriptions Version 2 Entity Table Index Protection or shorthand view Object Catalog Description A table that uses any Version 2 feature. An index that includes any column with a Version 2 data type or that uses any Version 2 feature. A view whose underlying table is a Version 2 table or whose selection expression includes a Version 2 feature such as a Version 2 constant, or UNION or JOIN. A Version 2 table, index, or view. A catalog with release C30 format. It can be created by NonStop SQL C30 software, or it can be created by C10 software and then upgraded with the C30 UPGRADE CATALOG command. Both Version 1 and Version 2 objects can be registered in a Version 2 catalog. Table D-2 shows the Version 1 entities and their descriptions. Table D-2. Version 1 Items and Descriptions Version 1 Entity Description Object A table, index, or view that does not include any Version 2 features. NonStop SQL release C10 always creates Version 1 objects, but NonStop SQL release C30 can create Version 1 and Version 2 objects. Catalog A catalog with NonStop SQL release C10 format. Only Version 1 objects can be registered in a Version 1 catalog. However, programs compiled by either the release C10 or C30 SQL compiler can be registered in a Version 1 catalog. To determine a version number, a program can call the SQLGETCATALOGVERSION, SQLGETOBJECTVERSION, or SQLGETSYSTEMVERSION system procedure. The procedures are described in Section 4, System Procedures A Version 2 catalog has more columns and column values than a Version 1 catalog. Table D-3 summarizes the new columns in Version 2 catalogs. For the column values, see the NonStop SQL Installation and Management Manual. D-2

NonStop SQL Version Issues Summary of Incompatible Changes Table D-3. Summary of New Columns in Version 2 Catalogs Catalog Table/Column Name Column Declaration Column Description COLUMNS Catalog Table DATETIMESTARTFIELD SMALLINT Date-time starting field DATETIMEENDFIELD SMALLINT Date-time ending field DATETIMEQUALIFIER VARCHAR (28) Date-time/INTERVAL field UPSHIFT CHAR (1) Upshifted Y,N HEADING CHAR (1) Heading Y,N HEADINGTEXT VARCHAR (132) Heading text FILES Catalog Table AUDITCOMPRESS CHAR(1) Audit compression Y,N Note. Object version and catalog version do not necessarily match the NonStop SQL release version of the system where they reside. NonStop SQL C10 software can only create Version 1 objects and Version 1 catalogs. Version 1 objects and catalogs, however, can reside on both NonStop SQL C10 and C30 systems. NonStop SQL C30 software creates only Version 2 catalogs and creates either Version 1 or 2 objects depending on the features used in the objects. Summary of Incompatible Changes Table D-4 on page D-4 summarizes the NonStop SQL release C30 features that are incompatible with NonStop SQL release C10. These features can affect programs running in a mixed-version environment and C10 programs that are migrated to a C30 system. These features are described on subsequent pages in this section. D-3

NonStop SQL Version Issues Migrating a C10 Program to Run on a C30 System Table D-4. Incompatible NonStop SQL Release C30 Features C10 Program Operation DDL statements that create column definitions and omit the NOT NULL clause or the SYSTEM DEFAULT clause. Programs that test for error 100 to determine if an aggregate function (AVG, MAX, MIN, or SUM) returned an empty set. Programs that use new C30 reserved words INNER, JOIN, and LEFT as column names, constraint names, correlation names, cursor names, or statement names. Programs that query catalog tables COLUMNS, COMMENTS, and FILES. Static SQL programs that access tables. Dynamic SQL programs that initialize the SQLDA. Required Change Explicitly include the NOT NULL and SYSTEM DEFAULT clauses in the CREATE TABLE or ALTER TABLE ADD COLUMN statements to ensure the same column definition produced by C10. Change the test for an empty set to a test for: A NULL value (in this case, you must also supply a NULL indicator variable). Error 8423. Change all names that use INNER, JOIN, or LEFT. To access Version 2 catalogs, change the queries affected by new columns or new column information in these catalog tables. To access Version 2 tables or views that have Version 2 data types, language compile and SQL compile to get internal structures to handle the data. To access Version 2 tables or views that allow null values, add code to handle the possible null values. To access Version 2 tables or views, initialize and use the release C30 SQLDA structure; add code to handle possible null values. Migrating a C10 Program to Run on a C30 System The following NonStop SQL C30 enhancements can affect migrated C10 programs. You need to be aware of these differences to develop programs that can run in a mixed-version environment or to migrate a C10 program to a C30 system. Column definition The default column definition has changed to allow null values. This change applies to the CREATE TABLE and ALTER TABLE ADD COLUMN statements. The C10 column defaults were SYSTEM DEFAULT and NOT NULL. The C30 column D-4

NonStop SQL Version Issues Migrating a C10 Program to Run on a C30 System default is DEFAULT NULL. For example, these column definitions result in these default definitions for the indicated release: col1 CHAR(10) Under C10: col1 CHAR(10) DEFAULT SYSTEM NOT NULL Under C30: col1 CHAR(10) DEFAULT NULL NULL allowed col2 CHAR(10) DEFAULT "XZ" Under C10: col2 CHAR(10) DEFAULT "XZ" NOT NULL Under C30: col2 CHAR(10) DEFAULT "XZ" NULL allowed To ensure that tables created with C10 software retain their current definition if recreated with C30 software, add the : NOT NULL clause to all CREATE TABLE column definitions if the clause is not already included DEFAULT SYSTEM clause to all CREATE TABLE column definitions if a DEFAULT clause is not already included Make these changes to programs that create tables or to SQLCI OBEY command files that create the tables that a migrated program uses. If you do not make these changes: NonStop SQL creates the tables as Version 2 tables, which are not accessible from a C10 system. If null data is entered into the table and a program tries to retrieve a null value without using an indicator variable, NonStop SQL returns error 8423. Result of aggregate functions The result returned in a SELECT statement of the aggregate functions AVG, MAX, MIN, or SUM operating on an empty set is NULL. To be ANSI compatible, this result has changed from error 100 (no rows selected or modified) to NULL for release C10. To migrate programs that use the AVG, MAX, MIN, or SUM aggregate functions, recode the programs to determine if a null value is returned. Consider using use one of these methods: Check an indicator variable to handle a returned null value. Check for error 8423 as well as error 100 for the result of the aggregate function. Error 8423 indicates that the query is attempting to return a null value but there is no indicator variable along with the host variable to receive the null value. New SQL reserved words for release C30 are INNER, JOIN, and LEFT. Check for the use of these words as column names in tables or views or as constraint names. Re-create any tables or views that use these names as column names or constraint names. D-5

NonStop SQL Version Issues Migrating a C10 Program to Run on a C30 System Check your programs for these words in SQL statements and change any that are present as correlation names, cursor names, SQL statement names, and column names. The TAL compiler detects the use of these reserved words and issues a syntax error. Caution. A table or view created with NonStop SQL C10 and having INNER, JOIN, or LEFT as a column name or constraint name will not be available to an SQL program that references these columns or constraints and is SQL compiled with the C30 SQL compiler. The SQL compiler detects references to C30 reserved words and issues an error. Result of subqueries If a subquery in a WHERE clause returns no rows, NULL is returned to the subquery. To be ANSI compatible, this result has changed from error 100 (no rows selected or modified) to NULL for the NonStop SQL C10 implementation. For example, consider this SELECT statement from tables TABLE1 and TABLE2, with the SELECT from TABLE2 being a subquery that returns no rows: SELECT * FROM table1 WHERE a = (SELECT a FROM table2) Because the subquery returns no rows, the WHERE clause is evaluated as equal to NULL and fails. The evaluation is: WHERE a = NULL. To migrate programs affected by the change in the result of subqueries, you do not have to code extra checking in the program. Be aware, however, that C30 programs might retrieve more rows than C10 programs, because the C10 programs would have received error 100 (no rows selected or modified). Querying the NULLP value in the SQLDA structure NULLP means null pointer. For C10, the system returns a system-defined value for NULLP in the VAR^PTR field of the SQLDA structure if the names buffer is not large enough. A C30 system returns a negative value in the VAR^PTR field instead of NULLP. Programs should check for a value less than zero instead of checking for NULLP. NULLP is an internal constant and can change; therefore, its actual value is not documented. Additional SQLDA fields Using a C30 SQLDA structure is necessary only if the program might encounter null values or the new C30 data types FLOAT, REAL, DOUBLE PRECISION, DATETIME, DATE, TIME, TIMESTAMP, and INTERVAL. The SQLDA structure for C30 has additional fields that can contain information about these new C30 features. You can use a release C10 SQLDA on a C30 system if the program does not encounter these C30 features. Note. A program can sometimes encounter null values even if there are no null values in the database. D-6

NonStop SQL Version Issues Migrating a C10 Program to Access Version 2 Objects To use a C10 SQLDA structure, specify the RELEASE1 option either in the INCLUDE SQLDA directive or in the SQL directive for the TAL compiler. Migrating a C10 Program to Access Version 2 Objects If a release C10 program needs to access Version 2 objects or catalogs, consider these issues: Dynamic SQL operations Static SQL operations Catalog tables Dynamic SQL Operations Dynamic SQL programs use the SQLDA to specify input and output variables used in dynamic SQL statements. The release C30 SQLDA has a new field named PRECISION that supplies precision information when a column of FLOAT, REAL, DOUBLE PRECISION, DATETIME, DATE, TIME, TIMESTAMP, or INTERVAL data type is accessed. If the program accesses columns of these data types, the program must provide a release C30 SQLDA structure. When the release C30 structure is provided, precision information is also returned when columns of other data types are accessed. In addition to the PRECISION field, two other significant changes have been made to the release C30 SQLDA for null support: The NULL^INFO field, unused in the release C10 SQLDA, is now set to -1 if a null value is allowed in the corresponding SELECT column. The value is allowed to be null only if the column definition permits a null value. The RESERVED field has been renamed IND^PTR. The IND^PTR field is similar to the VAR^PTR field, but is for the extended address of a null indicator variable. The extended address is not returned by NonStop SQL; the program must initialize IND^PTR to point to the input and output indicator variables that it has declared and allocated. Dynamic SQL programs accessing null values or Version 2 data types can either use the INCLUDE SQLDA directive to generate an SQLDA structure or include the SQLDA declaration code in the source file. Existing programs that include the SQLDA declaration code must use the release C30 SQLDA structure to access columns with Version 2 data types. If program code initializes the SQLDA structure, the code must set the correct version value in the SQLDA EYE^CATCHER field to match the SQLDA version. The value DA indicates a release C10 SQLDA; the value D1 indicates a release C30 SQLDA. D-7

NonStop SQL Version Issues Static SQL Operations If the dynamic SQL program is designed to handle null values, the program must allocate indicator variables and initialize the IND^PTR field in addition to the VAR^PTR field. To migrate a C10 program to access columns defined to allow null values or use Version 2 data types, you must TAL compile and SQL compile the program with release C30 compilers. Static SQL Operations The SQLDA structure is generated automatically by the language compiler for static SQL operations. The SQLDA has additional fields for C30 to accommodate new data types. To migrate a C10 program to access columns defined with the new data types, add code to manage null values and host variables for new data types. Then compile the program with the C30 TAL compiler and the C30 SQL compiler. Catalog Tables The COLUMNS and FILES catalog tables have new columns in Version 2. To migrate programs that query these catalog tables, you might need to recode to accommodate the new columns. For the new columns, see Table D-3 on page D-3 earlier in this appendix; for detailed information about the catalog tables, see the NonStop SQL Installation and Management Manual. Summary Table D-5 summarizes the points in the preceding discussion. Table D-5. Accessing Version 2 Objects from a C10 Program Situation Dynamic SQL statements Static SQL statements Statements that query catalog table COLUMNS or FILES Action To Take Generate a RELEASE2 SQLDA structure. If handling null values, allocate indicator variables and initialize the IND^PTR field for each SQLVAR entry in the SQLDA. TAL and SQL compile with C30. Add code to manage null values and to manage host variables for new data types. TAL and SQL compile with C30 software. If necessary, recode to accommodate new columns and new column values. TAL and SQL compile with C30. Installing Migrated Programs You can upgrade a release C10 system to release C30 system and continue executing existing programs. The recommended procedure for installing programs includes SQL compiling all SQL program object files with the C30 SQL compiler. SQL compilation performs error checking for potential version problems. The steps to install migrated programs are: D-8

NonStop SQL Version Issues SQL Component Compatibility 1. Alter all source program modules affected by incompatible C30 features. 2. TAL compile the programs that contain embedded SQL statements. 3. Bind object files if this step applies. Binding multiple C10 and C30 object files is discussed later in this appendix. 4. Optionally, run the Accelerator on the object file generated from Step 2 or 3 if you plan to run the object file on a TNS/R system. 5. SQL compile all SQL program object files with the C30 SQL compiler. 6. Install the program object file on the C30 system. SQL Component Compatibility All software on a system should be a single release version: either NonStop SQL release C10 or NonStop SQL release C30. NonStop SQL installation procedures warn against mixing SQL system components from different versions because of the risk of unpredictable errors. If NonStop SQL release C30 is installed on a network with NonStop SQL release C10 systems, all release C10 systems that are to communicate with the C30 systems must be running the SQL C10 Versioning PVU (or any later PVUs that supersede the Versioning PVU). The Versioning PVU contains enhancements for handling compatibility between SQL system components and SQL objects. The components and PVU numbers are listed in the Table D-6. Table D-6. Release C10 Versioning IPM Summary Component Name IPM Numbers Component Identification BACKUP/RESTORE T9074C10^06MAR89 T9074AAM TSQL T9095C10^06MAR89 T9095AAG TSQLCI T9191C10^06MAR89 T9191AAC TSQLCOB T9192AAD^06MAR89 T9192AAD TSQLEXE T9193C10^15MAR89 T9193AAF TSQLCAT T9194C10^06MAR89 T9194AAD TSQLUTI T9195C10^06MAR89 T9195AAD TSQLMSG T9197C10^06MAR89 T9197AAC TSQLCI2 T9198C10^06MAR89 T9198AAA FASTSORT T9620C10^14FEB89 T9620AAB D-9

NonStop SQL Version Issues Developing C10 Programs with C30 Software Note. For a node running the release C10 NonStop Kernel operating system with NonStop SQL release C10, the above PVUs must be explicitly installed. For a node running the release C20 NonStop Kernel operating system with NonStop SQL release C10, these PVUs are included with the C20 Guardian software, except for the BACKUP/RESTORE PVU, which does not apply. Developing C10 Programs with C30 Software In a network, different nodes are often running different versions of NonStop SQL. If you are developing NonStop SQL release C10 programs using NonStop SQL release C30 software, specify the RELEASE1 option of the SQL directive. The RELEASE1 option causes the C30 TAL compiler to generate code that can be SQL compiled and executed on either a system running either NonStop SQL release C10 or NonStop SQL release C30. Programs compiled with the RELEASE1 option cannot use NonStop SQL release C30 features. The TAL compiler, however, does not make a check for the use of these features. The use of NonStop SQL release C30 features is not detected until the program is SQL compiled on a node running NonStop SQL release C10 software. To ensure that a program using the RELEASE1 option is error free, SQL compile and test the program on the NonStop SQL release C10 system where it will be installed. To install a program on a NonStop SQL release C10 system, duplicate the program object file on the C10 system and then SQL compile the program object file. For more information about the RELEASE1 option of the SQL directive, see Section 3, NonStop SQL Statements and Directives. Binding C10 and C30 Object Files Several object files that have been compiled by different versions of the TAL compiler (C10 and C30) can be bound together as a single unit and then SQL compiled. The resulting object file is assigned the version of the SQL compiler. This version information is used internally by SQL software components. To migrate existing C10 programs that consist of multiple object files bound together to a C30 system, follow these steps: 1. Using the C30 TAL compiler, compile only the source program files that are modified. Adding release C30 functionality to a single module of an existing program does not require recompiling all source modules with the TAL compiler. 2. Bind all the object files. 3. SQL compile the resulting object file with the C30 SQL compiler. Do not pass: C10 SQLDA structures from C10/C30 modules to C30 modules. C30 SQLDA structures from C10/C30 modules to C10 modules. D-10

NonStop SQL Version Issues Mixed-Version Programmatic Features Mixed-Version Programmatic Features The NonStop SQL programming interface provides several features to assist you in developing programs to handle mixed versions. These features include release specification options and procedures that report the version of various SQL objects. Release Specification Options Release specification options are available in the SQL directive. When a program specifies the RELEASE1 or RELEASE2 option, the C30 host language compiler generates code that is intended to be executed on a C10 or C30 system, respectively. A program compiled with the RELEASE2 specification can be executed only on a C30 system. A program compiled with the RELEASE1 specification can be executed on a C10 or C30 system because of upward compatibility. Release specification options are also available in the INCLUDE SQLDA directive. RELEASE1 and RELEASE2 options are valid. By default, the generated SQLDA structure is compatible with the version of the TAL compiler or the version specified in the SQL directive. You can, however, specify another release version in the INCLUDE SQLDA directive. You can include two INCLUDE SQLDA directives with each specifying a different release option as appropriate for program logic. For the descriptions of the different SQLDA structures, see the INCLUDE SQLDA directive in Section 6. System Procedures In a NonStop SQL mixed-version environment, a program might need to determine the version of SQL objects. Use these procedures to determine version information: SQLGETCATALOGVERSION Returns a value that indicates the version of an SQL catalog. SQLGETOBJECTVERSION Returns a value that indicates the version of an SQL object. This value represents the earliest SQL release that can perform all DML and most DDL operations defined for a given SQL table, index, or view. SQLGETSYSTEMVERSION Returns a value that indicates the version of the SQL file system and disk process components on a given system. All other NonStop SQL components are considered to be the same version. See Section 4, System Procedures, for the descriptions of these procedures. For C10 programs to use these procedures, the program must include the procedure declarations. For information about including the declarations, see the TSQLEXE D-11

NonStop SQL Version Issues Techniques for Mixed-Version Programming (T9193C10^15MAR89, T9193AAF) component SOFTDOC for the C10 versioning PVUs. For C30 programs, external declarations for these procedures are included in the EXTDECS system file for TAL programs. Techniques for Mixed-Version Programming A generic release program can run on multiple release levels of NonStop SQL and handle Version 1 and Version 2 catalogs and objects. The techniques for developing a generic release program is: Running on multiple NonStop SQL releases Handling mixed-version objects Using the single-code thread design Handling Mixed-Version-Objects Both generic release programs and programs that run only on NonStop SQL C30 systems can use these techniques to handle objects of mixed versions: Use the SQL system procedures to determine the NonStop SQL object version or catalog version. Then, execute code depending on information returned by each procedure. Include two sets of catalog queries if the program queries the catalogs and is sensitive to the difference between Version 1 and Version 2 catalogs. Before executing a catalog query, the program can use the SQLGETCATALOGVERSION procedure to check the SQL catalog version. The program executes the appropriate query depending on the catalog version. For example, if a program wants to determine whether a user table contains date-time columns and the attributes of those columns, the program must first determine whether the catalog in which the table is registered is a Version 2 catalog. Check the version of an object before reading information from the catalog tables. If the version of the object is unknown, do not try to read the catalog information. Otherwise, you might encounter unknown column values. Consider querying the VERSIONS catalog table as an alternative test to determine catalog version. The value of the VERSIONS column represents the catalog version as follows: A010 Version 1 catalog A011 Version 2 catalog Check the catalog version before executing certain DDL statements. You must be sure to register objects in Version 2 catalogs for these operations: Create Version 2 tables, views, indexes, or constraints D-12

NonStop SQL Version Issues Running on Multiple NonStop SQL Releases Create partitions for Version 2 tables or indexes Add a column that has a Version 2 data type For the last operation, you would have to issue an error if the table intended to get the new column was registered in a Version 1 catalog. For all of the above operations, the system returns an error if a program attempts to register a Version 2 object in a Version 1 catalog. Running on Multiple NonStop SQL Releases Programs that run on multiple NonStop SQL releases and use Version 2 features whenever possible must determine the SQL release level. Typically, these programs handle objects of multiple versions by using dynamic SQL. Some coding techniques, however, enable static SQL statements to handle multiple versions. When developing generic release programs, you should consider these techniques: Maintain two code threads in a single set of source programs and use conditional compilation to build two different object files depending on the version of the NonStop SQL software release. This technique requires parallel build and release cycles to install the program on nodes of different versions. Advantages of this technique are: Dynamic SQL is not necessary. Program logic is simpler than in the single-code thread design. Maintain a single-code thread by using IF/THEN/ELSE statements in the source program; the statements test for the appropriate SQL version and choose between two code branches at run time. This technique contrasts with the two-code thread technique by performing version checking at run time instead of at compile time; the use of the single-code thread technique precludes the use of the two-code thread technique. Typically, the single-code thread technique uses dynamic SQL and can require extensive mixed-version code. The resulting single object file, however, needs only a single build and release cycle to install the program on nodes of different versions. If you have a choice, use static SQL rather than dynamic SQL. Static SQL has better performance than dynamic SQL because the SQL statements do not require compilation at run time. Many generic release programs, however, require dynamic SQL for other reasons. Include the SQLGETSYSTEMVERSION procedure in program code to test for system version. Then determine which code to execute depending on the version. D-13

NonStop SQL Version Issues Using the Single-Code Thread Design Using the Single-Code Thread Design To develop a program that can run on a node running NonStop SQL release C10 and a node running NonStop SQL release C30 software and use Version 2 features, follow these steps: 1. In static SQL statements, do not use Version 2 features and objects. Static SQL statements will be processed by both the release C10 and C30 SQL compilers. 2. Use Version 2 features and objects only in dynamic SQL statements. In dynamic SQL operations, only the host variables that contain the SQL statements are processed by the TAL compiler. The actual SQL statements are represented as text in the host variables and therefore are not explicitly SQL compiled. 3. For dynamic SQL statements: Generate both NonStop SQL release C10 and C30 SQLDA structures. When your program first begins executing (that is, before you issue an SQL query), check the NonStop SQL software version using an SQL system procedure. Then, depending on this version, initialize and use the appropriate SQLDA structure. Ensure that a dynamic SQL statement that uses VersionÊ2 features executes only within a code branch that handles VersionÊ2 features. For example: IF sw^version = version^2 THEN host^var ':=' "SELECT * FROM t1 UNION SELECT * FROM t2" ELSE host^var ':=' "SELECT * FROM t1"; EXEC SQL PREPARE statement FROM :host^var; 4. Compile your TAL source statements using a release C30 TAL compiler. Specify the SQL directive with the RELEASE1 option as the first line of your primary source file or in the RUN command line for the TAL compiler. The RELEASE1 option causes the TAL compiler to generate release C10 SQLDA structures and object code that is compatible with both the release C10 and C30 SQL compilers. (Object code and structures generated with the RELEASE2 option are not compatible with the release C10 SQL compiler.) 5. SQL compile and distribute the program for installation and use on production nodes as follows: For C30 nodes, SQL compile and test the program on a C30 node and then distribute the program object file to any other C30 nodes. For C10 nodes, SQL compile and test the program on a C10 node and then distribute the program object file to any other C10 nodes. D-14

NonStop SQL Version Issues Using the Single-Code Thread Design Figure D-1. Developing a Program For Mixed-Version Nodes Node \DEVEL Development Node Release C30 NonStop SQL System Release C30 TAL Compiler (RELEASE1 Option) Node \PRODR1 Production Node 1 Release C10 NonStop SQL System Release C10 NonStop SQL Compiler Node \PRODR2 Production Node 2 Release C30 NonStop SQL System Release C30 NonStop SQL Compiler VSTD01.vsd D-15

NonStop SQL Version Issues Using the Single-Code Thread Design D-16

E Enforcing Data Integrity Data integrity requires that certain data conditions must be true within a database. Examples of these conditions are: Data format, such as numeric only Value ranges, such as between 500 and 1000 A relationship between items within a row A relationship between items in different rows of a table or between rows in different tables (Referential Integrity) The data format is controlled by the data type definition in the CREATE TABLE statement. NonStop SQL implicitly checks the data type whenever data is added to or updated in a table. For example, if a column is defined as numeric, the insertion of a character string is not allowed. Value ranges and relationships with other columns within the same row are controlled by constraints. (See Using Constraints on page E-1.) A relationship between items in different rows of a table or between rows in different tables is called referential integrity. You can include code in your program to enforce referential integrity. For example, two tables exist and contain data about employees and work departments. Inconsistencies can be introduced through coding errors, or through operations performed with SQLCI. For example, the program should not delete a department from the DEPT table if any row in the EMPLOYEE table refers to that department. You should check for such inconsistencies. (See Managing Referential Integrity on page E-2.) Note. Logical operations, such as checking for referential integrity, should be performed within a TMF transaction in order to ensure consistency. If the referential integrity constraint is not satisfied, the transaction can be rolled back. Using Constraints NonStop SQL supports constraints to protect the integrity of base tables. A constraint is a condition that must be met before data is added to a row in the base table to which the condition applies. NonStop SQL ensures that all modifications to rows satisfy all current constraints. This means that you cannot add a row or change a row when the new data does not meet the constraint specification. A new constraint is disallowed if any rows currently in the table do not satisfy it. You can create or drop constraints at any time. Creating or dropping a constraint, however, causes the system to invalidate all SQL program files that use the underlying E-1

Enforcing Data Integrity Managing Referential Integrity table. You should ensure that these files are explicitly SQL compiled to avoid automatic recompilation every time a program runs. Note. When you add a constraint, NonStop SQL checks all rows in the table. For large tables, the CREATE CONSTRAINT operation might run for a long time. Constraints are also a replacement for program code; they operate for all programs that refer to a table to which constraints apply. For example, constraints can be used to establish value ranges for columns, true or false conditions, and so forth. Consider this example: CREATE CONSTRAINT MGRNUM_CONST ON DEPT CHECK MANAGER BETWEEN 0001 AND 5000 ; This constraint on the DEPT table restricts the value of the column MANAGER to the range shown. Your programs do not have to check the value for each insertion or update to this table. SQL ensures the value is within the range. If the value is not within the range, SQL returns an error message and aborts any current TMF transaction. This is a database protection mechanism. When constraints exist, programs do not have to perform such checks to avoid corrupting the database. This example illustrates a constraint that examines two columns within the same row: CREATE CONSTRAINT VALIDATE_CONST ON EMPLOYEE CHECK TERM_DATE >= HIRE_DATE ; This constraint ensures that the employee termination date is equal to or greater than the date of hire. Managing Referential Integrity Referential integrity is a user test to ensure that any foreign key values that exist in a table also exist as primary key values in the same or another table. A foreign key is a column in a table that is a primary key in that table or in another table. The rule for referential integrity is that every foreign key value must have a corresponding primary key value. You can check for referential integrity through a program or with SQLCI. These examples use SQLCI to illustrate methods for checking and maintaining referential integrity. E-2

Enforcing Data Integrity Managing Referential Integrity Referential Integrity: Example 1 In this example, every department must report to another valid department in the table. To verify this rule, you can use this SELECT statement to check the DEPT table: SELECT DEPTNUM, RPTDEPT FROM DEPT WHERE RPTDEPT NOT IN (SELECT DEPTNUM FROM DEPT) ; The query returns this result: DEPTNUM RPTDEPT ------- ------- --- 0 row(s) selected. The absence of selected rows indicates the integrity of the database is intact. If any department contained an invalid report-to department, it would have been selected and shown, for example, as: DEPTNUM RPTDEPT ------- ------- 1320 999 --- 1 row(s) selected. Such an error could be corrected with this statement: UPDATE DEPT SET RPTDEPT = 1120 WHERE DEPTNUM = 1320; --- 1 row(s) updated. Repeating the previous SELECT verifies the correction. Referential Integrity: Example 2 In this example, the CLASS table has a primary key of CLASSNUM and a foreign key of CLASS_COURSE--each class is one offering of the course. The COURSE table has a primary key of COURSENUM. This code determines whether each class row does indeed point to a valid course: SELECT CLASSNUM, CLASS_COURSE FROM CLASS WHERE CLASS_COURSE NOT IN (SELECT COURSENUM FROM COURSE) ; E-3

Enforcing Data Integrity Managing Referential Integrity The query returns this result: CLASSNUM CLASS_COURSE -------- ------------ --- 0 row(s) selected. The result of zero rows selected indicates that each class points to a valid course. The result does not prove that the class points to the correct course. E-4

Index A Accelerator effect on SQL validity 5-22 running on object file 1-7, 5-5, D-9 using SQL object file for 5-12 Access path EXPLAIN utility 5-18 local autonomy 5-28 RECOMPILE option 5-9 SQL compiler function 5-5 unavailable 5-26 using EXPLAIN with 5-17 valid programs 5-22 Access privileges for SQL compiler 5-10 ADD Command, Binder 5-5 ADD DEFINE command, TACL 5-19 Aggregate functions for C10 program migration D-5 using in a program 6-7 ALLOCATESEGMENT system procedure 3-41 Allocating memory for indicator variables 7-37 Altering SQL file attribute, effect of 5-23 ANYWHERE clause with INSERT statement 3-20 APPEND clause with INSERT statement 3-20 Array as host variable 2-11 ASSIGN command, TACL for SQL program file 5-30 Attributes, SQL file effect of altering 5-23 Authority for program file execution 5-30 Automatic SQL recompilation functions of 5-24 Automatic SQL recompilation (continued) performance considerations 5-24 predicting 5-24 AVG function for C10 program migration D-5 B BACKUP/RESTORE program version issues D-9 BEGIN DECLARE SECTION Directive, SQL 3-6 BEGIN DECLARE SECTION directive, SQL 1-3, 2-2 BEGIN WORK statement, SQL 7-13 Binder program 1-7, 5-12 ADD command 5-5 binding mixed-version object files D-11 binding object files 5-4 BUILD command 5-5 effect on SQL validity 5-22 SELECT command 5-5 STRIP command 5-4 using with TALLIB 5-4 BINSERV option in PARAM command 5-13 process 7-8 BROWSE ACCESS clause with SELECT statement 3-32 BUILD command, Binder 5-5 C C programming language 1-1 C10 program, migrating to C30 D-4 C30 features, migrating program for D-3 CALL format of WHENEVER 6-7 CATALOG clause for SQL compiler 5-7 CATALOG TACL DEFINE 5-7 Index-1

Index C Catalog, SQL access for program file execution 5-7 handling mixed versions D-12 version 1 D-2 version 2 D-2, D-8 with SQLGETCATALOGVERSION 4-19 Circumflex (^) in host variable names 2-2 CLOSE statement, SQL 3-7, 3-8, 3-34 CLOSE system procedure 1-3 COBOL85 programming language 1-1 Colon (:) with host variable 1-3 Colon(:) with host variable 2-6 COLUMNS catalog tables version 2 features D-8 Column, SQL definition for versions D-4 for C10 program migration D-4 Comments, in SQL statements 3-2 COMMIT WORK statement, SQL 7-14 Compatibility of SQL components D-9 Compiler directives for TAL compiler 5-4 Compiling automatic SQL recompilation 5-24 dynamic SQL statements 5-14 explicit SQL 5-10 TAL program 1-7, 5-2 Components, SQL version compatibility of D-9 Compound TAL statement 3-2 Constraints changes and program file validity 5-22 creating E-1 using for data integrity E-1 CONTROL directives 3-8 CONTROL EXECUTOR directive, SQL 3-9 CONTROL QUERY directive, SQL 3-10 CONTROL TABLE directive, SQL 3-10 Conversational interface, NonStop SQL 1-1 CONVERTTIMESTAMP SQL function 3-22 CONVERTTIMESTAMP system procedure 3-22 Copying SQL files, effect on SQL validity 5-22 CREATE INDEX statement, SQL 5-23 CREATE TABLE statement, SQL 2-20, 7-2 version compatibility D-4 CURRENTDEFINES option, SQL compiler 5-7 Cursor CLOSE statement 3-7 closing for dynamic SQL 7-13 declaration 3-11 DECLARE CURSOR statement, SQL 3-11 declaring for dynamic SQL 7-12 deleting 3-15 dynamic 3-16 dynamic CLOSE 3-16 dynamic OPEN 3-29 dynamic operation 3-30 FETCH statement 3-18, 3-29 guidelines for using 3-45 in SELECT statement 3-34 initializing WHERE variable 3-33 opening for dynamic SQL 7-13 static 3-7 static CLOSE 3-7 static OPEN 3-29 UPDATE WHERE CURRENT statement, SQL 3-45 using with dynamic SQL 7-31 when to close 3-35 when to initialize 3-35 with OPEN statement 3-29 Index-2

Index D D Data advantages of NonStop SQL 1-1 conversion between SQL and TAL 2-4 enforcing integrity E-1 using INSERT statement with 3-19 using SELECT statement with 3-31 Data Control Language (DCL) SQL statements 1-2 Data declarations BEGIN DECLARE SECTION directive, SQL 3-6 END DECLARE SECTION directive, SQL 3-6 tables and views 3-22 Data Definition Language (DDL) SQL statements 1-2 Data Manipulation Language (DML) SQL statements 1-2 Data structures, SQL placing in memory 3-37 Data types conversion between SQL and TAL 2-4 correspondence (SQL and TAL) 2-2 date-interval 2-11 date-time 2-4, 2-11 default for dynamic SQL parameters 2-26 FIXED 2-13 INTERVAL 2-4 literal declarations for 7-21 mapping with INVOKE 2-20, 3-23 overriding default types 2-5 SQL 2-2 TAL 2-2 version compatibility D-1 Database, NonStop SQL sample A-2 using embedded SQL 1-1 DATAPAGES directive, TAL compiler 7-8 DATA^LEN field in SQLDA structure 7-5 literals for 6-19 DATA^TYPE field in SQLDA structure 7-5 literals for 6-18 DATEFORMAT clause 2-17 with INVOKE directive 3-24 Date-time data types for 2-4 data types for host variables 2-15 literals for 6-19 static SQL example B-10 Debugging using SQLCOMP FORCE option 5-8, 5-14 with RUND command 5-30 DECLARE CURSOR statement, SQL 3-11 Declare Section 2-2 declaration 3-6 multiple use 2-2 Declare section 1-3 DEFAULT clause, version incompatibility D-4 DEFAULT SYSTEM clause for C10 program migration D-4 DEFINEPOOL system procedure 7-17 DEFINES option for EXPLAIN utility 5-8 for SQL compiler 5-8 DEFINEs, TACL EXPLAIN report format 5-18 for automatic SQL recompilation 5-25 for catalog name 5-7 for SQL compilation 5-15 for SQL program execution 5-32 for SQL program file 5-30 in sample program C-1, C-10 propagating 5-32 Index-3

Index E DEFINEs, TACL (continued) set by RECOMPILE option 5-9 using for SQL compilation 5-8 using to maximize local autonomy 5-28 using with INSERT statement 3-20 using with SQL compiler 5-32 using with TAL compiler 5-31 DEFINE, TAL declaration 3-2 DEFMODE option, TACL 5-32 Delete operation multiple rows 3-14 set of rows 3-15 single row 3-14 DELETE statement, SQL 3-13 DESCRIBE INPUT statement, SQL 3-16 DESCRIBE statement, SQL 3-16 DETAIL option, FILEINFO command 5-22 Directives BEGIN DECLARE SECTION 3-6 END DECLARE SECTION 3-6 NonStop SQL table of 1-3 TAL compiler 5-4 Disk process (DP2) 4-3, 4-9, 4-14 Distributed database, maximizing local autonomy 5-28 DROP statement, SQL 3-17 DUPLICATE command, FUP 5-22 Duplicating SQL files, effect on SQL validity 5-22 Dynamic memory allocation 7-14 Dynamic operations SQL compilation 5-14 Dynamic SQL operations applications for 7-2 compilation 5-14 conversational interface for 7-2 declaring the names buffer 7-5 declaring the SQLDA 7-5 description 1-5 Dynamic SQL operations (continued) getting information about 6-13 overview 7-1 programming techniques 7-7 sample program C-1, C-9 single-code thread design for D-14 specifying input parameters 7-4 specifying output parameters 7-4 SQLDA version format D-14 using a parameter 2-23 using a parameter list 2-24 using DESCRIBE and DESCRIBE INPUT 3-16 using EXECUTE IMMEDIATE 3-18 version issues D-7 writing a Pathway server 7-3 E ELSE TAL keyword in SQL statements 3-1 Embedded SQL statements advantages 1-1 in TAL source file 1-2, 3-1, 3-2 END DECLARE SECTION directive, SQL 1-3, 2-2, 3-6 End of line, in SQL statement 3-2 END TAL keyword in SQL statements 1-2 Enscribe database data file for 2-13 memory use by program 5-32 utilities protection for SQL objects 5-22 Equivalenced local structure as host variable 2-12 Error processing using SQL procedures for 4-1 using SQLCODE for 6-1 using WHENEVER for 6-4 Errors and error messages for DELETE statement 3-13 for FETCH statement 3-18 for INSERT statement 3-19 Index-4

Index F Errors and error messages (continued) for UPDATE statement 3-42 run-time SQL recompilation 5-28 SQL compiler 5-14 Example programs static program B-10 static SQL program B-1 Exclamation point (!) for TAL comments 3-2 EXEC SQL keywords 1-2, 3-1 EXECUTE IMMEDIATE statement, SQL 1-5, 3-18 EXECUTE statement, SQL 1-5, 3-18, 7-13 Executing a TAL program 1-7 Execution plan EXPLAIN report 5-18 optimized by SQL compiler 5-11 optimized by statistics 5-11 SQL compiler function 5-11 EXPLAIN option, SQL compiler 5-5 EXPLAIN report execution plan 5-18 query decomposition 5-17 Explicit SQL compilation 1-7, 5-4 EXT option, SQLMEM directive 3-38 EXTDECS file 1-3, 3-22, 3-39, 4-1, 7-3 Extended data segment estimating memory for 5-32 managing 3-42 specifying the default 3-38 EYE^CATCHER field in SQLDA, initializing 6-18, 7-6, 7-18 F FASTSORT program 4-2, 4-8, 4-14 FETCH statement, SQL 3-34, 7-5 Fields in structures as host variables 2-8 File attributes, SQL effect of altering 5-23 File label SQL program file validation 5-22 File number of SQLMSG file 4-3, 4-15 FILEINFO command FUP 5-22 SQLCI 5-22 FILEINQUIRE system procedure 4-1 FILES catalog tables version 2 features D-8 File-system errors 2-4 displaying with SQLCADISPLAY 4-2 with SQLCAFSCODE 4-7 with SQLCAGETINFOLIST 4-8 with SQLCATOBUFFER 4-13 First error flag in SQLCAFSCODE procedure 4-8 FIXED TAL data type in TYPE AS clause 2-7 with host variable 2-12 with SETSCALE SQL function 3-21 FOR UPDATE OF clause UPDATE statement 3-45 FORCE option error messages with 5-14 SQL compiler 5-8 FREE RESOURCES statement and cursors 3-35 Functions, aggregate, SQL for C10 program migration D-5 FUP DUPLICATE command 5-22 FILEINFO command 5-22 G Generic release program description of D-12 GETPOOL system procedure 7-10, 7-17 Global area, user 3-38 GOTO format of WHENEVER 6-7 Index-5

Index H Guardian 90 operating system 4-2, 4-7, 4-8, 4-14 H HEADING attribute 4-20 HELP TEXT attribute 4-20 Host variable array as 2-11 associated indicator variable for 2-13 creating with INVOKE 2-20 date-time data types as 2-15 declaration of 1-3, 3-6 declaring 2-2 fields in a structure as 2-8 in expressions 2-2 INDICATOR clause 2-7 initializing in cursor 3-35 INTERVAL data types as 2-15 multiple DECLARE sections for 2-2 naming conventions 2-2 null values in 2-7 pointer as 2-9 scale in 2-12 string parameter as 2-11 structure as 2-8 syntax for using 2-7 TYPE AS clause 2-7 type STRING array as 2-10 using colon (:) with 1-3 using INSERT with 3-19 with DELETE statement 3-13 HP NonStop Transaction Management Facility (TMF) 1-1, 7-13 Hyphen, double (--) for SQL comments 3-2 I INCLUDE SQLCA directive 3-19, 4-2, 6-9, 7-8 INCLUDE SQLDA directive 3-19, 6-14 INCLUDE SQLSA directive 3-19, 6-11, 7-8 Incompatible features C10 description D-4 C30 enhancements D-1 Index, SQL changes and program file validity 5-23 version 2 D-2 INDICATOR clause in SETSCALE function 2-13 with host variable 2-7 Indicator parameter function 2-25 in names buffer 7-38 syntax for 2-23 Indicator variable allocating memory for 7-37 using for null value 2-17 with aggregate function 6-7 with host variable 2-7 with INVOKE directive 3-27 IND^PTR field in SQLDA structure 7-5 IND^PTR, initializing 7-18 Initializing a cursor 3-35 INNER function reserved word for C30 D-5 Input host variable with DESCRIBE and DESCRIBE INPUT 3-16 Input parameter for dynamic SQL operations 7-4, 7-10 Insert operation timestamp value 3-21 with a null value 3-20 INSERT statement, SQL 3-19 Insertion program, static SQL B-1 Installing migrated programs D-8 INT (32) TAL data type with SETSCALE SQL function 3-21 Index-6

Index J INTERVAL data types conversion of 2-4 inserting 2-16, 3-26 literals for 6-19 selecting 3-25 with INVOKE directive 3-24 INTO clause with SELECT command 3-32 INVALIDATE option, CREATE INDEX statement 5-23 INVOKE directive, SQL 2-8, 2-17, 2-20, 3-22, A-1 Item codes for SQLCAGETINFOLIST (table) 4-10 SQLCAGETINFOLIST parameter 4-8 J JOIN function for C10 program migration D-4 reserved word for C30 D-5 JULIANTIMESTAMP system procedure 3-22 L LEFT function for C10 program migration D-4 reserved word for C30 D-5 Library procedures, system 1-3 List file SQL compiler 5-6 TAL compiler 5-3 Listing, SQL compiler 5-15 Literal declarations for data types 7-21 for DATA^TYPE field 6-18 for date-time values 6-19 for INTERVAL data types 6-19 for PRECISION field 6-18 SQLDA^EYE^CATCHER 6-18 Load time, SQL 5-25 Local autonomy maximizing for distributed database 5-28 program execution 5-24 program file validity 5-23 skipping unavailable partitions to maximize 5-28 using current statistics 5-29 using TACL DEFINEs 5-29 Local partition using to maximize local autonomy 5-28 Loops, infinite avoiding with WHENEVER 6-5 M MAPPED option, SQLMEM directive 3-39 Measure program 3-37 Memory management dynamic allocation 7-14 estimating use 5-32 using SQLMEM directive 3-37 Migration, C10 program to C30 D-4 Modifying data DELETE statement 3-13 UPDATE statement 3-43 MOVEX system procedure 3-39 Moving SQL files, effect on SQL validity 5-22 MULTILAN with dynamic SQL programs 7-2 Multiple SQL releases running program on D-13 Multi-row delete 3-14 retrieval 3-33 update 3-44 N Names buffer and indicator parameters 7-38 Index-7

Index N Names buffer (continued) declaring for dynamic SQL 7-8 estimating size of 7-15 for dynamic SQL 7-23 using with a parameter 2-25 NAMES INTO clause of DESCRIBE INPUT statement 7-23 NEWPROCESS system procedure 5-30 NO AUDITCOMPRESS attribute 4-20 NO INVALIDATE option, CREATE INDEX statement 5-23 NOEXPLAIN option, SQL compiler 5-9 NOFORCE option, SQL compiler 5-8 NonStop SQL database overview 1-1 sample of A-1 using embedded SQL for 1-1 NonStop SQL directives BEGIN DECLARE SECTION 1-3, 2-2 coding of 3-1 comments in 3-2 CONTROL EXECUTOR 3-8 CONTROL QUERY 3-8 CONTROL TABLE 3-8 END DECLARE SECTION 1-3, 2-2 INCLUDE SQLCA 3-19, 4-22, 6-9, 7-8 INCLUDE SQLDA 3-19, 6-14 INCLUDE SQLSA 3-19, 6-10, 7-8 INVOKE 2-8, 2-17, 2-20, 3-22, A-1 locating information about 3-4 placing in source file 3-2 table of 1-3, 3-4 WHENEVER 6-4 NonStop SQL statements BEGIN WORK 7-13 CLOSE 3-7, 3-34 coding of 3-2 comments in 3-2 COMMIT WORK 7-14 CREATE INDEX 5-23 NonStop SQL statements (continued) CREATE TABLE 2-20, 7-2 DECLARE CURSOR 3-11 DELETE 3-13 DESCRIBE 3-16 DESCRIBE INPUT 3-16 DROP 3-17 dynamically preparing 3-30 EXECUTE 1-5, 3-18, 7-13 EXECUTE IMMEDIATE 1-5, 3-18 FETCH 3-18 INSERT 3-19, 3-26 locating information about 3-4 OPEN 3-29, 3-34 placing in source file 3-2 PREPARE 3-30, 7-10, 7-15 RELEASE 3-31 SELECT 2-15, 3-25, 3-31 table of 1-2, 3-4 UPDATE 3-42 UPDATE STATISTICS 5-11, 5-14, 5-23, 5-29 WHENEVER 7-9 NonStop SQL system procedures SQLCADISPLAY 1-3, 2-4, 4-2, 6-9 SQLCAFSCODE 4-7, 6-9 SQLCAGETINFOLIST 4-8, 6-9 SQLCATOBUFFER 4-13, 6-9 SQLGETCATALOGVERSION 4-19, D-11 SQLGETOBJECTVERSION 4-19, D-11 SQLGETSYSTEMVERSION 4-21, D-11 SQLSADISPLAY 4-22 table of 4-1 NOOBJECT option, SQL compiler 5-9 NORECOMPILE option, SQL compiler 5-10, 5-24 NOSQLMAP option, SQL directive 3-37 Not found condition, WHENEVER 6-4 Index-8

Index O NOT NULL clause and version incompatibility D-4 for C10 program migration D-4 NOWHENEVERLIST option, SQL directive 3-36 NULL keyword with INSERT statement 2-18, 3-47 with UPDATE statement 3-47 Null keyword with INVOKE directive 2-17 NULL STRUCTURE clause with INVOKE directive 3-27 Null values handling 7-36 handling for dynamic SQL 7-13 in host variable 2-17 in input parameters 7-36 in names buffer 7-38 in output variables 7-38 version incompatibility D-3 with a parameter 2-26 with INSERT statement 3-20 with INVOKE directive 3-26, 3-27 with UPDATE statement 3-47 NULL^INFO field in SQLDA structure 7-5 O OBEY command file for running TAL compiler 5-3 format for EXPLAIN report 5-19 SQLCI D-5 OBEYFORM option for EXPLAIN report 5-18 for SQL compiler 5-9 Object file binding using Binder program 5-4 for SQL compiler 5-6 for TAL compiler 5-3 Object file (continued) handling mixed versions D-12 in TACL RUN command 5-3 running Accelerator on 5-12 SQL compilation of 5-32 SQL file format of 5-12 validation for 5-22 OBJECT option, SQL compiler 5-9 Object, SQL changes and program file validity 5-23 handling mixed versions D-12 using DROP for 3-17 version 1 D-2 version 2 D-2 OPEN statement, SQL 3-29 Open statement, SQL 3-34 OPEN system procedure 7-3 Open tables, SQL 5-25 Optimized execution plan EXPLAIN PLAN report 5-18 SQL compiler function 5-11 statistics requirement 5-11 OUT file SQL compiler 5-7 TAL compiler 5-3 Output host variable valid and invalid forms 2-1 Output variable allocating space for 7-27 displaying 7-27 handling for dynamic SQL 7-11 specifying for dynamic SQL operations 7-4 Override data types generated by INVOKE 3-23 INVOKE generated 2-20 syntax for 2-5 table 2-6 Index-9

Index P P PAGES option, SQL directive 3-36 Pages, allocation of 5-34 PARAM command, TACL for SQL program file 5-30 with SQL compiler 5-13 Parameters, TACL in RUN command for SQL object file 5-30 Parameter, SQL dynamic SQL default data types 2-26 in dynamic SQL operations 2-23 indicator 2-25 syntax for 2-23 unnamed 2-23 using a list 2-24 using in a loop 2-25 Partition, local using to maximize local autonomy 5-28 Pascal programming language 1-1 Pathway, dynamic SQL server 7-3 Performance, NonStop SQL 5-24, 5-34 getting from SQLSA 6-10 PLAN option for EXPLAIN utility 5-8 Pointer, structure as host variable 2-9 PRECISION field data type literals for 6-18 in SQLDA structure 7-5 PREFIX clause with INVOKE statement 3-29 PREPARE statement, SQL 3-30, 7-10, 7-15 Process file segment (PFS) 5-31 Program development, C using mixed-version features D-12 Program development, TAL for release C10 D-10 overview of 1-2 using mixed-version features D-11 Program development, TAL (continued) using Version 2 features for C10 program D-8 Program execution for SQL program file 5-30 using TACL DEFINEs 5-31 Program size, estimating 5-32 PROGRAMS tables 5-10 Program, dynamic SQL example C-1 Program, TAL using embedded SQL 1-2 Propagating TACL DEFINEs 5-32 PUTPOOL system procedure 7-14 Q Query decomposition in EXPLAIN plan 5-17 using a parameter with 2-23 Question mark (?) as unnamed parameter 2-23 Quotes double (") in SQL statements 3-2 Quotes ( ) in SQL statements 3-2 R READ system procedure 1-3 Reading a row using FETCH statement 3-18 READUPDATE system procedure 7-3 RECOMPILE option, SQL compiler 5-9, 5-24 RECOMPILEALL option, SQL compiler 5-10, 5-25 RECOMPILEONDEMAND option, SQL compiler 5-10, 5-25 Referential integrity enforcing E-1 example of E-3 managing E-2 Relational database management system (RDBMS) 1-1 Index-10

Index S Relative table insert into 3-20 RELEASE 2 option in INCLUDE SQLDA directive D-11 RELEASE statement, SQL 3-31 RELEASE1 option in INCLUDE SQLDA directive D-11 in SQL directive 3-36, D-11, D-14 RELEASE2 option in SQL directive 3-36, D-11, D-14 Renaming program file effect on SQL validity 5-23 REPLY system procedure 7-3 Requester, SCREEN COBOL 7-3 Reserved words, SQL for C10 program migration D-5 RESTORE/BACKUP version issues D-10 Retrieving data multiple rows 3-34 single row 3-33 with cursor 3-35 RETURNING LASTSYSKEY option, INSERT statement 7-6 RISC (TNS/R) system 1-7 Row in SQL table deleting 3-14 fetching 3-7, 3-18, 3-29 inserting data in 3-19 selecting 3-32, 3-34 updating 3-43, 3-44 RTDU See Run-time data unit (RTDU) RUN command for SQL program file 1-7 RUN command, TACL for SQL object file 1-7, 5-30 Run option, TACL for SQL object file 5-31 for SQLCOMP command 5-6 Run option, TACL (continued) for TAL compiler 5-3 RUND command, TACL for SQL object file 5-30 Run-time data unit (RTDU) 3-37 Run-time memory allocation 7-14 Run-time recompilation errors 5-28 S Scale from DATA^LEN field 7-27 SEARCH directive, TAL compiler 5-4 Section location table (SLT) 3-37 Security attribute, altering effect on SQL validity 5-23 SELECT statement, SQL 3-31 Selecting data, cursor declaration 3-11 Semicolon (;) in SQL statements 1-2, 3-1 Sequential I/O (SIO) procedures 4-2, 4-6, 4-8, 4-14, 4-22, 4-23 SET DEFINE command, TACL 5-19 Set operations delete 3-14 update 3-44 SETSCALE SQL function 2-4, 2-5, 2-7, 2-12, 2-13, 3-21 Shared memory, using 3-41 Single row in SQL table deleting 3-14 selecting 3-32 updating 3-43 Single-code thread design D-13, D-14 SIO See Sequential I/O (SIO) procedures 4-22 Sizing SQL data structures 3-41 SLT See Section location table (SLT) Sort operations, using TACL DEFINEs 5-32 Index- 11

Index S SORTPROG process 4-2, 4-8, 4-14 SORT_DEFAULTS DEFINE See=_SORT_DEFAULTS DEFINE Source file, TAL compiler 5-2 SQL compilation automatic recompilation 5-24 explicit 1-7 functions of SQL compiler 5-11 insufficient information for 5-15 interpreting error messages 5-14 listing 5-15 of dynamic SQL statements 5-14 SQL compiler 1-7 unresolved TACL DEFINEs for 5-15 using a PARAM command 5-13 using DEFINEs with 5-32 using EXPLAIN utility with 5-17 warning messages for 5-14 with SQLCOMP command 5-6 SQL directive, TAL compiler 3-1, 3-2, 3-35 SQL SENSITIVE flag 5-22 SQL SENSITIVE, SQL 5-22 SQL statements See NonStop SQL statements 1-1 SQL statistics area See SQLSA data structure SQLCA data structure 4-7, 4-8, 4-14 after DELETE statement 3-13 after INSERT statement 3-20 automatic SQL recompilation errors 5-24 declaring 6-9 description of 6-9 displaying with SQLCADISPLAY 4-2 with UPDATE statement 3-42 SQLCADISPLAY system procedure 1-4, 2-4, 4-2, 6-9 SQLCAFSCODE system procedure 4-7, 6-9 SQLCAGETINFOLIST system procedure 6-9 SQLCATOBUFFER system procedure 4-13, 6-9 SQLCI See Conversational interface, NonStop SQL SQLCODE variable after DELETE statement 3-13 after FETCH statement 3-18 after INSERT statement 3-20 after UPDATE statement 3-43 checking 6-2 declaring 6-2 declaring for dynamic SQL 7-9 in data conversion 2-4 used by WHENEVER 6-4 with automatic SQL recompilation errors 5-24 SQLCOMP command 5-24 SQLDA data structure 6-13, 7-6 data type literals for 6-18 EYE^CATCHER field 6-18 fields in 6-17 names buffer 6-14 Release 1 template 6-15 Release 2 template 6-15 SQLDA^EYE^CATCHER literal 7-10, 7-11, 7-18 SQLGETCATALOGVERSION system procedure 4-19, D-11 SQLGETOBJECTVERSION system procedure 4-19, D-11 SQLGETSYSTEMVERSION system procedure 4-21, D-11 SQLIN data structure 3-37 SQLIVARS data structure 3-37 SQLMAP option, SQL directive 3-37 SQLMEM directive, TAL compiler 3-1, 3-38 SQLMSG file number 4-3 SQLMSG file description of 4-6, 4-18 Index-12

Index S SQLMSG file (continued) file number 4-15 with SQLCADISPLAY procedure 4-15 with SQLCATOBUFFER procedure 4-15 SQLOVARS data structure 3-37 SQLSA data structure description of 6-1 with PREPARE statement 3-31 STACK option, SQLMEM compiler directive 3-3 STACK option, SQLMEM directive 3-39 Statements, NonStop SQL See also NonStop SQL statements table of 1-2 Static SQL operations description 1-4 version issues D-8 Static SQL statements, using 1-4 Statistics displaying with SQLCATOBUFFER 4-13 for SQL compilation 5-11 unavailable for maximizing local autonomy 5-28 Statistics area, SQL See SQLSA data structure Status reporting 6-1 STOREDDEFINES option for SQL compiler 5-8 in SQLCOMP command 5-32 STRING parameter as host variable 2-11 STRING type array as host variable 2-11 STRIP command, Binder 5-4 Structure as host variable 2-8 Structure pointer as host variable 2-9 Structure template, by INVOKE 3-23 Suffix clause with INVOKE statement 3-29 Swap file volume for SQL compiler 5-13 SWAPVOL option in PARAM command 5-13 SYMBOLPAGES directive, TAL compiler 3-1, 3-3, 3-42 SYSKEY with INSERT statement 3-20 System procedure GETPOOL 7-17 System procedures ALLOCATESEGMENT 3-41 CLOSE 1-3 CONVERTTIMESTAMP 3-22 DEFINEPOOL 7-17 GETPOOL 7-10 JULIANTIMESTAMP 3-22 MOVEX 3-39 NEWPROCESS 1-7, 5-30 OPEN 7-3 PUTPOOL 7-14 READ 1-3 READUPDATE 7-3 REPLY 7-3 table of 4-1 USESEGMENT 3-38 WRITEREAD 1-3 System procedures, NonStop SQL SQLCADISPLAY 2-4 SQLCADISPLAY procedure 1-4 SQLCAGETINFOLIST 4-8 SQLGETCATALOGVERSION 4-19, D-11 SQLGETOBJECTVERSION 4-19, D-11 SQLGETSYSTEMVERSION 4-21, D-11 SQLSADISPLAY 4-22 Index-13

Index T T Table, SQL changes and program file validity 5-23 maximizing local autonomy for partitions 5-28, 5-30 open time and automatic SQL recompilation 5-25 using SELECT statement 3-32 version 2 D-2 TACL ASSIGN command for SQL program file 5-30 DEFINEs ADD DEFINE command 5-19 CLASS CATALOG 5-7 DEFMODE option 5-19, 5-32 for automatic SQL recompilation 5-25 for SQL program execution 5-32 for SQL program file 5-30 propagating 5-32 SET DEFINE command 5-19 using to maximize local autonomy 5-29 using with SQL compiler 5-32 using with TAL compiler 5-31 in sample program B-1, C-1 PARAM command for SQL program file 5-30 RUN command for SQL object file 5-30 for TAL compiler 5-3 parameters for SQL object file 5-30 run option for SQL object file 5-31 for SQLCOMP command 5-7 for TAL compiler 5-3 RUND command for SQL object file 5-30 Timestamp check at table open time 5-25 program validation time 5-22 run-time check 5-26 with INSERT statement 3-21 TNS/R 1-7 Transaction Application Language (TAL) compiler running 3-2 using TACL DEFINEs with 5-31 WHENEVER pseudocode 6-4 compiler directives DATAPAGES 7-8 in RUN command 5-4 SEARCH 3-3, 5-4 SOURCE 3-3 SQL 3-1, 3-2, 3-40, 5-4 SQLMEM 3-1, 3-42 SYMBOLPAGES 3-1, 3-3, 3-42 compiler syntax 5-6 ELSE keyword in SQL statements 1-2, 3-1 END keyword in SQL statements 1-2, 3-1 program development with 1-2 TALDECS 6-18, 7-21 TALLIB 1-7, 7-8 TALLIB file 5-5 UNTIL keyword in SQL statements 1-2, 3-1 Transaction Manangement Facility (TMF) See HP NonStop Transaction Manangement Facility TRANSIDS tables 5-10 Two-code thread design D-13 TYPE AS clause examples of 2-16 with a parameter 2-24 with date-time data 2-16 with host variable 2-5, 2-7 Index-14

Index U U Uncompiled SQL statements, FORCE option 5-14 Underscore (_) in host variable names 2-2 UNTIL TAL keyword in SQL statements 1-2, 3-1 Update operation multiple rows 3-14 set of rows 3-14 single row 3-14 using indicator parameter in 2-23 using null values in 2-17 with null values 3-47 UPDATE statement, SQL 3-42 Update statistics effect on SQL validity 5-23 optimized execution plan 5-14 UPDATE STATISTICS statement, SQL 5-11, 5-14, 5-23 UPDATE WHERE CURRENT clause for a cursor 7-32 USAGES table 5-11 recorded program dependencies 5-23 unrecorded program dependencies 5-15 Usages table 5-10 USER option, SQLMEM directive 3-38 USESEGMENT system procedure 3-38 USING DESCRIPTOR clause for a cursor 7-32 in FETCH statement 7-5 V VALID flag, SQL 5-22 Validation program file 5-22 with error conditions 5-14 VARCHAR data type as host variable 2-8 VARCHAR data type columns with INVOKE directive 3-24 VAR^PTR field in SQLDA structure 7-5 VERIFY utility, SQL 5-22 Version information data types D-1 descriptions D-2 features D-1 functions D-1 using SQLGETCATALOGVERSION 4-19, D-2, D-11 using SQLGETOBJECTVERSION 4-19, D-2, D-11 using SQLGETSYSTEMVERSION 4-21, D-2, D-11, D-13 versioning PVU D-9 Version Management, NonStop SQL A-2 VERSIONS catalog table D-12 View, SQL changes and program file validity 5-23 version 2 D-2 W Warning messages detecting with WHENEVER 6-4 for SQL compiler 5-14 WHENEVER directive, SQL 6-4, B-11 WHENEVERLIST option, SQL directive 3-36 WHERE clause in subquery for C10 program migration D-6 WHERE CURRENT OF in DELETE statement 3-15 WHERE CURRENT OF clause in DELETE statement 3-15 in UPDATE statement 3-45 Index-15

Index Z WRITEREAD system procedure 1-3 Z ZZBInnnn object file 5-4 Special Characters! (exclamation point) for TAL comment 3-2 " (double quote) in SQL statement 3-2 -- double hyphen in SQL comment 3-2 : (colon) with host variable 1-3 ; (semicolon) in SQL statement 3-1 =_DEFAULTS DEFINE, TACL propagating 5-32 used by EXPLAIN utility 5-18 =_SORT_DEFAULTS DEFINE 5-32? (question mark) as unnamed parameter 2-23 (single quote) in SQL statement 3-2 Index-16