Top Banner

of 88

Netezza_stored_procedures_guide.pdf

Oct 30, 2015

Download

Documents

irshad_sk

Natezza
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
  • IBM Netezza 6.0.3 and LaterIBM Netezza Stored Procedures Developers GuideRevised: September 26, 201120470-03 Rev. 2

  • Note: Before using this information and the product that it supports, read the information in Notices and Trademarks on page C-1.

    Copyright IBM Corporation 2009, 2011.US Government Users Restricted Rights Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.

  • Contents

    Preface

    1 Introduction to Stored ProceduresStored Procedures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-1

    NZPLSQL Language. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-2

    SQL Commands for Stored Procedures. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-2

    Stored Procedures Input and Return Types. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-3

    How to Create and Use a Stored Procedure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-3

    How to Execute a Stored Procedure. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-3

    Best Practices for Developers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-4

    Security Considerations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-4

    Cross-Database Access to Stored Procedures . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-4

    Block Quoting Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-5

    SQL Restrictions within the Stored Procedure. . . . . . . . . . . . . . . . . . . . . . . . . . . 1-6

    Best Practices for Netezza Administrators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-6

    Backing Up and Restoring Stored Procedures . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-7

    Upgrading and Patching Netezza Systems that Have Stored Procedures . . . . . . . . 1-7

    Downgrading Netezza Systems with Stored Procedures . . . . . . . . . . . . . . . . . . . . 1-7

    2 NZPLSQL Statements and GrammarNZPLSQL Structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-1

    Comments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-2

    Variables and Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-2

    Parameter Passing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-4

    Argument List and Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-4

    Variable Scoping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-5

    Data Types and Aliases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-6

    Array Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-9

    Expressions. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-9

    Literals and Math Operations in Expressions. . . . . . . . . . . . . . . . . . . . . . . . . . . 2-10

    Statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-14

    Assignment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-14

    Calling Another Procedure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-14

    Executing Dynamic Queries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-15iii

  • Obtaining Other Results Status . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-15

    Returning From a Procedure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-16

    Control Structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-16

    Conditional Control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-16

    Iterative Control. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-17

    Working with Records . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-19

    Declaration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-19

    Assignments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-19

    Iterating Through Records . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-20

    Aborting and Messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-21

    Exceptions and Error Messages Support. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-22

    Returning a Result Set. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-23

    Managing Large Datasets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-25

    Advanced Development Topics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-25

    Extending the Language with UDFs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-25

    Tips and Developer Best Practices. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-26

    3 Creating and Managing Stored ProceduresManaging User Account Permissions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-1

    Granting Create Permission . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-2

    Granting All Object Permissions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-2

    Revoking Create Permission . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-2

    Managing Alter Permission . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-2

    Managing Execute Permission. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-2

    Managing Drop Permission . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-3

    Creating a Stored Procedure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-3

    Design a Stored Procedure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-3

    Create a Stored Procedure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-3

    Understanding Size-Specific, Generic, and Variable Argument Procedures . . . . . . 3-5

    Obfuscating the Procedure Body . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-7

    Calling or Invoking a Stored Procedure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-10

    Altering a Stored Procedure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-10

    Commenting on a Stored Procedure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-11

    Dropping a Stored Procedure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-11

    Showing Information About a Stored Procedure . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-12

    NzAdmin UI for Stored Procedures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-12iv

  • Appendix A: SQL ReferenceALTER PROCEDURE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-1

    Synopsis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-1

    Inputs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-2

    Outputs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-2

    Description . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-3

    Usage. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-4

    CALL and EXEC[UTE [PROCEDURE]] . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-4

    Synopsis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-4

    Inputs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-4

    Outputs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-4

    Description . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-5

    Usage. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-5

    CREATE [OR REPLACE] PROCEDURE. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-6

    Synopsis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-6

    Inputs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-6

    Outputs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-7

    Description . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-8

    Usage. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-8

    DROP PROCEDURE. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-9

    Synopsis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-9

    Inputs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-9

    Outputs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-9

    Description . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-10

    Usage. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-10

    SHOW PROCEDURE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-10

    Synopsis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-10

    Inputs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-11

    Outputs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-11

    Description . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-11

    Usage. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-12

    Appendix B: Stored Procedure ExamplesVariable Argument Stored Procedure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . B-1

    Example of Simulating an Anonymous Block . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . B-2

    Appendix C: Notices and TrademarksNotices. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . C-1v

  • Trademarks. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . C-3

    Open Source Notifications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . C-4

    Electronic Emission Notices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . C-6

    Regulatory and Compliance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . C-9

    Indexvi

  • List of Tables

    Table 2-1: Supported Data Types for Variables . . . . . . . . . . . . . . . . . . . . . . . . . 2-7

    Table A-1: Stored Procedure SQL Commands. . . . . . . . . . . . . . . . . . . . . . . . . . A-1

    Table A-2: ALTER PROCEDURE Input. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-2

    Table A-3: ALTER PROCEDURE Output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-2

    Table A-4: CALL and EXEC[UTE [PROCEDURE]] Input . . . . . . . . . . . . . . . . . . . A-4

    Table A-5: CALL and EXEC[UTE [PROCEDURE]] Output . . . . . . . . . . . . . . . . . . A-4

    Table A-6: CREATE OR REPLACE PROCEDURE Input . . . . . . . . . . . . . . . . . . . A-6

    Table A-7: CREATE [OR REPLACE] PROCEDURE Output . . . . . . . . . . . . . . . . . A-7

    Table A-8: DROP PROCEDURE Input . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-9

    Table A-9: DROP PROCEDURE Output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-9

    Table A-10: SHOW PROCEDURE Input . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-11

    Table A-11: SHOW PROCEDURE Output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-11vii

  • viii

  • PrefaceThe IBM Netezza Stored Procedures Developers Guide describes how to create and use stored procedures on a Netezza data warehouse appliance.

    About This Guide

    This guide is written for IBM Netezza users who plan to create and use stored proce-dures. The guide contains the following topics:

    The Purpose of This Guide

    This guide describes how to create stored procedures on an IBM Netezza system using the Netezza procedural language, NZPLSQL. It provides an overview of the language and state-ments, and how to create, alter, and drop procedures using Netezza SQL commands.

    To use this guide, you should be very familiar with the Netezza systems and architecture, as well as Netezza SQL commands and how to access a Netezza database. You should also be familiar with the general concepts of stored procedures, how to create structured language programs, and how to debug applications.

    Symbols and Conventions

    This guide uses the following typographical conventions:

    Italics for terms, and user-defined variables such as file names Upper case for SQL commands; for example INSERT, DELETE Bold for command line input; for example, nzsystem stop

    Topics See

    An overview of stored procedures, their use, and how to develop them for a Netezza system

    Introduction to Stored Procedures on page 1-1

    A description of the NZPLSQL language statements

    NZPLSQL Statements and Grammar on page 2-1

    How to create, manage, and drop stored pro-cedures using SQL commands and the NzAdmin interface

    Creating and Managing Stored Proce-dures on page 3-1

    A reference of the new Netezza SQL com-mands for creating and managing stored procedures

    SQL Reference on page A-1

    Examples of stored procedures Stored Procedure Examples on page B-1ix

  • If You Need Help

    If you are having trouble using the Netezza appliance, you should:

    1. Retry the action, carefully following the instructions given for that task in the documentation.

    2. Go to the Netezza Knowledge Base at https://knowledge.netezza.com. Enter your sup-port username and password. You can search the knowledge base or the latest updates to the product documentation. Click Netezza HelpDesk to submit a support request.

    3. If you are unable to access the Netezza Knowledge Base, you can also contact Netezza Support at the following telephone numbers:

    North American Toll-Free: +1.877.810.4441 United Kingdom Free-Phone: +0.800.032.8382 International Direct: +1.508.620.2281

    Refer to your Netezza maintenance agreement for details about your support plan choices and coverage.

    Comments on the Documentation

    We welcome any questions, comments, or suggestions that you have for the IBM Netezza documentation. Please send us an e-mail message at [email protected] and include the following information:

    The name and version of the manual that you are using Any comments that you have about the manual Your name, address, and phone numberWe appreciate your comments on the documentation. x

  • C H A P T E R 1Introduction to Stored Procedures

    Whats in this chapter Stored Procedures How to Create and Use a Stored Procedure How to Execute a Stored Procedure Best Practices for Developers Best Practices for Netezza Administrators

    This chapter provides an overview of the support for stored procedures in the IBM Netezza family of data warehouse appliances. Stored procedure support is available in Netezza Release 4.6 and later. This guide describes changes available in Release 6.0.x and later.

    Stored Procedures

    Netezza stored procedures combine the benefits of SQL to query and manipulate database information with the benefits of a procedural programming language to handle data pro-cessing, transaction logic, and application branching behaviors.

    For example, if you have a database that contains customer information, inventory, and sales records, you might also have an application that processes the sale of an item in inventory. When an order request arrives, the application might be designed to query the database to determine how many items of that type are available in inventory, and then to take actions such as the following:

    If the available inventory is less than the order number, the application processes the request for the available number and notifies an order administrator to order more inventory to complete the purchase.

    If the available inventory is greater than the order request, the application processes the order and updates the database to show the reduction in the current inventory.1-1

    If the inventory is discontinued, the application saves the order request and returns a message that the item is no longer available. It may also query for related or replace-ment inventory to report alternative merchandise.

    While such an application could be managed with a third-party business application that accesses the Netezza database to perform these tasks, you can also use Netezza stored pro-cedures to encapsulate this application as an object in the Netezza database. SQL provides the power to access and update the database information on the host, and the procedure

  • IBM Netezza Stored Procedures Developers Guidelanguage provides the logic for if-then-else branching and application processing.

    Because the application resides on the Netezza host, the application performance can ben-efit from its location onsite by avoiding the network time between an application client system and the Netezza host. The application itself also becomes easier to maintain, as it resides in only one location (the Netezza host) and thus versioning and updates need only be made in one place to keep the application up-to-date for all users.

    With Netezza stored procedures, you can also take advantage of security and access bene-fits. Stored procedures can be defined to run with the credentials of the user who created the procedure or the credentials of the user who is running the procedure. The procedure manages the access to information contained in various base tables and views. You can grant a user permission to run a stored procedure without granting that user explicit access to underlying tables or views.

    NZPLSQL LanguageYou implement stored procedures on the Netezza host by creating applications using the NZPLSQL language. NZPLSQL is an interpreted language which is based on Postgres PL/pgSQL language and designed for the Netezza host environment.

    NZPLSQL is a scripting language embedded in SQL. As a procedural language, it has branch, loop, and subprogram structures while SQL provides the main program. The sub-programs, known as procedures, can take arguments and declare internal variables. Once stored in a database, these procedures can be called from within other databases on the same Netezza host.

    The NZPLSQL language provides for the following types of procedural logic:

    Conditionals (if/else) Looping (while, for) Execution of SQL (including dynamic SQL) Variables Returning a scalar result or a result set Input arguments Execution in the calling context (session and transaction) Extending functionality (adding NZPLSQL library routines)

    SQL Commands for Stored ProceduresTo support stored procedures in the Netezza database, the Netezza SQL language has been extended to include new commands for stored procedures:

    ALTER PROCEDURE CALL or EXEC[UTE[ PROCEDURE]] CREATE [OR REPLACE] PROCEDURE DROP PROCEDURE SHOW PROCEDURE1-2 20470-03 Rev.2

  • How to Create and Use a Stored ProcedureYou can use any SQL tool that supports ODBC, JDBC, OLE-DB to enter these commands. This document contains examples that use the nzsql command line tool.

    Appendix A, SQL Reference, describes these commands and their syntax in detail. In addition to these procedure-specific commands, you can also use the commands GRANT and REVOKE to permit or deny access to procedures, as well as COMMENT ON to add descriptions and details to the procedure definitions. For more information about managing procedures, refer to Chapter 3, Creating and Managing Stored Procedures.

    Stored Procedures Input and Return TypesNetezza stored procedures are a hybrid between functions and procedures (as defined by the SQL:2003 standard for SQL-invoked routines). In the Netezza implementation, an NZPLSQL stored procedure takes only input arguments and supports a return value as functions do. Unlike functions, a stored procedure must be called using CALL or a similar construct, and it is not allowed in the usual query locations where a built-in or standard function is allowed.

    Note: A stored procedure can also be designed to return a result set. For more information, see Returning a Result Set on page 2-23.

    How to Create and Use a Stored Procedure

    As a high-level summary, follow these steps to create and use a stored procedure. These steps are described in more detail in Chapter 3, Creating and Managing Stored Procedures.

    1. Design the stored procedure logic and operation.

    2. Define the stored procedure object using the CREATE [OR REPLACE] PROCEDURE command.

    3. Run or execute the procedure from the SQL command prompt.

    As with other Netezza objects, the Netezza admin user can create, list, and execute stored procedures by default. The admin user may also grant other users permission to create, list, and execute stored procedures on the Netezza system. For more information about permis-sions, see Managing User Account Permissions on page 3-1.

    How to Execute a Stored Procedure

    You execute a stored procedure in the SQL command using either the CALL or EXEC[UTE[ PROCEDURE]] commands. For example, if you have a stored procedure named update-acct(), you can run it using any of the following commands:

    MYDB(USER)=> CALL updateacct(); MYDB(USER)=> EXEC updateacct();MYDB(USER)=> EXECUTE updateacct();MYDB(USER)=> EXECUTE PROCEDURE updateacct();

    You can also use the SELECT command to execute a procedure; however, you cannot spec-ify a FROM clause. For example:

    MYDB(USER)=> SELECT updateacct();20470-03 Rev.2 1-3

  • IBM Netezza Stored Procedures Developers GuideTo execute the procedure, the user must be the owner of or have permission to execute the updateacct() procedure. For more information about the CALL and EXEC[UTE[ PROCE-DURE]] commands, refer to Appendix A, SQL Reference.

    Best Practices for Developers

    The following sections describe some best practices for users who develop stored procedures.

    Security ConsiderationsWhen you define a stored procedure, you can specify whether the Netezza system should execute the procedure using the ID of the owner who created the stored procedure or the ID of the user who runs the procedure. This allows you an additional layer of security (or expanded access) for the data processed by the stored procedure.

    For example, if the admin user created the stored procedure and specified execute as owner permissions, which is the default, then any other user who is permitted to execute the procedure will run the procedure as the admin user. This could, for example, allow the user to see results from tables or views that he or she does not have permission to access using SQL directly.

    If the procedure should access only the data that the user is permitted to see, the stored procedure should be defined as execute as caller. In this case, the procedure uses the user ID of the calling user, and thus the access permissions of that user.

    Cross-Database Access to Stored ProceduresWhen you create a stored procedure using the CREATE [OR REPLACE] PROCEDURE com-mand, the command adds the procedure to the database to which you are connected. You can define the stored procedure in more than one database if necessary.

    Typically, most users are logged in to the database that contains the stored procedure that they plan to run. However, the Netezza system allows for cross-database access of stored procedures using two methods:

    Using fully-qualified object names when calling a procedure object that resides within a different database, for example:

    MYDB(ADMIN)=> EXEC OTHERDB..UPDATEACCT();

    Using the PATH SQL session variable to specify the databases to search to find a proce-dure. To use the PATH session variable, you enter a command similar to the following:

    MYDB(ADMIN)=> SET PATH = [, ]; The value can be a database name or the variables CURRENT_CATALOG, CURRENT_USER, CURRENT_SCHEMA or CURRENT_PATH. Anything you specify as must resolve to a database name.

    For example:

    MYDB(ADMIN)=> SET PATH = mydb, nzdb, customer;SET VARIABLE

    To display the PATH value, use the following command:1-4 20470-03 Rev.2

  • Best Practices for DevelopersMYDB(ADMIN)=> SELECT CURRENT_PATH;CURRENT_PATH

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

    MYDB,NZDB,CUSTOMER(1 row)

    The Netezza system uses the PATH variable during the lookup of any unqualified proce-dures. It searches the current database if PATH is not set; otherwise it searches the databases specified in PATH, in the order that they are specified. The Netezza system uses the first match that it finds, even if a better match might exist in a subsequent database. A poorer match is one that might require implicit casting of arguments or that causes an error due to multiple potential matches. Note that PATH searches databases, not schemas, as there is no schema support for this capability. Also, the Netezza system uses the PATH ses-sion variable to find only stored procedures, user-defined functions (UDFs), and user-defined aggregates (UDAs). Other object types are not supported.

    It is important to note that if a stored procedure is invoked from a different database, unqualified objects will bind to objects in the invoking database, not in the database where the stored procedure resides. Note that unqualified stored procedures, UDFs, and UDAs are exceptions to this rule because the Netezza system first uses the PATH variable to search for those three object types before it searches within the invoking database.

    If you plan to invoke cross-database calls to stored procedures that access data in other databases, make sure that the stored procedure uses fully-qualified object names to refer to those data objects.

    Note: Certain types of operations will not work across databases, such as insert, update, and delete operations. For any procedure which contains those types of operations, make sure that you are connected to the database where the stored procedure is defined.

    Block Quoting Support Since stored procedures are defined as a block or body of numerous lines of text, Netezza provides a block-quoting mechanism to help ease the definition of the procedure body as well as to make the content more readable for debugging and learning.

    A section of text bounded by BEGIN_PROC and END_PROC is a block quote. An example follows:

    CREATE OR REPLACE PROCEDURE name() RETURNS INT4 LANGUAGE NZPLSQL ASBEGIN_PROC DECLARE

    string varchar;BEGIN

    string := 'This string is quoted';END;END_PROC;

    As shown in the example, single quotes are not escaped within the block-quoted string. The string content is always written literally. Backslashes have no special escape meaning.

    Note: The stored procedure body is in clear text format by default. Permitted users can use the SHOW PROCEDURE VERBOSE command and interfaces such as NzAdmin to review the stored procedure. If necessary, you can hide the procedure code when you create the procedure. For more information, see Obfuscating the Procedure Body on page 3-7.

    Block quotes are intended for use only in NZPLSQL body quoting or stored procedure invo-cation. The execution commands CALL and EXEC[UTE[ PROCEDURE]] support them, 20470-03 Rev.2 1-5

    although SELECT does not. They can be used inside a stored procedure body to build DDL

  • IBM Netezza Stored Procedures Developers Guidestatements where they are allowed, but they have no quoting implications inside the body. If they are used inside the body, make sure that there are an equal number of both key-words and that they match (a BEGIN_PROC appears before the corresponding END_PROC) to avoid errors. If your program logic dictates that they are not matching, they must be bro-ken up (that is, 'BEGIN_' || 'PROC').

    Both BEGIN_PROC and END_PROC can appear inside a single or double-quoted string in normal SQL statements, as long as the SQL statements are not inside a block quote. For example:

    select "BEGIN_PROC" from ;insert into values ('BEGIN_PROC');

    If you want to do this inside a block quote body, then you must have a matching END_PROC. For example:

    CREATE OR REPLACE PROCEDURE name() RETURNS INT4 LANGUAGE NZPLSQL ASBEGIN_PROC DECLARE

    string varchar;BEGIN

    string := 'This string is quoted';-- This comment is the match for below BEGIN_PROCinsert into va values ('END_PROC');

    END;END_PROC;

    Because nested BEGIN_PROC and END_PROC keywords have no quoting implications, the following example is not supported:

    CREATE OR REPLACE PROCEDURE name() RETURNS INT4 LANGUAGE NZPLSQL ASBEGIN_PROCDECLARE

    string varchar;BEGIN

    -- The next statement is a syntax error since it is not quotedstring := BEGIN_PROC This string is not quoted END_PROC;

    END;END_PROC;

    SQL Restrictions within the Stored ProcedureWithin the body of a stored procedure, you can use most SQL commands to perform tasks relating to database objects. However, you cannot use SQL commands that are prohibited for use within a BEGIN/COMMIT transaction block. For a description of the transaction control practices and command restrictions, see the IBM Netezza Database Users Guide.

    Best Practices for Netezza Administrators

    The following sections describe some best practices for Netezza administrators who man-age Netezza systems that have stored procedures. 1-6 20470-03 Rev.2

  • Best Practices for Netezza AdministratorsBacking Up and Restoring Stored Procedures Any stored procedures that you create are backed up and restored by the Netezza backup and restore operations. If you backup and restore obfuscated procedures, those restored procedures remain obfuscated. If you restore a database to a system that is running a release which does not support obfuscated procedures or VARARGS, for example, those procedures will not run and the queries that use them will return a syntax error.

    If you drop a database, note that all the objects defined in the database including stored procedures are likewise dropped. As a best practice, you should keep backup copies of your source CREATE OR REPLACE PROCEDURE definitions in a safe location outside of the Netezza system. Make sure that you have recent backups of your Netezza systems in the event that you need to recover from an accidental deletion or change, or to restore Netezza services as part of a disaster recovery situation.

    Upgrading and Patching Netezza Systems that Have Stored ProceduresThere are no special requirements or procedures necessary to preserve any stored proce-dures during a service pack update or an upgrade to a new release. The stored procedures should continue to operate in the same manner on the newly updated or upgraded system as on the previous release.

    If you downgrade the system, note that your stored procedures should continue to run if the downgrade release also supports stored procedures. However, if you downgrade from a Release 6.0.x version to a previous release such as 5.0.x which does not support obfus-cated procedures or VARARGS, for example, those procedures will not run and the queries that use them will return a syntax error.

    If the new release or service pack introduces any new features or changes that could affect the operation of stored procedures, Netezza will describe the changes in the release notes for the service pack or release. Before you install any new release or service pack, you should review the release notes to familiarize yourself with any new features, changes, fixes, and known issues for that release. You should also make sure that you have a recent backup of your Netezza system before you upgrade the system.

    Downgrading Netezza Systems with Stored ProceduresIf you downgrade your Netezza release, note that downgrades to any releases prior to Release 4.6 will drop all stored procedures automatically. If you downgrade to a release that supports stored procedures, the procedures should continue to work after the down-grade, unless your stored procedures use features that were available only in the later release. 20470-03 Rev.2 1-7

  • IBM Netezza Stored Procedures Developers Guide1-8 20470-03 Rev.2

  • C H A P T E R 2NZPLSQL Statements and Grammar

    Whats in this chapter NZPLSQL Structure Comments Variables and Constants Array Variables Expressions Statements Control Structures Working with Records Aborting and Messages Exceptions and Error Messages Support Returning a Result Set Advanced Development Topics

    This chapter describes the NZPLSQL language, its structure, and how to use the language to create stored procedures.

    NZPLSQL is very similar to the Postgres PL/pgSQL language. Some of the language descriptions in this chapter leverage the Postgres PL/pgSQL documentation. However, NZPLSQL has some differences which are based on the Netezza systems design and envi-ronment. NZPLSQL also includes some extensions to assist users who may be migrating stored procedures written in other languages to the Netezza environment.

    NZPLSQL Structure

    NZPLSQL is a block structured language. A block is defined as follows:

    [][DECLARE2-1

    declarations]BEGINstatements

    [EXCEPTION WHEN OTHERS THENhandler statements] END;

  • IBM Netezza Stored Procedures Developers GuideThe statements section of a block can contain zero, one, or more sub-blocks. A sub-block is used for logical grouping or to localize variables to a small group of statements.

    All of the keywords and identifiers are case-insensitive and can be used in mixed upper- and lower-case mode. Identifiers are automatically converted to uppercase, as they are in general SQL statements, unless they are enclosed in quotes to keep them case-sensitive.

    The variables declared in the declarations section preceding a block are initialized to their default values every time the block is entered, not just once per procedure call.

    Note: Be careful not to confuse the use of BEGIN/END for grouping statements in NZPLSQL with the BEGIN/END SQL database commands for transaction control. The NZPLSQL BEGIN/END keywords are used only for grouping; they do not start or end a transaction. Procedures are always executed within a transaction established by an outer querythey cannot start or commit transactions, since Netezza SQL does not have nested transactions.

    Comments

    There are two types of comments in NZPLSQL.

    A double dash (--) starts a comment that extends to the end of the line. For example:-- This is a comment line.

    A forward-slash asterisk pair (/*) starts a block comment, which extends to the next occurrence of the ending sequence which is an asterisk forward-slash (*/) pair. For example:

    /* This is a block comment, which can span multiple lines.

    Any code inside the block such as:

    url varchar := 'http://www.netezza.com'is ignored. */

    Block comments cannot be nested, but double dash comments can be enclosed in a block comment. Note that a double dash can hide the block comment delimiters /* and */.

    Variables and Constants

    All of the variables, rows, and records that are used in a block or its sub-blocks must be declared in the declarations section of a block. (There are some exceptions, namely the loop variable of a FOR loop that iterates over a range of integer values, and some built-in variables like FOUND, ROW_COUNT, and LAST_OID.)

    NZPLSQL variables can have any SQL datatype, such as INTEGER, VARCHAR, and CHAR. Some sample variable declarations follow:

    user_id INTEGER;

    quantity NUMERIC(5,2);url VARCHAR;

    A variable declaration has the following syntax:

    name [ CONSTANT ] type [ NOT NULL ] [ { DEFAULT | := } value ];2-2 20470-03 Rev.2

  • Variables and Constants The DEFAULT clause, if included, specifies the initial value assigned to the variable when the block is entered. If a DEFAULT clause is not specified, the variable uses the SQL NULL value as its default.

    The CONSTANT option means that the variable cannot be changed; its value remains constant for the duration of the block.

    If NOT NULL is specified, an assignment of a NULL value results in a runtime error. Since the default value of all variables is the SQL NULL value, all variables declared as NOT NULL must also specify a non-null default value.

    When specifying types in declarations, NUMERIC may be specified with or without a preci-sion and scale. CHAR, NCHAR, VARCHAR, and NVARCHAR may be specified with or without a size. When these types are specified with a size or a precision/scale, assignment to the variable will follow normal cast rules. If they are specified without sizes, assignment will preserve the original source size or precision/scale.

    The default value is evaluated each time the procedure is called. So assigning now() to a variable of type timestamp causes the variable to be set to the time of the actual procedure call, not the time when the procedure was precompiled into its bytecode.

    Some examples of variable assignments follow:

    quantity INTEGER := 32;

    url varchar := 'http://mysite.com';user_id CONSTANT INTEGER := 10;

    Using the %TYPE and %ROWTYPE attributes, you can declare variables with the same datatype or structure of another database item (for example, a table field).

    %TYPE provides the datatype of a variable or database column. You can use this to declare variables that will hold database values. For example, if you have a column named user_id in your users table, you can declare a variable with the same datatype as user_id as follows:

    user_id users.user_id%TYPE;

    By using %TYPE, you do not have to know the datatype of the structure that you are refer-encing. Also, if the datatype of the referenced item changes in the future (for example, you change your table definition of user_id to become a REAL), you do not have to change your procedure definition.

    You can declare a row with the structure of a given table, as follows:

    name table%ROWTYPE;

    The table value must be an existing table or view name of the database. The fields of the row are accessed using the dot notation.

    Only the user attributes of a table row are accessible in the row. You cannot access an OID or other system attribute because the row could be from a view. The fields of the rowtype inherit the table's sizes or precision for CHAR, NCHAR, and NUMERIC data types, as applicable. 20470-03 Rev.2 2-3

  • IBM Netezza Stored Procedures Developers GuideParameter Passing In NZPLSQL, parameters are not named. Instead, only the data types are passed, and parameters are referenced via their position. To name parameters, use the ALIAS FOR syn-tax. For example:

    CREATE OR REPLACE PROCEDURE p1 (int, varchar(ANY)) RETURNS int LANGUAGE NZPLSQL ASBEGIN_PROCDECLARE

    pId ALIAS FOR $1; pName ALIAS FOR $2;

    BEGININSERT INTO t1 SELECT * FROM t2 WHERE id = pId;

    The example highlights the recommended convention to name parameters with a p prefix to differentiate them from variables. This convention is helpful because parameters are constant and cannot be modified. If a parameter must be updated (for example, to assign it a default value if it is null), assign the parameter to a variable and update the variable. For example:

    DECLAREpId ALIAS FOR $1;vID integer;

    BEGINvId := ISNULL(pId, 0);INSERT INTO t1 SELECT * FROM t2 WHERE id = vId;

    Argument List and VariablesThe arguments passed as input to procedures can be identified using the names $1 (first argument), $2 (second argument), and so on. You can also use the $var notation, which takes the integer value of var to identify the input value specified in that order position.

    You can specify from 0 to 64 arguments. If you specify VARARGS in the input argument list, users can input any number of arguments up to a maximum of 64.

    Netezza saves the OIDs of the input arguments in the PROC_ARGUMENT_TYPES array. The array has the same size as the number of parameters that are passed to the stored pro-cedure. Its elements are of type OID and contain the OID type of the corresponding input argument. You can use the array to obtain the number and type of each argument.

    For example:

    CREATE OR REPLACE PROCEDURE test(VARARGS)RETURNS INT4LANGUAGE NZPLSQLAS BEGIN_PROC

    DECLAREnum_args int4;typ oid;idx int4;

    BEGINnum_args := PROC_ARGUMENT_TYPES.count;RAISE NOTICE 'Number of arguments: %', num_args;for i IN 0 .. PROC_ARGUMENT_TYPES.count - 1 LOOP

    typ := PROC_ARGUMENT_TYPES(i);2-4 20470-03 Rev.2

    idx := i+1;

  • Variables and ConstantsRAISE NOTICE 'argument $% is type % and has the value ''%''', idx, typ, $idx;

    END LOOP;END;

    END_PROC;

    A sample call follows:

    MYDB(USR2)=> CALL TEST (1, 3, 9::bigint, 'test value', 324.56);NOTICE: Number of arguments: 5NOTICE: argument $1 is type 23 and has the value '1'NOTICE: argument $2 is type 23 and has the value '3'NOTICE: argument $3 is type 20 and has the value '9'NOTICE: argument $4 is type 705 and has the value 'test value'NOTICE: argument $5 is type 1700 and has the value '324.56'test------

    (1 row)

    Variable ScopingWhen you explicitly declare a new variable (or name), the scope of the variable is the block in which it is defined. For example, the following sample defines a variable named val in the blocks DECLARE section, and then defines another val variable in the blocks DECLARE section. Although the variables have the same name, these are two different variables:

    DECLARE

    val int4;BEGIN

    val := 5;

    DECLARE

    val int4;BEGIN

    val := 7;RAISE NOTICE 'inner val != outer val % %', val, outer.val;

    END;RAISE NOTICE 'outer val is 5 %', val;

    END;

    In this example, note that the block labels inner and outer can be used to identify a spe-cific val variable using its fully-qualified variable name. If you create this as a stored procedure and run it, you would see output similar to the following:

    MYDB(USER)=> call vals(); NOTICE: inner val != outer val 7 5NOTICE: outer val is 5 5VALS------

    (1 row)

    When you declare variables for loop iterators, which are described in Loop Statement on page 2-17, note that the iterator variables have their own unique scope. For example, you could use a variable named val as a loop iterator. Using the same sample procedure, this would give you three unique val variables in your procedure, as follows: 20470-03 Rev.2 2-5

  • IBM Netezza Stored Procedures Developers Guide

    DECLARE

    val int4;BEGIN

    val := 5;

    DECLARE

    val int4;BEGIN

    val := 7;RAISE NOTICE 'inner val != outer val % %', val, outer.val;FOR val IN 1..10 LOOP

    --Note that this is a NEW val variable for the loop. RAISE NOTICE 'The value of val is %', val;

    END LOOP;RAISE NOTICE 'inner val is still 7. Value %', inner.val;

    END;RAISE NOTICE 'outer val is still 5. Value %', val;

    END;

    Sample output for this stored procedure follows:

    MYDB(USER)=> call vals(); NOTICE: inner val != outer val 7 5NOTICE: The value of val is 1NOTICE: The value of val is 2NOTICE: The value of val is 3NOTICE: The value of val is 4NOTICE: The value of val is 5NOTICE: The value of val is 6NOTICE: The value of val is 7NOTICE: The value of val is 8NOTICE: The value of val is 9NOTICE: The value of val is 10NOTICE: inner val is still 7. Value 7NOTICE: inner val is still 5. Value 5VALS------

    (1 row)

    As shown in the output, the val variable of the loop iterator has its own scope. It has its own value and does not affect the other two val definitions. Within the loop, if you need to refer to a specific variable that is defined outside the for loop, you can use the fully qualified form of the variable name (label.variable).

    Data Types and AliasesTable 2-1 lists the supported data types by their preferred name form, and includes sup-ported aliases and some notes about the values. For more information about the data types and values, see the IBM Netezza Database Users Guide.2-6 20470-03 Rev.2

  • Variables and ConstantsTable 2-1: Supported Data Types for Variables

    Data Type Alias Name(s) Notes

    BOOLEAN BOOL A boolean field can store true values, false values, and null. You can use the following words to spec-ify booleans: true or false, on or off, 0 or 1, 'true or false, t or f, on or off, yes or no.

    CHAR CHARACTER, CHAR(n), CHARACTER(n)

    Fixed length character string, blank padded to length n. If you do not specify n, the default is an unsized CHAR value. The maximum character string size is 64,000.

    VARCHAR CHARACTER VARY-ING, VARCHAR(n), CHARACTER VARY-ING(n), CHAR VARYING(n)

    Variable length character string to a maximum length of n. If you do not specify n, the default is an unsized VARCHAR value. There is no blank padding, and the value is stored as entered. The maximum character string size is 64,000.

    NCHAR NATIONAL CHAR-ACTER, NATIONAL CHAR(n), NCHAR(size)

    Fixed length character string, blank padded to length n. If you do not specify n, the default is an unsized NCHAR value. The maximum length is 16,000 characters.

    NVARCHAR NATIONAL CHAR-ACTER VARYING, NATIONAL CHAR VARYING, NATIONAL CHAR VARYING(n), NATIONAL CHAR-ACTER VARYING(n), and NVARCHAR(n)

    Variable length character string to a maximum length of n. If you do not specify n, the default is an unsized NVARCHAR value. The maximum length is 16,000 characters.

    DATE Specifies a day with resolution that spans January 1, 0001 to December 31, 9999 (centered around 2000-01-01).

    TIMESTAMP DATETIME Has a date part and a time part, with seconds stored to 6 decimal positions. The value repre-sents the number of microseconds since midnight 2000-01-01. Min: -63,082,281,600,000,000 (00:00:00, 1/1/0001)Max: 252,455,615,999,999,999 (23:59:59.999999, 12/31/9999)20470-03 Rev.2 2-7

  • IBM Netezza Stored Procedures Developers GuideTIME TIME WITHOUT TIME ZONE

    Hours, minutes, and seconds to 6 decimal posi-tions. Ranging from 00:00:00.000000 to 23:59:59.999999. This is microsecond resolu-tion that represents the time of day only (midnight to one microsecond before midnight).

    INTERVAL TIMESPAN An interval of time. It has microsecond resolution and ranges from +/- 178000000 years. The time part represents everything but months and years (microseconds) and the month part represents months and years. For more information see the section on Netezza interval support in the IBM Netezza Database Users Guide.

    TIME WITH TIME ZONE

    TIMETZ Hours, minutes, seconds to 6 decimal positions, and time zone offset from GMT. Ranging from 00:00:00.000000+13:00 to 23:59:59.999999-12:59.

    NUMERIC(p,s)

    NUMERIC, DEC, DEC(p,s), DECI-MAL(p,s), DECIMAL

    Fixed-point numeric types with precision p and scale s. Precision can range from 1 to 38, scale from 0 to the precision.NUMERIC(p) is equivalent to NUMERIC(p,0).NUMERIC is an unsized numeric value.Although decimal is sometimes a distinct SQL data type, Netezza SQL treats it as an alias for numeric.

    REAL FLOAT(p), FLOAT4 Floating point number with precision p. Precision values of 1 to 6 are equivalent to FLOAT(6), and are stored as a 4-byte value. Netezza SQL prefers the type name real, as float(p) is considered more of an alias for the pre-ferred form.

    DOUBLE PRECISION

    DOUBLE, FLOAT, FLOAT(p), FLOAT8

    Floating point number with precision p, from 7 to 15. Precision values between 7 and 15 are equiv-alent to 15 and are stored as an 8-byte value.Netezza SQL prefers the type name double preci-sion, as float(p) is considered more of an alias for the preferred form.

    INTEGER INT, INT4 32-bit values in range 2,147,483,648 to2,147,483,647

    BYTEINT INT1 8-bit values in the range 128 to 127

    SMALLINT INT2 16-bit values in range 32,768 to 32,767

    Table 2-1: Supported Data Types for Variables (continued)

    Data Type Alias Name(s) Notes2-8 20470-03 Rev.2

  • Array VariablesArray Variables

    In addition to normal scalar variables, NZPLSQL also supports array variables. To declare an array variable, use the following syntax:

    name VARRAY(size) OF type;

    All of the elements of the array will initially be set to the SQL NULL value for the declared type. To assign a value to an element, do the following:

    name(idx) := value;

    This syntax will raise an exception if the index (idx) is out of bounds. The following meth-ods are supported:

    name.EXTEND(size)name.COUNT

    name.TRIM(size)

    The EXTEND method will extend the array by the specified size. If size is omitted, the default is 1.

    COUNT returns the number of elements in the array.

    TRIM deletes the last size elements in the array (the default is 1). TRIM and EXTEND will raise an exception if size is out of bounds.

    Array references are allowed almost anywhere variable references are allowed, with the fol-lowing exceptions:

    As an argument to RAISE As an INTO variable As the variable in a FOR LOOP As part of a default value

    Expressions

    All expressions used in NZPLSQL statements are processed using the backends executor. Expressions that appear to contain constants could require run-time evaluation (for exam-ple, using 'now()' for the timestamp type) so it is impossible for the NZPLSQL parser to identify real constant values other than the NULL keyword. All expressions are evaluated internally by executing a query such as the following:

    SELECT expression

    In the expression, occurrences of variable identifiers are substituted by parameters and the actual values from the variables are passed to the executor in the parameter array. All

    BIGINT INT8 64-bit values in range -9,223,372,036,854,775,808 to9,223,372,036,854,775,807

    Table 2-1: Supported Data Types for Variables (continued)

    Data Type Alias Name(s) Notes20470-03 Rev.2 2-9

    expressions used in a NZPLSQL procedure are compiled and cached the first time they are

  • IBM Netezza Stored Procedures Developers Guideencountered. (Everything in NZPLSQL is cached, with the exception of variable values and SQL plans.) If there is a compile error (syntax error), the expression will not be cached. The cached copy is preserved until one of the following happens:

    The procedure body is modified. The procedure is dropped. The database session ends. The type checking done by the Netezza SQL main parser has some side effects to the inter-pretation of constant values. For example, the following two examples are different in how constant values are interpreted. The first example follows:

    DECLARElogtxt ALIAS FOR $1;

    BEGININSERT INTO logtable VALUES (logtxt, 'now()');RETURN 'now()';

    END;

    The second example follows:

    DECLARElogtxt ALIAS FOR $1;curtime timestamp;

    BEGINcurtime := 'now()';INSERT INTO logtable VALUES (logtxt, curtime);RETURN curtime;

    END

    In the first example, when the Netezza SQL main parser prepares the plan for the INSERT, it interprets now() as a timestamp because the target field of logtable is of that type. It will interpret both instances of now() each time it runs.

    In the second example, the Netezza SQL main parser does not know what type now() should become and therefore it returns a data type of text containing the string now(). Dur-ing the assignment to the local variable curtime, the NZPLSQL interpreter casts this string to the timestamp type by calling the text_out() and timestamp_in() functions for the conversion.

    If record fields are used in expressions or statements, the data types of fields should not change between calls to the same expression or statement.

    Literals and Math Operations in ExpressionsIf your stored procedures perform math operations in expressions, carefully consider the supported ranges for literals and the possible implicit typecasts that the Netezza system may perform. These ranges and behaviors could cause unexpected results in complex math expressions.

    For example, all integer literals are 32-bit (signed) numbers by default, which supports a range of values from -2147483648 to 2147483647. If you perform math operations on a literal, use caution to check for overflows. For example, the following stored procedure defines a numeric value n, assigns it the largest supported value (2147483647) and then adds 1 to the value:

    CREATE OR REPLACE PROCEDURE num() RETURNS BOOL LANGUAGE NZPLSQL ASBEGIN_PROC2-10 20470-03 Rev.2

    DECLARE

  • Expressionsn NUMERIC;BEGIN

    n := 2147483647;RAISE NOTICE 'n is %', n;n := 2147483647 + 1;RAISE NOTICE 'n is %', n;

    END;END_PROC;

    If you create and run this stored procedure, the output is as follows:

    NOTICE: n is 2147483647NOTICE: n is -2147483648

    The output demonstrates that when a value overflows its maximum range value, the value wraps to its minimum value and begins again. To avoid this counter-wrap behavior, you must either use a cast operation to cast n to a higher precision type, or assign values to intermediate values. For example, the following stored procedure creates the counter-wrap issue for the numeric value n, but then it uses casts to numerics or bigints to increase the range of valid values, as follows:

    CREATE OR REPLACE PROCEDURE num() RETURNS BOOL LANGUAGE NZPLSQL ASBEGIN_PROCDECLAREn NUMERIC;BEGIN

    n := 2147483647;RAISE NOTICE 'n is %', n;n := 2147483647 + 1;RAISE NOTICE 'n is %', n;n := 2147483647::numeric + 1;RAISE NOTICE 'n is %', n;n := 2147483647::bigint + 1;RAISE NOTICE 'n is %', n;n := 2147483647;n := n + 1;RAISE NOTICE 'n is %', n;

    END;END_PROC;

    If you create and run this stored procedure, the output would be similar to the following:

    NOTICE: n is 2147483647NOTICE: n is -2147483648NOTICE: n is 2147483648NOTICE: n is 2147483648NOTICE: n is 2147483648

    If you use floating point numbers in expressions, Netezza attempts to cast it into a numeric if possible, with a specific precision and scale that it calculates using internally defined casting rules.

    Because arithmetic operations in a stored procedure are evaluated by invoking the backend executor, they will be processed as SELECT statements. To more clearly see the calculated shape of the expression result, it can be helpful to use it to create a table, which can then be described using the \d command. Printing the results may not provide enough insight to the resulting datatypes.

    In the arithmetic expression that follows, Netezza casts the precision and scale based on 20470-03 Rev.2 2-11

    internal Netezza SQL behavior rules:

  • IBM Netezza Stored Procedures Developers GuideDEV(ADMIN)=> create table test as select (1 + 0.08/365) interest;INSERT 0 1

    DEV(ADMIN)=> \d testTable "TEST"

    Attribute | Type | Modifier | Default Value ----------+--------------+----------+---------------

    INTEREST | NUMERIC(8,6) | | Distributed on hash: "INTEREST"

    In the sample table, the Netezza internal casting rules evaluated the expression 1+0.08/365 and determined that the field would be a numeric value with 8 digits of precision and 6 of scale. The following command shows the actual value saved in the row:

    DEV(ADMIN)=> select * from TEST;INTEREST ----------

    1.000219(1 row)

    Another example follows:

    DEV(ADMIN)=> create table test2 as select (4 + 1/5) loanrt;INSERT 0 1

    DEV(ADMIN)=> \d test2Table "TEST2"

    Attribute | Type | Modifier | Default Value ----------+----------+----------+---------------

    LOANRT | INTEGER | | Distributed on hash: "LOANRT"

    In the previous example, Netezza is evaluating three integer values (4, 1, and 5). The Netezza system uses integer as the type for the new column. If you display the column value, as follows, you can see that the decimal portion of the value was truncated:

    DEV(ADMIN)=> select * from TEST2;LOANRT --------

    4(1 row)

    A similar example follows, but instead of the expression 1/2, this expression uses the numeric value .5 instead, as follows:

    DEV(ADMIN)=> create table test3 as select (4 + .5) loanrt; INSERT 0 1

    DEV(ADMIN)=> \d test3Table "TEST3"

    Attribute | Type | Modifier | Default Value ----------+---------------+----------+---------------

    LOANRT | NUMERIC(3,1) | | Distributed on hash: "LOANRT"

    DEV(ADMIN)=> select * from TEST3;LOANRT --------

    4.5(1 row)2-12 20470-03 Rev.2

  • ExpressionsIn this example, the .5 value is interpreted as 0.5, and thus cast to numeric(3,1).

    In addition to the casts that can occur when math expressions are parsed, Netezza func-tions can also cause an implicit typecast. For example, the function sqrt() takes and returns a double precision value. The following example uses the function to define a table column:

    DEV(ADMIN)=> create table test4 as select (sqrt(42));INSERT 0 1

    DEV(ADMIN)=> \d test4Table "TEST4"

    Attribute | Type | Modifier | Default Value ----------+------------------+----------+---------------

    SQRT | DOUBLE PRECISION | | Distributed on hash: "SQRT"

    DEV(ADMIN)=> select * from TEST4;SQRT

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

    6.4807406984079(1 row)

    In the test4 example, the sqrt() function causes Netezza to cast the input integer value to a double and to return a double.

    Keep these behaviors in mind when you work with stored procedures that use arithmetic expressions to evaluate data. The implicit casts may not provide the value that you would expect if you evaluated the same arithmetic expression with a calculator. An example follows:

    CREATE OR REPLACE PROCEDURE sp_expressions_numeric02() RETURNS NUMERIC LANGUAGE NZPLSQL ASBEGIN_PROC

    DECLAREthisnum9_2 NUMERIC(9,2);million NUMERIC(9,2) := 1000000.00;thisnum18 NUMERIC(18);litespeed NUMERIC := 186282;thisnum38 NUMERIC(38);

    BEGIN/* The following expression causes implicit casts in the math

    evaluation, reducing the precision and scale of the result. */thisnum9_2 := million * (1 + 0.08/365)^(365 * 20);RAISE NOTICE 'thisnum9_2 == %', thisnum9_2;

    /* The following expression uses an explicit cast to increase the precision and scale of the intermediate evaluation. */

    thisnum9_2 := million * (1 + 0.08::numeric(20,15)/365)^(365 * 20);RAISE NOTICE 'thisnum9_2 == %', thisnum9_2;

    /* The following expression uses the numeric literal litespeed to convert the speed of light from miles per sec to miles per year. */

    thisnum18 := litespeed * 60 * 60 * 24 * 365.25;RAISE NOTICE 'thisnum18 == %', thisnum18;/* The following expression uses the integer 186282 to convert

    lightspeed from miles per sec to miles per year. In the right-side evaluation, however, the values overflowed the 20470-03 Rev.2 2-13

  • IBM Netezza Stored Procedures Developers Guideupper limit of an int several times during evaluation, yielding incorrect results. */

    thisnum38 := 186282 * 60 * 60 * 24 * 365.25;RAISE NOTICE 'thisnum38 == %', thisnum38;

    END;END_PROC;

    Sample output follows:

    NOTICE: thisnum9_2 == 4945731.93NOTICE: thisnum9_2 == 4952164.15NOTICE: thisnum18 == 5878612843200NOTICE: thisnum38 == -396334376256

    As this example shows, explicit casts during arithmetic evaluations and careful use of liter-als, constants, and types can help to increase the accuracy of the expressions used in your stored procedures.

    Statements

    The following sections describe the types of statements which are explicitly understood by the NZPLSQL parser. Any statements which are not specified using these conventions (and thus are not understood by the NZPLSQL parser) are assumed to be SQL commands and sent to the database engine to execute. The resulting query should not return any data.

    AssignmentTo assign a value to a variable or row/record field, use the assignment statement as follows:

    identifier := expression;

    If the expressions result data type does not match the variables data type but the types are compatible, or the variable has a size/precision that is known (as for char(20)), the result value will be implicitly cast by the NZPLSQL bytecode interpreter using the result types output-function and the variables type input-function. Note that this could potentially result in runtime errors generated by the types input functions.

    Several examples follow:

    user_id := 20;tax := subtotal * 0.06;

    For more information about Netezza casting rules and behaviors, see the IBM Netezza Database Users Guide.

    Calling Another ProcedureAll procedures defined in a Netezza database return a value; the default value is NULL. Thus, the normal way to call a procedure is to execute a SELECT query or to do an assign-ment (resulting in an NZPLSQL internal SELECT).

    However, there are cases where you might not be concerned with the procedure's result. In these cases, use the CALL statement to call the procedure, as follows:

    CALL query

    The CALL statement executes a SELECT query and discards the result. Identifiers such as local variables are still substituted into input parameters. 2-14 20470-03 Rev.2

  • StatementsThere is a maximum stored procedure call recursion limit of 1024. If the call recursion exceeds this value, the following error message is returned:

    ERROR: stored procedure recursion limit exceeded

    Executing Dynamic QueriesThere may be times when you want to generate dynamic queries inside your NZPLSQL pro-cedures. Or, you may have procedures that are designed to generate other procedures. For these situations, NZPLSQL provides the EXECUTE IMMEDIATE statement:

    EXECUTE IMMEDIATE query-string

    The query-string value is a string of type text which contains the query to be executed.

    When working with dynamic queries, make sure that you escape any single quotes in NZPLSQL.

    A query run by an EXECUTE IMMEDIATE statement is prepared each time the statement is run. The query string can be dynamically created within the procedure to perform actions on different tables and fields.

    The results from SELECT queries are discarded by EXECUTE IMMEDIATE, and SELECT INTO is not currently supported within EXECUTE IMMEDIATE. So, the only way to extract a result from a dynamically-created SELECT is to use the FOR ... EXECUTE form, described in Iterating Through Records on page 2-20.

    An example statement follows:

    EXECUTE IMMEDIATE 'UPDATE tbl SET' || quote_ident('fieldname')|| ' = '|| quote_literal('newvalue')|| ' WHERE ...';

    This example demonstrates the use of the quote_ident and quote_literal functions. To ensure that strings are correctly processed for quotes or special characters, expressions containing column and table identifiers should be passed to quote_ident. Expressions con-taining values that should be literal strings in the constructed command should be passed to quote_literal. Both take the appropriate steps to return the input text enclosed in double or single quotes, respectively, with any embedded special characters properly escaped.

    Obtaining Other Results StatusThere are two variables that provide system status indicators: ROW_COUNT and LAST_OID.

    ROW_COUNT is the number of rows processed by the last SQL query sent down to the SQL engine.

    LAST_OID is the object ID (oid) of the last row inserted by the most recent SQL query.LAST_OID is useful only after an INSERT query, and then only when the insert happens on a catalog table. In practice, LAST_OID is not likely to be very useful.

    In addition to these variables, you can also use the FOUND and IS NULL variables to per-form special conditional processing based on record results. For more information, see Assignments on page 2-19. 20470-03 Rev.2 2-15

  • IBM Netezza Stored Procedures Developers GuideReturning From a ProcedureThe RETURN command allows you to return data from a procedure:

    RETURN [expression]

    The procedure terminates and the value of expression is returned to the upper executor. If expression is not provided, NULL is assumed.

    The return value of a procedure can be undefined. If control reaches the end of the top-level block of the procedure without encountering a RETURN statement, NULL is assumed. The expressions result is automatically cast into the procedure's return type as described for assignments.

    Control Structures

    Control structures may be the most useful and important part of the NZPLSQL language. With NZPLSQL's control structures, you can manipulate SQL data in a very flexible and powerful way.

    Conditional ControlYou use IF statements to take action according to certain conditions. NZPLSQL has three forms of IF statements:

    IF-THEN IF-THEN-ELSE IF-THEN-ELSE IF Note: All NZPLSQL IF statements require a corresponding END IF statement. In ELSE-IF statements, you need two END IF statements: one for the first IF and one for the second (ELSE IF).

    IF-THEN StatementsIF-THEN statements are the simplest form of an IF. The statements between THEN and END IF will be executed if the condition is true. Otherwise, the statements following END IF will be executed. An example follows:

    IF v_user_id 0 THENUPDATE users SET email = v_email WHERE user_id = v_user_id;

    END IF;

    IF-THEN-ELSE Statements IF-THEN-ELSE statements add to IF-THEN by letting you specify the statements that should be executed if the condition evaluates to FALSE. For example:

    IF parentid IS NULL or parentid = ''THEN

    return fullname;ELSE

    return hp_true_filename(parentid) || '/' || fullname;END IF;

    IF v_count > 0 THEN2-16 20470-03 Rev.2

    INSERT INTO users_count(count) VALUES(v_count);

  • Control Structuresreturn 't';ELSE

    return 'f';END IF;

    You can nest IF statements as in the following example:

    IF movies.genre = 'd' THENfilm_genre := 'drama';

    ELSE IF movies.genre = 'c' THEN

    film_genre := 'comedy';END IF;

    END IF;

    IF-THEN-ELSE IF StatementWhen you use the "ELSE IF" statement, you are actually nesting an IF statement inside the ELSE statement. Thus you need one END IF statement for each nested IF and one for the parent IF-ELSE. For example:

    IF movies.genre = 'd' THENfilm_genre := 'drama';

    ELSE IF movies.genre = 'c' THENfilm_genre := 'comedy';

    END IF;END IF;

    While this form works, it can become a little tedious and error-prone if there are many alter-natives to check. Thus, the language offers the alternative syntax using ELSIF or ELSEIF, as follows:

    IF movies.genre = 'd' THENfilm_genre := 'drama';

    ELSIF movies.genre = 'c' THENfilm_genre := 'comedy';

    ELSIF movies.genre = 'a' THENfilm_genre := 'action';

    ELSIF movies.genre = 'n' THENfilm_genre := 'narrative';

    ELSE -- An uncategorized genre form has been requested.

    film_genre := 'Uncategorized';END IF;

    The IF-THEN-ELSIF-ELSE form offers some flexibility and eases the coding process when you need to check many alternatives in one statement. While it is equivalent to nested IF-THEN-ELSE-IF-THEN commands, it needs only one END IF statement.

    Iterative ControlWith the LOOP, WHILE, FOR, and EXIT statements, you can control the flow of execution of your NZPLSQL program iteratively.

    Loop Statement The LOOP statement defines an unconditional loop that repeats until terminated by an EXIT statement or a RETURN statement (which terminates the procedure and the loop). It has the following syntax:20470-03 Rev.2 2-17

  • IBM Netezza Stored Procedures Developers Guide[]LOOP

    statementsEND LOOP;

    The optional label can be used by EXIT statements of nested loops to specify which level of nesting should be terminated.

    EXIT Statement The EXIT statement terminates a loop. It has the following syntax:

    EXIT [ label ] [ WHEN expression ];

    If you do not specify a label, the innermost loop is terminated and the statement following END LOOP is executed next. If you specify a label, it must be the label of the current or an upper level of nested loop or blocks. Then the named loop or block is terminated and con-trol continues with the statement after the loops/blocks corresponding END.

    Examples:

    LOOP-- some computationsIF count > 0 THENEXIT; -- exit loopEND IF;END LOOP;

    LOOP-- some computationsEXIT WHEN count > 0;END LOOP;

    BEGIN-- some computationsIF stocks > 100000 THENEXIT; END IF;END;

    WHILE StatementWith the WHILE statement, you can loop through a sequence of statements as long as the evaluation of the condition expression is true.

    []WHILE expression LOOPstatementsEND LOOP;

    For example:

    WHILE amount_owed > 0 AND gift_certificate_balance > 0 LOOP-- some computations hereEND LOOP;

    WHILE NOT boolean_expression LOOP-- some computations hereEND LOOP;2-18 20470-03 Rev.2

  • Working with RecordsFOR Statement Using the FOR statement, you can create a loop that iterates over a range of integer values.

    []FOR name IN [ REVERSE ] expression .. expression LOOPstatementsEND LOOP;

    The variable name is automatically created as type integer and exists only inside the loop. The two expressions for the lower and upper bound of the range are evaluated only when entering the loop. The iteration step is always 1.

    Some examples of FOR loops:

    FOR i IN 10..1 LOOP-- some expressions hereRAISE NOTICE 'i is %',i;END LOOP;

    FOR i IN REVERSE 10..1 LOOP-- some expressions hereEND LOOP;

    Working with Records

    Records are similar to rowtypes, but they have no predefined structure. They are used in selections and FOR loops to hold one database row from a SELECT operation.

    DeclarationVariables of type RECORD can be used for different selections. Accessing a record or an attempt to assign a value to a record field when there is no row in it results in a run-time error. To declare a RECORD variable:

    name RECORD;

    Assignments You can use the following query to assign a complete selection into a record or row:

    SELECT expressions INTO target FROM ...;

    target can be a record, a row variable, or a comma-separated list of variables and record-fields or row-fields. Note that this is different from the SQL interpretation of SELECT INTO, which is that the INTO target is a newly created table. (If you want to create a table from a SELECT result inside a NZPLSQL procedure, use the equivalent syntax CREATE TABLE AS SELECT.)

    If a row or a variable list is used as the target, the selected values must exactly match the structure of the target(s) or a runtime error occurs. The FROM keyword can be followed by any valid qualification, grouping, or sorting that can be given for a SELECT statement.

    After a record or row has been assigned to a RECORD variable, you can use the "." (dot) notation to access fields in that record as follows:

    DECLAREusers_rec RECORD;full_name varchar;20470-03 Rev.2 2-19

  • IBM Netezza Stored Procedures Developers GuideBEGINSELECT * INTO users_rec FROM users WHERE user_id=3;

    full_name := users_rec.first_name || ' ' || users_rec.last_name;There is a special variable named FOUND of type boolean that can be used immediately after a SELECT INTO to check whether an assignment was successful. The following exam-ple uses the NOT FOUND form to raise an exception if a SELECT INTO statement does not match on the requested input name:

    SELECT * INTO myrec FROM EMP WHERE empname = myname;IF NOT FOUND THEN

    RAISE EXCEPTION 'employee % not found', myname;END IF;

    FOUND is very similar to ROW_COUNT (described in Obtaining Other Results Status on page 2-15). For example, the following statement:

    IF FOUND

    is equivalent to this statement:

    IF ROW_COUNT >= 1

    You can also use the IS NULL (or ISNULL) conditionals to test whether a RECORD or ROW is NULL. If the selection returns multiple rows, only the first is moved into the target fields. All others are silently discarded. For example:

    DECLAREusers_rec RECORD;full_name varchar;

    BEGINSELECT * INTO users_rec FROM users WHERE user_id=3;IF users_rec.homepage IS NULL THEN

    -- user entered no homepage, return "http://"return 'http://';

    END IF;END;

    Iterating Through RecordsUsing a special type of FOR loop, you can iterate through the results of a query and manip-ulate that data accordingly. The FOR IN loop syntax is as follows:

    []FOR record | row IN select_clause LOOP

    statementsEND LOOP;

    The record or row is assigned all the rows resulting from the select clause and the loop body is executed for each. An example follows:

    DECLAREmviews RECORD;-- Instead, if you did:-- mviews cs_materialized_views%ROWTYPE;-- this record is ONLY usable for the cs_materialized_views table

    BEGINCALL cs_log('Refreshing materialized views...');FOR mviews IN SELECT * FROM cs_materialized_views ORDER BY sort_key LOOP-- Now "mviews" has one record from cs_materialized_views

    RAISE EXCEPTION, 'Can't execute SQL while processing SQL for %',mview.my_name;2-20 20470-03 Rev.2

  • Aborting and MessagesEND LOOP;CALL cs_log('Done refreshing materialized views.');return 1;

    end;

    If the loop is terminated with an EXIT statement, the last assigned row is still accessible after the loop.

    The FOR-IN EXECUTE statement is another way to iterate over records:

    []FOR record | row IN EXECUTE text_expression LOOP

    statementsEND LOOP;

    This is similar to the previous form, except that the source SELECT statement is specified as a string expression. The main difference between the two is the syntax and use of vari-ables to build the SQL to execute. Note that the first form is faster to evaluate.

    Aborting and Messages

    Use the RAISE statement to report messages and raise errors. The statement syntax follows:

    RAISE level 'format' [, identifier [...]];

    Inside format, the percent character (%) is used as a placeholder for a subsequent, comma-separated identifier. You can specify more than one % and identifier pair, as follows:

    RAISE NOTICE 'Welcome % %', firstname, lastname;

    In this example, the notice message substitutes the value of firstname for the first % char-acter, and substitutes the value of lastname for the second % character.

    The message levels are as follows:

    DEBUG messages only appear in pg.log. NOTICE messages are written to the database log and forwarded to the client

    application.

    EXCEPTION messages are written to the database log, forwarded to the client applica-tion as non-fatal messages, and usually abort the transaction if they are not caught.

    An example of a RAISE statement follows:

    RAISE NOTICE 'Calling cs_create_job(%)', job_id;In the example, job_id will replace the % in the string and display the message to the client and in pg.log.

    RAISE EXCEPTION 'Inexistent ID --> %', user_id;

    This EXCEPTION statement will abort the transaction (if the exception is not caught) and write the message to the database log.20470-03 Rev.2 2-21

  • IBM Netezza Stored Procedures Developers GuideExceptions and Error Messages Support

    By default, any error occurring in a NZPLSQL procedure aborts the execution of the proce-dure, and aborts the surrounding transaction as well. The system returns to the main loop to obtain the next query from the client application. Note that it is not possible to catch all exceptions, especially if that action should leave the database in a bad state.

    The NZPLSQL language uses the EXCEPTION statement to process exceptions:

    EXCEPTION WHEN OTHERS THENHandler_statements

    You place the statement at the end of a block. If no error occurs, the EXCEPTION handler statements are not executed.

    The variable SQLERRM contains the text of an error message that has been caught. In the absence of an exception block, the exception propagates up to the next stored procedure in the call stack. So, for example, if sproc1 calls sproc2 which generates an exception, but sproc2 does not have an exception handler, then the system looks for a handler in sproc1. The system also looks at the enclosing block declarations.

    For example:

    create or replace procedure sp_except01() returns BOOL LANGUAGE NZPLSQL AS BEGIN_PROCDECLARE

    r record;BEGIN

    BEGIN

    SELECT * INTO r FROM NONEXISTENT;END;

    END;END_PROC;

    create or replace procedure sp_except02() returns BOOL LANGUAGE NZPLSQL AS BEGIN_PROCBEGIN

    CALL sp_except01();END;END_PROC;

    create or replace procedure sp_except03() returns BOOL LANGUAGE NZPLSQL AS BEGIN_PROCBEGIN

    CALL sp_except02();EXCEPTION WHEN OTHERS THEN

    RAISE NOTICE 'Caught exception';END;END_PROC;

    In these examples, the exception is generated in sp_except01, in the block inner. The sys-tem first checks for an exception handler for block inner, which is not found. Control passes to the parent context, which is the procedure sp_except01, and an exception handler is also not found there. Control then passes to sp_except02, and finally sp_except03, where 2-22 20470-03 Rev.2

    an exception handler is found and used.

  • Returning a Result SetIf an exception is not caught at any level, additional NOTICE-level log messages are sent to provide context about the error and where it occurred (line number and type of statement, unless the error is from a RAISE EXCEPTION statement).

    If you include exception handlers in stored procedures, the handlers will catch any errors and the errors are not displayed. For example:

    CREATE PROCEDURE sp() RETURNS INTEGER LANGUAGE NZPLSQL ASBEGIN_PROCBEGIN

    EXECUTE IMMEDIATE 'insert into NOTEXIST' || 'values(1,1)';EXCEPTION WHEN OTHERS THENEND;

    END_PROC;

    Assuming that NOTEXIST does not exist in the database, the query does not display any error output because the error was handled by the exception handler.

    To display the error, write the procedure as follows:

    CREATE PROCEDURE sp() RETURNS INTEGER LANGUAGE NZPLSQL ASBEGIN_PROCBEGIN

    EXECUTE IMMEDIATE 'insert into NOTEXIST' || ' values(1,1)';EXCEPTION WHEN OTHERS THENRAISE NOTICE 'Got exception: %', SQLERRM;

    END;END_PROC;

    When you run this query, it displays the following output:

    NOTICE: Got exception: ERROR: Relation 'NOTEXIST' does not exist

    Returning a Result Set

    Typically, an NZPLSQL procedure returns a unique return value, but it can also return a result set in the form of a specified table.

    To create a stored procedure that returns a result set, do the following:

    Define the stored procedure with a return value of RETURNS REFTABLE () to indicate that it returns a result set that looks like the specified table.

    Inside the body of the procedure, use the variable REFTABLENAME to refer to the results table.

    The table specified in the RETURNS value must exist at the time that the stored procedure is created, although the table could be empty. The table will continue to exist after the stored procedure completes. You will not be permitted to drop the reference table while the stored procedure is defined. (That is, you must drop the stored procedure or modify it to return a different reference table before you can drop the table.)

    For example, the following stored procedure returntwo returns a result set using the refer-ence table feature. The reference table that it uses, tbl, was previously defined using the following command:

    CREATE TABLE tbl (i INT4, i2 INT4);20470-03 Rev.2 2-23

  • IBM Netezza Stored Procedures Developers GuideA description of tbl follows:

    DEV(ADMIN)=> \d tbl Table "TBL"Attribute | Type | Modifier | Default Value -----------+---------+----------+---------------

    I | INTEGER | | I2 | BIGINT | | Distributed on hash: "I"

    After you confirm that the reference table exists, you can use the following command to define the stored procedure returntwo:

    DEV(ADMIN)=> CREATE OR REPLACE PROCEDURE returntwo(timestamp) RETURNS REFTABLE(tbl) LANGUAGE NZPLSQL AS BEGIN_PROC

    BEGINEXECUTE IMMEDIATE 'INSERT INTO ' || REFTABLENAME ||' values (1,1)';EXECUTE IMMEDIATE 'INSERT INTO ' || REFTABLENAME ||' values (2,2)';RETURN REFTABLE;

    END;END_PROC;

    A sample call to the returntwo stored procedure follows:

    DEV(ADMIN)=> EXECUTE PROCEDURE returntwo(now());I | I2 ---+----

    1 | 12 | 2(2 rows)

    Note: You cannot specify a WHERE clause in a query which calls a stored procedure that returns a result set.

    When you call or invoke the stored procedure using a SQL command such as SELECT pro-cedure(), CALL procedure(), EXECUTE procedure(), and so forth, the database does the following:

    Generates a tablename TEMPFUNC where oid is the object ID of the procedure that was invoked

    Checks if the tablename exists; if it does, it issues a DROP TABLE command

    Issues a CREATE TEMPORARY TABLE as select * from LIMIT 0 to create the table for the results set with no initial contents

    Returns the results of SELECT * from where proc(args) is NULL (Note that this is the only situation in which a stored procedure is allowed to be exe-cuted with a FROM clause and where the return value is used as part of a query.)

    To use this in a procedure, you must insert your results in using the REFTABLENAME variable to obtain the name. This SQL command must be invoked dynam-ically in order to use the variable.

    Additionally, you must return NULL in your procedure by one of the following means:

    RETURN REFTABLE; RETURN NULL;2-24 20470-03 Rev.2

  • Advanced Development Topics RETURN; Not specifying a RETURN clause.If you do not return NULL, the procedure returns an error. The recommended method to return NULL is RETURN REFTABLE.

    One REFTABLE procedure can call another, but you will encounter unusual results if a REFTABLE procedure calls itself (either directly or recursively) because of the temporary table logic; therefore, avoid designing a REFTABLE procedure which calls itself.

    Cross-database access for a REFTABLE procedure should work without problem as the tem-porary table will be created in the local database; it will retrieve the shape of the REFTABLE definition in the other database.

    The SQL that is executed (for example, CREATE TEMPORARY TABLE, DROP TABLE, and so forth) uses the owner ID of the procedure as the effective user ID if EXECUTE AS OWNER is set; otherwise, if EXECUTE AS CALLER is set, the SQL uses the user ID of the account which calls or invokes the procedure.

    Managing Large Datasets If users run stored procedures on large datasets, there may be situations where there is not enough memory to hold the results of a select on that table. For example, some stored pro-cedures could read each record from a table and take action on each record, as follows:

    FOR rec in SELECT * from tablenm LOOP

    --perform processing steps

    END LOOP:

    The SELECT operation runs first and caches its results in memory or as a temporary file on disk, depending upon the size of the result set. The procedure then applies the steps in the inner processing loop.

    If the table (tablenm) is very large, such as a table with millions of rows or one with many thousands of large rows, the temporary file could be a huge file which consumes the free disk space on the Netezza host. Use caution when your stored procedures process very large tables.

    Note: In the Netezza environment, these types of select loops that operate on single rows are not optimized for performance in the Netezza environment. Where possible, recast the loop to operate on record sets. For more information, see Query Processing in Loops on page 2-26.

    Advanced Development Topics

    The following sections describe some topics which leverage user-defined functions and stored procedures to perform advanced programming and scripting on the Netezza system.

    Extending the Language with UDFs If you or other users at your site create user-defined functions (UDFs) for your Netezza sys-tems, you can use UDFs to extend the NZPLSQL language. These UDFs must be invoked using SQL that is designed to run only on the Netezza host inside Postgres. For details 20470-03 Rev.2 2-25

  • IBM Netezza Stored Procedures Developers Guideabout the use of UDFs to extend NZPLSQL, refer to the IBM Netezza User-Defined Func-tions Developers Guide. Note that the guide is available only to members of the Netezza Developer Network (NDN); contact [email protected] for more information.

    Tips and Developer Best PracticesThe following sections describe some common tips and best practices for stored procedures.

    Control-C Interrupt Processing in LoopsIf the procedure encounters an infinite loop, you can press Control-C to interrupt the loop. This key sequence should cause an exception (which is not catchable) and thus cause the loop and the procedure call to be interrupted and return.

    Query Processing in Loops Within stored procedures, there may be loop designs which appear to use concurrent que-ries to process the results. For example, the following procedure uses a SELECT to gather information, which is then processed for a possible DELETE action:

    FOR rec in SELECT * from mytable LOOPIF rec.type = d THEN

    EXECUTE IMMEDIATE DELETE FROM mytable2 WHERE recid = || rec.id;END IF;

    END LOOP;

    While it appears that the outer FOR loop SELECT and the inner EXECUTE IMMEDIATE queries are running at the same time, the SELECT query finishes and caches its results before the inner query begins. Thus, deleting records from the table in the inner loop will not impact the SELECT query in the outer loop or change its results.

    Note: Although it may be very common to perform row-at-a-time operations, as used in the preceding example, you can significantly improve the performace of these procedures by designing them to operate on sets of records rather than single row operations. For exam-ple, if you recast the example above to the following:DELETE from mytable2 where recid in (select recid from my tablewhere type = 'd') ;This procedure design can take advantage of Netezzas massively parallel processing (MPP) environment to run much more quic