Saturday, 17 August 2013

Db2 User-Defined Functions: SQL and External UDF Guide


Db2 user-defined function flow showing SQL UDFs, external functions, table functions, SELECT calls, and guardrails
Db2 UDFs keep reusable logic close to SQL.

A payroll query that repeats the same allowance calculation in ten COBOL programs is hard to test and easy to change in one place only. A Db2 user-defined function can move that calculation behind one SQL routine, so the application calls PAYROLL.NET_PAY(...) instead of carrying copy-pasted expression logic through every cursor.

This refresh keeps the original topic, but narrows it to what a Db2 for z/OS developer needs: when a UDF belongs in SQL, how scalar and table functions differ, when an external COBOL or C routine is justified, and which options can affect performance or security.

What Is a Db2 User-Defined Function?

A user-defined function, or UDF, is a Db2 routine that you create with CREATE FUNCTION and then call from SQL. IBM's Db2 for z/OS documentation describes CREATE FUNCTION as the statement that registers a user-defined function with the database server. The function can return a single scalar value or a table, depending on how it is defined.

From an application point of view, the most common use is a scalar call in a SELECT, WHERE, or VALUES statement.

SELECT EMPNO,
       PAYROLL.NET_PAY(SALARY, BONUS, TAX_CODE) AS NET_AMOUNT
  FROM PAYROLL.EMP_PAY
 WHERE PAYROLL.ACTIVE_EMP(STATUS, TERM_DATE) = 'Y';

That example hides the rule behind a named function. It also creates a contract. If the rule changes, the DBA and development team can review the function definition instead of searching every batch program for a similar expression.

Use a UDF for Reusable SQL Logic

A UDF is a good fit when the result belongs inside a SQL expression. Date normalization, account-number formatting, small code translations, financial rounding rules, and common eligibility checks are typical examples.

Use case Good UDF fit? Reason
Return a normalized branch code for each account row. Yes The result is a scalar value used directly in SQL.
Calculate net pay from salary, allowance, and tax code. Usually The same expression is reused by reports and batch programs.
Post an accounting transaction across several tables. No That is transaction logic. Use a stored procedure or application service.
Return a filtered set of rows from a table-like routine. Maybe An SQL table function can work, but compare it with a view or direct query.

Scalar, Table, SQL, External, and Sourced Functions

The old post listed UDF categories but did not explain when each matters. Db2 supports several function forms, and the choice affects how the function is written, invoked, secured, and tuned.

Function type What it returns Typical use
SQL scalar function One value Reusable expression written in SQL PL or a single return expression.
SQL table function A row set Table-like result that can be referenced in a query.
External scalar function One value Logic implemented in COBOL, C, Java, PL/I, or Assembler.
External table function A row set External routine returns rows to the invoking SQL statement.
Sourced function Depends on source function Reuse an existing built-in or user-defined function with a distinct type or different signature.

For a COBOL application team, start with a SQL scalar function when the rule can be stated in SQL. Move to an external function only when the logic already exists in a tested language routine or needs facilities that SQL cannot express cleanly.

Create a Simple SQL Scalar UDF

The simplest UDF is a scalar SQL function. The function below standardizes a status value before the calling program compares it. A rule like this is small enough to keep in SQL and easy to test with VALUES.

CREATE FUNCTION APP.CLEAN_STATUS
       (P_STATUS CHAR(1))
  RETURNS CHAR(1)
  LANGUAGE SQL
  DETERMINISTIC
  NO EXTERNAL ACTION
  RETURN
    CASE
      WHEN P_STATUS IN ('A', 'I', 'S') THEN P_STATUS
      WHEN P_STATUS IS NULL            THEN 'U'
      ELSE 'X'
    END;

Test it before wiring it into a batch cursor.

VALUES APP.CLEAN_STATUS('A');
VALUES APP.CLEAN_STATUS(' ');
VALUES APP.CLEAN_STATUS(CAST(NULL AS CHAR(1)));

If the function is deterministic, tell Db2. If it reads tables, calls an external service, or depends on the current time, do not mark it deterministic just because that looks faster. The declaration should match the real behavior.

Call a UDF from COBOL SQL

A COBOL program calls a Db2 UDF inside embedded SQL the same way it calls many built-in functions: qualify the function when needed, pass host variables, and fetch the result into a compatible host variable.

