MacLochlainns Weblog

Michael McLaughlin's Technical Blog

Site Admin

Pipelined table functions

with 7 comments

Some posts take on a life of their own. This is one of those. When I presented the concept at the Utah Oracle User’s Group (UTOUG) Training Days 3/12-3/13/2009 it became clear the community could benefit from more detail about table and pipelined table functions. Also, since the subject is beyond a straightforward implementation of technique, it now uses folding to separate subtopics (see here for more detail on how to read the blog page).

This approach is useful when you’re trying to implement third party program. Third party programs often overused index-by or Associative Array PL/SQL data types as formal parameters and return type. You can generally wrap these modules in pipelined table functions. Then, you can implement them in any SQL programming context. This appproach lets you access them through Java, PHP, or other OCI8 programming languages.

The primary purpose of a pipelined table function lets you retrieve PL/SQL record collection structures in a SQL context. PL/SQL record structures are (a) any collection that contains a record structure, and (b) system reference cursors. While system reference cursors have a SQL*Plus structure for letting you dump their contents at the command line, there is no convenient single step to convert them to a SQL context. You must first read a system reference cursors in a for loop to convert them to a SQL context. You do that second step with a pipelined table function.

There’s a nightmare of strong opinion about the term PL/SQL Table because their more aptly called index-by or Associative Array collections. Unfortunately, it was Oracle’s documentation that gave the community the term. Its unfortunate that it stuck because it can be misleading. A PL/SQL Table isn’t a table in any sense of the word because it doesn’t have a SQL context. A PL/SQL table, index-by table, or Associative Array is a two-dimensional memory structure in the SGA, and it is accessible in a PL/SQL scope or through external programming languages that use the OCI8 libraries.

Pipelined table functions are slower than other approaches, but they are easy to implement. That’s why a number of folks use them. The alternative to a pipelined function is typically a complex query. Complex queries may include advanced joins, selective aggregation, or DECODE/CASE logic statements. Many programmers choose to perform data conditioning inside PL/SQL blocks because they’re more comfortable with the procedure constructs. The same programmers also plan to return tables to only other PL/SQL programming units. After they’ve written the logic and they discover that the program also needs to run in a SQL context, they write pipelined table function to wrap the table function or return variable logic.

There are two general situations where code reuse requires a pipelined table function. They are a function that returns a PL/SQL only context variable and a procedure that returns a pass-by-reference formal parameter that is a PL/SQL only context variable (more on that in another PL/SQL formal parameter modes blog post). The second and far less frequent scenario is where you require a pipelined table function as part of the process to convert a system reference cursor.

The blog page describes and provides some small examples of these types of problems. It is organized as shown. You can also find examples in Oracle Database 11g PL/SQL Programming or Oracle Database 11g PL/SQL Programming Workbook.

Written by maclochlainn

May 11th, 2008 at 8:21 pm

Posted in Uncategorized

7 Responses to 'Pipelined table functions'

Subscribe to comments with RSS or TrackBack to 'Pipelined table functions'.

  1. Valuable information.
    Thanks

    hunns

    17 Sep 08 at 2:14 pm

  2. Thanks for the extremly useful info. Currently trying to understand PL/SQL tables in order to understand how one get a HTML check box values to be used in PL/SQL.

    usefulinfo

    8 May 09 at 9:10 am

  3. I found your article very informative. However I’m having trouble how to apply the concepts in an already working package.

    The main function on the package outputs a ref cursor so it can be read as a result set in java. Now the problem comes as it depends on a type object defined as an sql type to return such ref cursor. This type object would have to be replaced executing it’s definition (I guess) if some column types of a cursor on the package change on the future.

    What I want to do taking your articles is eliminate the dependency on the sql type object and create a plsql type object from a local record on the package. Now it’s impossible to return a ref cursor unless some concepts on your article are applyied.

    By now, what you mean on the cursor:

    SELECT   common_lookup_id
    ,        common_lookup_type
    ,        common_lookup_meaning
    FROM     common_lookup
    WHERE    common_lookup_table = UPPER(TABLE_NAME)
    AND      common_lookup_column = UPPER(column_name);

    I’m really confused what table would be “commn_lookup” on my application. I’m guessing the columns on this cursor are just columns on a collection which is “common_lookup”. But then I don’t know what would be common_lookup_table and common_lookup_column as there’s nothing like that defined on the structure of the collection. Would it be metadata? And how would I acces it?

    And if I’m lost on what I have just catched yet. What would I solve the problem previusly mentioned? Thanks!

    Gauss

    5 Mar 10 at 5:55 pm

  4. This shows you an alternative approach to work with system reference cursors.

  5. If I understood your question correctly, I’ve added a post that should help you here.

    maclochlainn

    7 Mar 10 at 9:20 pm

  6. […] wrap it in a Pipelined Table function […]

  7. I apologize but sometimes comments get approved on my iPhone and replying gets lost in the shuffle. The problem here is that Oracle doesn’t really support an Adapter pattern (example in PL/SQL). Unfortunately, these solutions are structurally coupled.

    maclochlainn

    16 Dec 10 at 1:58 am

Leave a Reply