EXEC SQL
    SELECT APP.CLEAN_STATUS(STATUS)
      INTO :WS-CLEAN-STATUS
      FROM CUSTOMER_STATUS
     WHERE CUSTOMER_ID = :WS-CUSTOMER-ID
END-EXEC.

Keep the host variable data type close to the UDF return type. A CHAR(1) result belongs in a one-byte character field, not a loosely sized display field that later gets compared with padded values. The related DB2 Host Variables and Structures guide is the right companion when copybook definitions are the problem.

External UDFs Need More Operational Control

An external UDF registers code that lives outside the SQL function body. IBM's external scalar function reference notes that the statement registers an external scalar function and that a scalar function returns one value each time it is invoked. External definitions can specify options such as language, parameter style, WLM environment, security behavior, null handling, and SQL data access.

CREATE FUNCTION APP.RISK_SCORE
       (P_ACCT_NO CHAR(12), P_BALANCE DECIMAL(13,2))
  RETURNS INTEGER
  EXTERNAL NAME 'RSKSCORE'
  LANGUAGE COBOL
  PARAMETER STYLE SQL
  FENCED
  DETERMINISTIC
  NO SQL
  RETURNS NULL ON NULL INPUT
  NO EXTERNAL ACTION
  WLM ENVIRONMENT RISKUDF;

That definition is not just syntax. It tells the operations team where the routine runs, whether it can read SQL data, whether null input should call the routine, and whether the function has side effects outside Db2.

UDF or Stored Procedure?

Do not use a UDF as a hidden transaction processor. If the logic updates several tables, writes audit rows, sends messages, or owns commit boundaries, a stored procedure is usually the cleaner object. A UDF should behave like a function: input values in, result value or rows out.

Question Choose UDF Choose stored procedure
Can it be used inside a SELECT expression? Yes Usually no
Does it return one calculated value? Yes Not the main reason
Does it perform a business transaction? No Yes
Does COBOL call it with CALL? No, it appears in SQL Yes, SQL CALL is normal

For the next topic in this cleanup list, the DB2 Stored Procedure page should cover transaction-style routines, result sets, parameters, and deployment. This UDF page should stay focused on function behavior inside SQL.

Performance Checks Before You Add a UDF

A UDF can make SQL easier to read, but it can also hide work from the person reading the query. Before using a UDF in a high-volume cursor, check how often it runs and whether it blocks index-friendly predicates.

  • Use EXPLAIN on the SQL that calls the function.
  • Avoid wrapping indexed columns in a function inside a WHERE clause unless you have tested the access path.
  • Mark DETERMINISTIC, NO SQL, and NO EXTERNAL ACTION only when they are true.
  • For external UDFs, confirm WLM environment, RACF permissions, load module availability, and Language Environment setup.
  • Test null handling with RETURNS NULL ON NULL INPUT or CALLED ON NULL INPUT.
  • Do not give a UDF the same name as a built-in function unless the function signature and SQL path behavior are reviewed.

The companion Db2 SQL Optimization Tips for COBOL Programs article covers access-path checks in more detail.

Deployment Checklist

  • Choose a schema that matches site naming rules and does not collide with system schemas.
  • Use a specific name for functions that may be overloaded.
  • Grant EXECUTE only to the packages, roles, or IDs that need the function.
  • For static COBOL SQL, confirm bind or rebind steps after new SQL references are introduced.
  • Keep source, DDL, grants, WLM definition, and load module promotion in the same change record.
  • Prepare rollback DDL before changing a function used by nightly batch jobs.

FAQ

Can a Db2 UDF return more than one row?

Yes. A table function can return a set of rows. A scalar function returns one value each time it is invoked.

Can COBOL code be used in a Db2 UDF?

Yes, an external UDF can reference a routine written in COBOL when the site supports the required Language Environment, WLM, security, and deployment setup.

Should a UDF replace a stored procedure?

No. Use a UDF for reusable logic inside SQL expressions. Use a stored procedure for transaction-style work, multiple statements, result sets, or business operations called with SQL CALL.

A UDF is worth creating when it gives SQL a clear name for a repeated rule and behaves predictably under production volume. If it hides expensive work inside every fetched row, fix the design before it reaches the batch window.

No comments:

Post a Comment

New In-feed ads