+ All Categories

9ib_EXT

Date post: 10-Apr-2015
Category:
Upload: api-3831209
View: 46 times
Download: 2 times
Share this document with a friend
68
Extensibility New Features 1-1 New Oracle9i Features for Extensible Indexing and Extensible Optimizer
Transcript
Page 1: 9ib_EXT

Extensibility New Features 1-1

New Oracle9i Features for Extensible Indexing and Extensible Optimizer

Page 2: 9ib_EXT

Extensibility New Features 1-2

Objectives

At the end of this lesson, you should be able to:• Describe the process for implementing a local

domain index on a range-partitioned table– Create a local domain index for a range-

partitioned table– Identify INDEXTYPE routines and user defined

statistics routines to be enhanced• Describe the purpose and benefits of:

– Function-based domain indexes– Domain indexes on embedded object types– Domain indexes on Index-Organized tables

Page 3: 9ib_EXT

Extensibility New Features 1-3

Domain Index Enhancements for Oracle9i

• What’s new:– Create Local domain indexes for range-

partitioned tables– Collect statistics, cost and selectivity for local

domain indexes • Benefits: Extends local index capabilities to

application-specific domain indexes which enables:– Concurrent operations on two or more partitions – Concurrent rebuild of two or more partitions – Efficient searching on partition level indexes

Partitioned Domain IndexesIn Oracle8i, only non-partitioned domain indexes were supported. Even if the base table was partitioned, only global non-partitioned domain indexes were supported on it. In Oracle9i, local domain indexes on range-partitioned tables are supported. Local domain indexes on Index Organized Tables are not supported.

Local IndexLocal indexes are equi-partitioned with the underlying table. All keys in a particular index partition refer only to rows in a single underlying table partition.

INDEXTYPEIdentifies the set of operators that can be evaluated using a domain index that is specified using the index type.

Domain IndexThe domain index is an application-specific index that is created, managed and accessed by routines supplied by an INDEXTYPE.The Oracle server interacts with the application to build, maintain and search the domain index. The domain index indexes application-specific domains.Rather than natively build indexing schemes to cater to selected domains, Oracle provides an extensible approach to easily integrate new domain operators, indexing schemes, and related optimizer functions into DBMS.

UsageDBAs can take advantage of range partitioning in tables with domain indexes. Local domain indexes on hash-partitioned tables, composite-partitioned tables, list-partitioned tables, and Index Organized Tables (IOTs) are not supported.

Page 4: 9ib_EXT

Extensibility New Features 1-4

Local Domain Index Application Example:Oracle Spatial

• Oracle Spatial with Oracle8i:– Spatial object type manages point, line and

polygon geometries– Large Spatial data sets are common– Global domain indexes used for performance– Needs ability to partition data and domain

indexes by spatial attribute like region• Oracle Spatial with Oracle9i local domain index

support:– Partition elimination speeds query response– Users can query one partition while

simultaneously inserting data into another

Local Domain Indexes on Partitioned TablesMost spatial data sets are very large and randomly accessed. Spatial application performance can be enhanced with domain specific indexing and partitioned tables, focusing queries on relevant partitions. Oracle8i only supports global domain indexes on partitioned tables. However, queries using global domain indexes don’t benefit from table partitioning.With Oracle9i support for local domain indexes, users can partition their base table and create local domain indexes to query only relevant partitions, resulting in substantial performance improvements.For example, tables storing spatial geometries that describe regional sales information can be partitioned by region and local domain indexes can be built. This will allow only relevant partitions to be accessed during a query, resulting in faster query response.Also, the users get other benefits of partitioning like concurrent operations on partitions. For example, the users of the spatial cartridge could be querying one partition, while concurrently inserting data into another partition.

Page 5: 9ib_EXT

Extensibility New Features 1-5

INDEXTYPE: Implementation Steps

• Modify INDEXTYPE to permit local domain indexes– Modify existing ODCIIndex routines and add

new ODCIIndex routines– ALTER INDEXTYPE to specify support for range

partitioning• Modify statistics type using existing ODCIStats

routines to support partitioning

Implementing Local Partitioning on Domain IndexesAn object type describes data for particular application domain like chemicals or location. By default, operations on this object type are evaluated as functions on a per row basis.An index must be created in order for operators to be evaluated against an entire table or a partition of the table. Before an index can be created for the object type an INDEXTYPE is created. It associates a set of user-created, domain-specific operators and index routines with the object type and with any domain indexes that are subsequently created for the object type.The INDEXTYPE interface, ODCIIndex, has been enhanced to support local domain indexes. The application developer supplies the routines underlying the ODCIIndex interface for

• Domain-specific operators • Local domain index management, including the commands CREATE, DROP, and ALTER• Local domain index operations, including the commands SELECT, INSERT, UPDATE,

and DELETEALTER INDEXTYPE causes these changes take effect. Use the RANGE PARTITIONEDclause to specify support for local domain indexes After the DBA issues a DDL SQL statement to create an index on an object type, operators can be evaluated using the local, partition-level domain index.

Page 6: 9ib_EXT

Extensibility New Features 1-6

INDEXTYPE: Enhance Global DDL Routines

DDL commands and their associated OCI routines:

SQL DDLCREATE INDEXALTER TABLE ADD PARTITIONDROP INDEXALTER TABLE DROP PARTITIONALTER INDEXALTER INDEX MODIFY PARTITIONTRUNCATE TABLEALTER TABLE TRUNCATE PARTITION

ODCIIndex RoutineODCIIndexCreate()

ODCIIndexDrop()

ODCIIndexAlter()

ODCIIndexTruncate()

DDL Statements on Domain IndexesUpdate the routines on the slide to allow DDL statements on local domain indexes. All of these routines accept a parameter to specify global or local partition level operations

Page 7: 9ib_EXT

Extensibility New Features 1-7

INDEXTYPE: Create Partition DDL Routines

DDL commands and their associated OCI routines for partition level operations:

SQL DDLMERGE PARTITIONSPLIT PARTITIONEXCHANGE PARTITION

ODCIIndex RoutineODCIIndexMergePartition()ODCIIndexSplitPartition()ODCIIndexExchangePartition()

DDL Statements on Domain IndexesCreate the routines on the slide to allow DDL statements on local domain indexes.

Page 8: 9ib_EXT

Extensibility New Features 1-8

INDEXTYPE: Enhance Global DML Routines

OperationINSERTDELETEUPDATESELECT

DML commands and their associated OCI routines:

ODCIIndex Routine InvokedODCIIndexInsert()ODCIIndexDelete()ODCIIndexUpdate()ODCIIndexStart()ODCIIndexFetch()ODCIIndexClose()

DML Statements on Local Domain IndexesUpdate the routines on the slide to allow DML statements on local domain indexes.

Page 9: 9ib_EXT

Extensibility New Features 1-9

CREATE and ALTER INDEXTYPE

• Create a new INDEXTYPE for local domain index:

• Alter existing INDEXTYPE for local domain index :

CREATE INDEXTYPE spatial_indexFOR sdo_relate (

sdo_geometry, sdo_geometry, VARCHAR2 )USING spatialimpltypeWITH LOCAL RANGE PARTITION;

ALTER INDEXTYPE spatial_indexFOR sdo_relate (

sdo_geometry, sdo_geometry, VARCHAR2 )USING spatialimpltypeWITH LOCAL RANGE PARTITION;

ExamplesIn both examples, the SPATIAL_INDEX INDEXTYPEis used. This INDEXTYPEhas the following properties:

• Supports the SDO_RELATE operator • Indexes objects of type SDO_GEOMETRY• Is implemented using the SPATIALTIMPLTYPE

CREATE INDEXTYPEThe CREATE INDEXTYPE command defines a new INDEXTYPE, SPATIAL_INDEX, that supports the SDO_RELATE operator and is capable of supporting local domain indexes on range-partitioned tables.

ALTER INDEXTYPEThe ALTER INDEXTYPEcommand alters an existing INDEXTYPE, SPATIAL_INDEX, to specify that it now also has support for local domain indexes on range partitioned tables.

Page 10: 9ib_EXT

Extensibility New Features 1-10

Creating a Local Domain Index

CREATE INDEX sdo_index ON t1(c1)INDEXTYPE IS spatial_indexLOCAL (

PARTITION p1PARAMETERS('TABLESPACE sdo1'),

PARTITION p2PARAMETERS('TABLESPACE sdo2'))

PARAMETERS('PCTFREE 10');

Create Local Domain Index ExampleThe example shows how a local domain index, SDO_INDEX, can be created. It assumes that the base table, T1, is range-partitioned and has two partitions.It also assumes that the INDEXTYPESPATIAL_INDEX has already been created or altered to specify support for local domain indexes on range-partitioned tables.

Page 11: 9ib_EXT

Extensibility New Features 1-11

Enhance ODCIStats Type Routines

• ODCIStatsCollect and ODCIStatsDelete: collect or delete statistics for– A single table or index partition– The entire table or index

• ODCIStatsIndexCost: compute the scanning cost of

– One or more domain index partitions– The entire index

• ODCIStatsSelectivity: handle predicates involving

– One or more partitions– The entire table

ODCIStats ChangesOracle9i extensible optimizer extensions include support for local domain indexes. Modify ODCIStats routines to collect statistics at the index partition level as well as the index level.This support has been extended to statistics for column types too. So, user-defined statistics for columns should be modified to collect statistics at the table partition level as well as the table level.Similarly, the ODCIIndexCost function should be modified to compute the cost of a subset of index partitions as well as the cost for the entire index.The ODCIStatsSelectivityshould be modified to calculate the selectivity of predicates relative to interesting partitions as well as to the entire table.

Page 12: 9ib_EXT

Extensibility New Features 1-12

Function-Based Domain Indexes

• Extends function-based indexing to include support for domain indexes:– Indexes the return value of a function– There is no new syntax

• Example:CREATE INDEX idx1

ON t1(sdo_type(c1,c2))INDEXTYPE IS spatial_index;

Function Based IndexA function based index precomputes the result of an expression or function and stores it in an index. it provides an efficient mechanism to evaluate statements that contain functions in their WHERE clause.In Oracle8i, function-based indexes and domain indexes are not integrated; however, Oracle9iallows users to combine the richness of these two schemes and build function-based domain indexes.Cartridge developers or users who build new index typesmay not have to do any extra work to support this functionality. The benefit of a Function based index is the ability to take any data, transform it using functions to a datatype that an index type supports and index it.A function-based index enables Oracle Spatial queries and analysis on any data associated with a location attribute without creating and preloading an Oracle Spatial column of the type SDO_GEOMETRY. When a query is executed, the user-defined function converts the location attribute to an SDO_GEOMETRY type, perhaps using a geocoding service, and from that, creates the spatial index entry needed by the spatial operator to process the query.

ExampleIn the example above, there is an INDEXTYPE that is capable of indexing Spatial objects of type SDO_GEOMETRY. Oracle8i requires a column of type SDO_GEOMETRY in order for spatial operators to be evaluated in a query on the base table. With Oracle9i, if any of the columns in base table can be transformed, via a function, to a SDO_GEOMETRY type, spatial operators can be evaluated in queries on the table. In the example, function SDO_TYPE takes in two columns, C1 and C2, and returns a SDO_GEOMETRY type. So the DBA can build a function based domain index using the SPATIAL_INDEXINDEXTYPE.

Page 13: 9ib_EXT

Extensibility New Features 1-13

Domain Indexes on Embedded Object Types

• Allows creation of domain index on an object datatype nested to any level

• Example:

CREATE TYPE super_spatial AS OBJECT (attr NUMBER,data sdo_geometry );

CREATE TABLE t1 (c1 NUMBER,c2 super_spatial );

CREATE INDEX idx ON t1(c2.data)INDEXTYPE IS spatial_index;

Domain Indexes on Embedded Object TypesIn Oracle8i it is possible to create domain indexes on object types columns with the restriction that they be top level objects. Oracle9i extends domain indexes so they can be created on an object embedded within another object.Even though there is no syntax change, the users get the added capability to build domain indexes on embedded object types.Users also benefit. They can take an object type with a domain index built on it and seamlessly make it a part of another object. Existing domain indexes on the embedded object will continue to work.

ExampleThe example shows an object type SUPER_SPATIAL that takes a SDO_GEOMETRY type as one of its attributes. With Oracle9i, the INDEXTYPE, SPATIAL_INDEX, supports the creation of domain indexes on embedded objects of type SDO_GEOMETRY. A domain index can be created on the embedded object type column C2.DATA.

Page 14: 9ib_EXT

Extensibility New Features 1-14

Domain Indexes on IOTs

• Build secondary domain index on an index organized table (IOT)– No new syntax– ODCIIndex routines need to handle universal ROWIDs instead of physical ROWIDs

• Example CREATE TABLE t1 (c1 NUMBER PRIMARY KEY,c2 sdo_geometry )ORGANIZATION INDEX;

CREATE INDEX idx1 ON t1(c2)INDEXTYPE IS spatial_index;

Index Organized Table (IOT)An Index Organized Table is an table that stores data in its associated index. Changes to the table data result in updates to the index.In Oracle8i, there is support for secondary indexes on index organized tables and domain indexes. Domain indexes on index-organized tables are not supported. In Oracle9i, DBAs can build secondary domain indexes on IOTs.

Domain Indexes on IOTsFor domain indexes on regular heap-organized tables, the ODCIIndex routines often store the ROWID of the corresponding base table rows in their index structures as a ROWID or VARCHAR2column and access them during INSERT, DELETE, UPDATE, and SELECT. For domain indexes on IOTs, the ROWID of the base table needs to be stored in a UROWID column since IOTs don’t have physical ROWIDs. And ODCIIndex insert, update, delete, and query routines also need to be extended accordingly to handle universal ROWIDs.

ExampleThe example shows how a secondary domain index of type SPATIAL_INDEX can be built on a column of an index-organized table. In Oracle 8i, users of SPATIAL_INDEXwere restricted to having their base table to be non IOTs, but in Oracle 9i, domain indexes can be built on columns of tables, irrespective of their base table type.

Page 15: 9ib_EXT

Extensibility New Features 1-15

Summary

In this lesson, you should have learned that the Oracle9i Extensibility Architecture supports:

• Local domain indexes for range-partitioned tables, allowing application specific data to be indexed at the partition level.

• Function based indexes that allow domain data to be transformed via functions to a datatype that is supported by an INDEXTYPE and indexed.

• Domain indexes created on an object embedded within another object with no changes to application code.

• Secondary domain indexes on Index Organized Tables.

Page 16: 9ib_EXT

Extensibility New Features 2-1

Creating and Accessing Dynamic Data

Page 17: 9ib_EXT

Extensibility New Features 2-2

Objectives

After completing this lesson, you should be able to:• Describe the uses of the dynamic data• Create a dynamic data type• Create an instance of a dynamic data type• Access the dynamic data type• Access the instance of a dynamic data type

Page 18: 9ib_EXT

Extensibility New Features 2-3

Overview

• Can create and access dynamic datatypes:– Are not stored persistently in the DBMS– Include self-descriptive data– Can include single and multiple instances– Have C and SQL APIs

• Can create and access non-SQL datatypes in the Oracle9i DBMS

• Can be used in various database contexts• This lesson includes the PL/SQL implementation• For the OCI implementation, see the course OCI

Enhancements

Concepts• Transient types: type-descriptions, that is type meta-data, that are not stored persistently in

the database.• Persistent types: SQL types created using the CREATE TYPESQL statement. These type

descriptions are stored persistently in the database.• Self-descriptive data: Data encapsulating type information along with the actual contents.• Self-descriptive Multi-Set: encapsulation of a set of data instances of the same type, along

with their type description. They should all have the same type description.Overview

In Oracle 8.0, the only way for the user to create type descriptions was through the CREATE TYPE statement in SQL. Access to these type descriptions (OCIType) was provided through OCIDescribeAny(). The Type Interfaces provide C and SQL APIs to enable dynamic creation and access of type descriptions. Additionally, these new interfaces allow dynamic creation of transient type descriptions, that are not stored persistently in the DBMS.The SQL datatypes that will correspond to these data types are implemented using the Opaque Type Mechanism. This will enable creation of Database table columns and SQL queries on such data.The type interfaces are heterogeneous in nature, that is, a type can hold values of any other type in the DBMS and it can be converted back to a value of the appropriate type. Such heterogeneity can be modeled with an opaque type mechanism.Opaque types can be used from all kinds of database contexts: SQL, PLSQL, OCI, JAVA, triggers, and others.

Page 19: 9ib_EXT

Extensibility New Features 2-4

Features and Benefits

• Easier access to non-SQL datatypes• Stores non-SQL datatypes in the database:

– Type definition– Data

• Can be used with the extensible index optimizer• Can improve performance when accessing

multiple object instances

Features and BenefitsType and self descriptive data interfaces are useful for accessing information over the web that may be stored in a data type that is not compatible with SQL. Also, it can be used to store data in native formats in SQL tables to reduce the processing time need to convert between SQL and non-SQL data types. For example, non-SQL data types could be used in messages posted to Advanced Queuing.The extensible indexing and extensible optimizer projects need a way to pass these type descriptions and data as parameters to stored procedures.You can also model a set of type instances and pass the resulting entity as a parameter to stored procedures. This will provide performance enhancements during multi-row SQL operations.

Page 20: 9ib_EXT

Extensibility New Features 2-5

Installation

• Includes the opaque types:• SYS.AnyType• SYS.AnyData• SYS.AnyDataSet

Page 21: 9ib_EXT

Extensibility New Features 2-6

APIs

• AnyType is used to:

• Create and access transient types not stored in the DBMS

• Access persistent types created using CREATE TYPE

• Create and access collection types• AnyData is used to create and access a single self-

descriptive object• AnyDataSet is used to create and access multiple

instances of a self-descriptive object• DBMS_TYPES defines valid PL/SQL type codes

Self Descriptive Data Self descriptive data encapsulates the type information as well as a data instance of that type. Because the meta-data is included with the data, the type definitions are not stored persistently in the database.

C APIThe OCIAnyData type models a self descriptive data instance of a given type. That is, it can include the type definition and a single instance of that type. The OCIAnyDataSet type models a set of data instances of a given type.The C API enables creation and access of OCIAnyDataand OCIAnyDataSet.

SQL APIThe SQL API includes similar types:

• SYS.AnyData corresponds to OCIAnyData• SYS.AnyDataSet corresponds to OCIAnyDataSet

They enable creation of database table columns and SQL queries on such data.A data value of any SQL type can be converted to a SYS.AnyData type, which can be converted back to the old data value. An incorrect conversion attempt will result in an exception.The material in this course presents the SQL API.

Page 22: 9ib_EXT

Extensibility New Features 2-7

APIs: SYS.DBMS_TYPES

• DBMS_TYPES defines valid PL/SQL type codes

• Examples:TYPECODE_DATE PLS_INTEGER := 12;TYPECODE_NUMBER PLS_INTEGER := 2;TYPECODE_CHAR PLS_INTEGER := 96;TYPECODE_VARCHAR2 PLS_INTEGER := 9;TYPECODE_BFILE PLS_INTEGER := 114;TYPECODE_CLOB PLS_INTEGER := 112;TYPECODE_TIMESTAMP PLS_INTEGER := 187;TYPECODE_OBJECT PLS_INTEGER := 108;TYPECODE_VARRAY PLS_INTEGER := 247;

Using DBMS_TYPESThe package DBMS_TYPES contains constants that used to define the type of data being accessed when using the SYS.AnyType, SYS.AnyData, or SYS.AnyDatSetAPIs. It also contains exceptions that are raised when the data type enumerator is invalid.

Displaying DBMS_TYPES Type CodesTo see a complete list the codes in DBMS_TYPES in SQL*Plus, enter the command:

DESC SYS.DBMS_TYPESPackage DBMS_TYPES Type Codes

TYPECODE_DATE PLS_INTEGER := 12;TYPECODE_NUMBER PLS_INTEGER := 2;TYPECODE_RAW PLS_INTEGER := 95;TYPECODE_CHAR PLS_INTEGER := 96;TYPECODE_VARCHAR2 PLS_INTEGER := 9;TYPECODE_VARCHAR PLS_INTEGER := 1;TYPECODE_MLSLABEL PLS_INTEGER := 105;TYPECODE_BLOB PLS_INTEGER := 113;TYPECODE_BFILE PLS_INTEGER := 114;TYPECODE_CLOB PLS_INTEGER := 112;TYPECODE_CFILE PLS_INTEGER := 115;TYPECODE_TIMESTAMP PLS_INTEGER := 187;

Page 23: 9ib_EXT

Extensibility New Features 2-8

Package DBMS_TYPES Type Codes (continued)TYPECODE_TIMESTAMP_TZ PLS_INTEGER := 188;TYPECODE_TIMESTAMP_LTZ PLS_INTEGER := 232;TYPECODE_INTERVAL_YM PLS_INTEGER := 189;TYPECODE_INTERVAL_DS PLS_INTEGER := 190;TYPECODE_REF PLS_INTEGER := 110;TYPECODE_OBJECT PLS_INTEGER := 108;TYPECODE_VARRAY PLS_INTEGER := 247; /* COLLECTION TYPE */TYPECODE_TABLE PLS_INTEGER := 248; /* COLLECTION TYPE */TYPECODE_NAMEDCOLLECTION PLS_INTEGER := 122;TYPECODE_OPAQUE PLS_INTEGER := 58; /* OPAQUE TYPE */SUCCESS PLS_INTEGER := 0;NO_DATA PLS_INTEGER := 100;/* Exceptions */invalid_parameters EXCEPTION;PRAGMA EXCEPTION_INIT(invalid_parameters, -22369);incorrect_usage EXCEPTION;PRAGMA EXCEPTION_INIT(incorrect_usage, -22370);type_mismatch EXCEPTION;PRAGMA EXCEPTION_INIT(type_mismatch, -22626);END dbms_types;/CREATE PUBLIC SYNONYM dbms_types FOR sys.dbms_types;

Page 24: 9ib_EXT

Extensibility New Features 2-9

APIs: SYS.AnyType

• The SYS.AnyType API defines dynamic types

• It includes the following program units:BeginCreate() creates a new type of AnyTypeSetInfo() sets information for transient typesAddAttr() adds an attribute to an AnyTypeEndCreate() ends creation of a transient AnyTypeGetPersistent() returns a CREATE TYPE typeGetInfo() gets type information for the AnyTypeGetAttrElemInfo() gets type attribute information

SYS.AnyType Program UnitsBeginCreate() creates a new instance of AnyTypewhich can be used to create a transient type description. SetInfo() sets any additional information required for constructing a collection or built-in type. It is an error to call this function on an AnyType that represents a persistent user defined type.AddAttr() adds an attribute to an AnyType.EndCreate() ends the creation of a transient AnyType. Other creation functions cannot be called after this call.GetPersistent() returns an AnyType corresponding to a persistent type created earlier using the CREATE TYPE SQL statement.GetInfo() gets the type information for the AnyType.GetAttrElemInfo() gets the type information for an attribute of the type TYPECODE_OBJECTor gets the type information for a collection’s element type if the selfparameter is of a collection type.

Page 25: 9ib_EXT

Extensibility New Features 2-10

Example: Using AnyType

The PL/SQL example performs the following steps:• Creates procedure BUILD_ANYTYPE_WH that builds

the ANYTYPE variable passed to it• Creates procedure PRINT_ANYTYPE_ATTR that prints

out the properties of a ANYTYPE attribute. The procedure is passed two parameters:• The ANYTYPE variable

• The number of the attribute to print• The anonymous PL/SQL block:

• Builds an ANYTYPE object with three attributes• Calls PRINT_ANYTYPE_ATTR three times to display

the properties of each of the attributes just created

PL/SQL ExampleSQL> CREATE PROCEDURE build_anytype_wh (

2 p_any_type IN OUT sys.anytype )3 AS4 /* AnyType properties

*/5 BEGIN6 sys.AnyType.BeginCreate7 (DBMS_TYPES.TYPECODE_OBJECT, p_any_type);8 p_any_type.AddAttr (9 aname => 'warehouse_id',

10 typecode => DBMS_TYPES.TYPECODE_NUMBER,11 prec => 3,12 scale => 0,13 len => NULL,14 csid => NULL,15 csfrm => NULL );

Page 26: 9ib_EXT

Extensibility New Features 2-11

PL/SQL Example (continued)16 p_any_type.AddAttr (17 aname => 'warehouse_name',18 typecode => DBMS_TYPES.TYPECODE_VARCHAR2,19 prec => NULL,20 scale => NULL,21 len => 35,22 csid => NULL,23 csfrm => NULL );24 p_any_type.AddAttr (25 aname => 'location_id',26 typecode => DBMS_TYPES.TYPECODE_NUMBER,27 prec => 4,28 scale => 0,29 len => NULL,30 csid => NULL,31 csfrm => NULL );32 p_any_type.EndCreate;33 END;34 /

Procedure created.

SQL> CREATE PROCEDURE print_anytype_attr (2 p_any_type IN sys.anytype,3 p_attr_id IN NUMBER )4 AS5 /* AnyType properties

*/6 v_prec PLS_INTEGER; /* Numeric precision */7 v_scale PLS_INTEGER; /* Numeric precision */8 v_len PLS_INTEGER; /* Character length */9 v_csid PLS_INTEGER; /* Character set ID */

10 v_csfrm PLS_INTEGER; /* Character set form */11 v_attr_elt_type sys.AnyType; /* Object attribute */12 v_aname VARCHAR2(40); /* Attribute name */13 v_attr_type PLS_INTEGER; /* Attr. object code */14 BEGIN

Page 27: 9ib_EXT

Extensibility New Features 2-12

PL/SQL Example (continued)15 v_attr_type := p_any_type.GetAttrElemInfo (16 pos => p_attr_id,17 prec => v_prec,18 scale => v_scale,19 len => v_len,20 csid => v_csid,21 csfrm => v_csfrm,22 attr_elt_type => v_attr_elt_type,23 aname => v_aname );24 dbms_output.put_line('type code: ' || v_attr_type);25 dbms_output.put_line('aname: ' || v_aname);26 dbms_output.put_line('prec: ' || v_prec);27 dbms_output.put_line('scale: ' || v_scale);28 dbms_output.put_line('len: ' || v_len);29 dbms_output.put_line('csid: ' || v_csid);30 dbms_output.put_line('csfrm: ' || v_csfrm);31 END;32 /

Procedure created.

SQL> DECLARE2 v_any_type sys.AnyType; /* AnyType variable */3 BEGIN4 /* Build the ANYTYPE variable. */5 build_anytype_wh(v_any_type);6 /* Now, get the information about the type's attributes.

*/7 dbms_output.put_line('Properties for the 1st attribute');8 print_anytype_attr(v_any_type, 1);9 dbms_output.put_line('.');

10 dbms_output.put_line('Properties for the 2nd attribute');11 print_anytype_attr(v_any_type, 2);12 dbms_output.put_line('.');13 dbms_output.put_line('Properties for the 3rd attribute');14 print_anytype_attr(v_any_type, 3);15 END;16 /

Page 28: 9ib_EXT

Extensibility New Features 2-13

PL/SQL Example (continued)The anonymous PL/SQL block produces the following output:Properties for the 1st attributetype code: 2aname: warehouse_idprec: 3scale: 0len:csid:csfrm:.Properties for the 2nd attributetype code: 9aname: warehouse_nameprec:scale:len: 35csid: 0csfrm: 1.Properties for the 3rd attributetype code: 2aname: location_idprec: 4scale: 0len:csid:csfrm:

PL/SQL procedure successfully completed.

SQL>

Page 29: 9ib_EXT

Extensibility New Features 2-14

APIs: SYS.AnyData

• SYS.AnyData defines a single dynamic object

• Two ways to construct:• Convert from:

• Oracle ORDBMS data type•SYS.AnyData

• Piece by piece construction• Get calls access attributes

Using SYS.AnyData to Build an Object InstanceThere are two ways to construct an AnyData types:

• Convert*() calls enable construction of the AnyData in its entirety with a single call. They serve as explicit CAST functions from any type in the Oracle ORDBMS to SYS.AnyData.

• The piece by piece approach uses the following types of calls:– BeginCreate()begins the construction process– Set*() calls add attributes– EndCreate() finishes the construction process

The AnyData has to be constructed or accessed sequentially starting from its first attribute or collection element.Get*() calls are used to access the attributes of the AnyData object. For piece by piece access of the attributes of objects and elements of collections, the PieceWise() call should be invoked prior to Get*() calls.For Convert*, Get*, and Set* calls, the “*” is replaced with one of the following:

• The name of a built-in datatype• OBJECT indicates that an object is being accessed• REF indicates that an object reference is being accessed• COLLECTION indicates that a collection is being accessed

Page 30: 9ib_EXT

Extensibility New Features 2-15

APIs: SYS.AnyData Program Units

• Convert*() converts from Oracle SQL datatypes• BeginCreate() creates a new AnyData instance• PieceWise() sets the access mode of the data• Set*() procedures set the current data value• EndCreate() ends the creation of the instance• GetTypeName() gets the type name for the AnyData• GetType() returns the type code for the AnyData• Get*() gets the current data value

SYS.AnyData Program UnitsConvert*() functions are used to convert instances of built-in types to AnyData. The function called depends on the type of the parameter. BeginCreate() begins creation process on a new AnyData instance. PieceWise() sets the MODE of access of the current data value to one of the following:

• If the data value is of a TYPECODE_OBJECT, then the mode is an attribute at a time• If the data value is of a collection type, then the mode is a collection element at a time

There is no support for piece-wise construction or access of embedded object type attributes or nested collections. Once this call has been made, subsequent Set*() and Get*() calls will sequentially obtain individual attributes or collection elements.Set*() procedures set the current data value. The procedure called depends on the type of the current data value. The type of the data value should be the type of the attribute at the current position during the piece-wise construction process. When BeginCreate() is called, construction has already begun in a piece-wise fashion. Subsequent calls to Set*()will set the successive attribute values. If the AnyData is a standalone collection, the Set*() call will set the successive collection elements. Parameters for Set*() procedures include:

• self is the AnyData instance being set• value is the value for the next attribute in self, the actual parameter name depends on

the procedure being called and is included in the specification listed subsequently• last_elem is relevant only if AnyData represents a a collection and is set to TRUE if it

is the last element of the collectionEndCreate() ends Creation of a AnyData.Other creation functions cannot be called after this call.

Page 31: 9ib_EXT

Extensibility New Features 2-16

SYS.AnyData Program Units (continued)GetType() function returns the type code corresponding to the type of the AnyData parameter passed to the function. Its parameters include:

• self is the AnyData instance• typ is the AnyType corresponding to the AnyData, and is NULL if it does not represent

a user-defined typeGetTypeName() gets the fully qualified type name for the AnyData. The type name returned depends on the type of the single parameter, self, passed to GetTypeName().

• If self is based on a built-in type, this function will return the built-in type, for example NUMBER or DATE

• If self is based on a user defined type, this function will return the schema_name, a period, and the type name, for example HR.EMP

• If self is based on a transient anonymous type, this function will return NULL.Get*() gets the current data value, with its type dependent on the MODE with which we are accessing the data. The MODE is set by calling PieceWise(). If PieceWise() has not been called, you are accessing the AnyData in its entirety and the type of the data value should match the type of the AnyData. If PieceWise() has been called, you are accessing the AnyDatapiece wise. The type of the data value should match the type of the attribute or collection element at the current position. The parameters for the Get*() functions include:

• self is the AnyData instance• value is the value of the data being retrieved, but the actual parameter name depends on the

function being calledThe Get*() function returns DBMS_TYPES.SUCCESSor DBMS_TYPES.NO_DATA. The return value is relevant only if PieceWise() has been already called for a collection. In such a case, DBMS_TYPES.NO_DATAsignifies the end of the collection when all elements have beenaccessed.

Page 32: 9ib_EXT

Extensibility New Features 2-17

Example: Use the AnyData Datatype

• Create a table with an AnyData column• Create the WAREHOUSE_TYP object type

• Insert two rows with different datatypes into the table• In a PL/SQL block loop through each row:

• Get the ANYDATA column• Get the TYPE_CODE of the AnyData column

• If the type is a number, print it• If the type is an object:

• Get the schema and object name• If the schema and name are valid, print the

object

SQL and PL/SQL ExampleSQL> CREATE TABLE any_data_table (

2 any_data SYS.AnyData );

Table created.

SQL> CREATE TYPE warehouse_typ AS OBJECT2 ( warehouse_id NUMBER(3)3 , warehouse_name VARCHAR2(35)4 , location_id NUMBER(4)5 ) ;6 /

Type created.

SQL> /* Insert a built-in type value after explicit conversion to AnyData. */SQL> INSERT INTO any_data_table

2 VALUES (SYS.AnyData.ConvertNumber(5));

1 row created.

Page 33: 9ib_EXT

Extensibility New Features 2-18

SQL and PL/SQL Example (continued)SQL> /* Insert a user-defined object after explicit conversion to an AnyData */SQL> INSERT INTO any_data_table

2 VALUES (SYS.AnyData.ConvertObject (3 warehouse_typ(1, 'Southlake, Texas', 1400) ));

1 row created.

SQL> COMMIT;

Commit complete.

SQL> DECLARE2 v_any_type SYS.AnyType;3 v_any_data SYS.AnyData;4 v_warehouse warehouse_typ; /* Put AnyData here */5 /* AnyType properties

*/6 v_prec PLS_INTEGER; /* Numeric precision

*/7 v_scale PLS_INTEGER; /* Numeric precision

*/8 v_len PLS_INTEGER; /* Character length

*/9 v_csid PLS_INTEGER; /* Character set ID

*/10 v_csfrm PLS_INTEGER; /* Character set form

*/11 v_attr_elt_type sys.AnyType; /* Object attribute

*/12 v_schema_name VARCHAR2(40); /* Object owner

*/13 v_type_name VARCHAR2(40); /* Object name

*/14 v_version VARCHAR2(40); /* Version */15 v_count PLS_INTEGER; /* Number of attributes

*/16 v_aname VARCHAR2(40); /* Attribute name

*/17 v_type_code PLS_INTEGER; /* Object type code

*/18 v_return PLS_INTEGER; /* Return code = status

*/19 v_n NUMBER;20 21 CURSOR any_data_c IS

Page 34: 9ib_EXT

Extensibility New Features 2-19

SQL and PL/SQL Example (continued)27 LOOP28 FETCH any_data_c INTO v_any_data;29 EXIT WHEN any_data_c%NOTFOUND;30 31 /* Get the type of data stored in v_any_data */32 v_type_code := v_any_data.GetType(v_any_type);33 34 /* Test the type. */35 IF v_type_code = DBMS_TYPES.TYPECODE_NUMBER THEN36 /* It is a number, so print it */37 v_return := v_any_data.GetNumber(v_n);38 dbms_output.put_line(39 'The value for the number datatype is: ' || v_n);40 ELSIF (v_type_code = DBMS_TYPES.TYPECODE_OBJECT) THEN41 /* It is an object, so get the schema and type */42 v_type_code := v_any_type.GetInfo (43 v_prec,44 v_scale,45 v_len,46 v_csid,47 v_csfrm,48 v_schema_name,49 v_type_name,50 v_version,51 v_count );52 /* Verify that the schema and type is correct */53 IF v_schema_name = USER54 AND (v_type_name = 'WAREHOUSE_TYP') THEN55 /* It is, so print its attribute information */56 dbms_output.put_line('1st attribute');57 print_anytype_attr(v_any_type, 1);58 dbms_output.put_line('.');59 dbms_output.put_line('2nd attribute');60 print_anytype_attr(v_any_type, 2);61 dbms_output.put_line('.');62 dbms_output.put_line('3rd attribute');63 print_anytype_attr(v_any_type, 3);

Page 35: 9ib_EXT

Extensibility New Features 2-20

SQL and PL/SQL Example (continued)64 /* Now, print it attribute values */65 v_return := v_any_data.GetObject(v_warehouse);66 DBMS_OUTPUT.PUT_LINE (67 'Warehouse: ' || v_warehouse.warehouse_id68 || ' named ' || v_warehouse.warehouse_name

);69 ELSE /* Invalid schema.type */70 dbms_output.put_line (71 'Mismatch: Type code is: ' || v_type_code );72 dbms_output.put_line (73 'Mismatch: Schema is : ' || v_schema_name );74 dbms_output.put_line (75 'Mismatch: Type name is: ' || v_type_name );76 END IF;77 ELSE /* Invalid type code */78 dbms_output.put_line (79 'Mismatch: Type code is: ' || v_type_code );80 END IF;81 END LOOP;82 EXCEPTION83 WHEN DBMS_TYPES.TYPE_MISMATCH THEN84 DBMS_OUTPUT.PUT_LINE('Invalid data type');85 END;86 /

Page 36: 9ib_EXT

Extensibility New Features 2-21

SQL and PL/SQL Example (continued)The anonymous PL/SQL block produces the following output:The value for the number datatype is: 51st attributetype code: 2aname: WAREHOUSE_IDprec: 3scale: 0len:csid:csfrm:.2nd attributetype code: 9aname: WAREHOUSE_NAMEprec:scale:len: 35csid: 31csfrm: 1.3rd attributetype code: 2aname: LOCATION_IDprec: 4scale: 0len:csid:csfrm:Warehouse: 1 named Southlake, Texas

PL/SQL procedure successfully completed.

SQL>

Page 37: 9ib_EXT

Extensibility New Features 2-22

APIs: SYS.AnyDataSet

• SYS.AnyDataSet defines multiple dynamic objects• Use AddInstance() to add an new instance to an AnyDataSet

• Subsequent Set*() calls set the current data values• Similar to SYS.AnyData.PieceWise()

• No support for piecewise construction and access of nested objects

Using SYS.AnyDataSet to Build Object InstancesThe AnyDataSet type is constructed value by value sequentially. For each data instance, of the type of the AnyDataSet, the AddInstance() function need to be invoked to add a new data instance to the AnyDataSet. Subsequently, Set*() can be called to set each value in its entirety.The MODE of construction or access can be changed to attribute and collection element by making calls to PieceWise():

• If the type of the AnyDataSet is TYPECODE_OBJECT, individual attributes will be set with subsequent Set*() calls, or retrieved with Get*() calls.

• If the type of the current data value is a collection type, individual collection elements will be set with subsequent Set*() calls, or retrieved with Get*()calls.

This call is very similar to AnyData.PieceWise()call defined for the type SYS.AnyData.There is no support for piecewise construction and access of nested, that is not top level, attributes that are of object types or collection types.EndCreate() should be called to finish the construction process. No access calls can be made until construction is complete.

Page 38: 9ib_EXT

Extensibility New Features 2-23

APIs: SYS.AnyDataSet Program Units

• BeginCreate creates a new AnyDataSet• AddInstance() adds an instance to an AnyDataSet• PieceWise() sets the access mode of the data• Set*() procedures set the current data value• EndCreate() ends the creation of the dataset• GetTypeName() gets the type name for the AnyData• GetType() returns the type code for the AnyData• GetInstance() gets the next instance• Get*() gets the current data value

SYS.AnyDataSet Program UnitsBeginCreate() creates a new AnyDataSetwhich can be used to create a set of data values of the given AnyType.AddInstance() adds a new data instance to a AnyDataSet. The data instances have to be added sequentially. The previous data instance must be fully constructed or set to NULL before a new one can be added. This call does not automatically set the mode of construction to be piece-wise. The user has to explicitly call PieceWise() if a piece-wise construction of the instance is intended. PieceWise() performs the same as in SYS.AnyData, except that its input parameter is of the AnyDataSet type, instead of the AnyData type.Set*() procedures perform the same as in SYS.AnyData, except that its first input parameter is of the AnyDataSet type, instead of the AnyData type. Parameters for Set*() procedures include:

• self is the AnyDataSet being set• value is the value for the next attribute in self, the actual parameter name depends on

the procedure being called and is included in the specification listed subsequently• last_elem is relevant only if AnyDataSet represents a a collection and is set to TRUE

if it is the last element of the collectionEndCreate() ends Creation of a AnyDataSet.Other creation functions cannot be called after this call. GetType() function gets the AnyType describing the type of the data instances in an AnyDataSet. It performs the same as in SYS.AnyData, except that its first input parameter is of the AnyDataSet type, instead of the AnyData type.GetTypeName() gets the fully qualified type name for the AnyDataSet. It performs the same as in SYS.AnyData, except that its first input parameter is of the AnyDataSet type, instead of the AnyData type.

Page 39: 9ib_EXT

Extensibility New Features 2-24

SYS.AnyDataSet Program Units (continued)GetInstance() gets the next instance in an AnyDataSet. This function should be called even before accessing the first instance. Only sequential access to the instances in an AnyDataSet is allowed. After this function has been called, the Get*() functions can be invoked on the AnyDataSet to access the current instance. If PieceWise() is called before doing the Get*() calls, the individual attributes or collection elements can be accessed. It is an error to invoke this function before the AnyDataSet is fully created. Its single parameter, selfis the AnyDataSet being accessed. The value returned from the function indicates whether the get was successful:

• DBMS_TYPES.SUCCESS indicates that the AnyData instance was available• DBMS_TYPES.NO_DATAsignifies the end of the AnyDataSet, that is, all instances

have been accessedGet*() gets the current data value. It performs the same as in SYS.AnyData, except that its first input parameter is of the AnyDataSet type, instead of the AnyData type.

Page 40: 9ib_EXT

Extensibility New Features 2-25

Example: Use the AnyDataSet Datatype

• Create an AnyType object from the user-defined type WAREHOUSE_TYP , because it is used to create the AnyDataSet object

• Builds an AnyDataSet object with two instances of WAREHOUSE_TYP objects

• Gets and print the two AnyDataSet instances

PL/SQL ExampleSQL> DECLARE

2 v_any_type SYS.AnyType;3 v_any_data SYS.AnyData;4 v_any_data_set SYS.AnyDataSet;5 v_warehouse warehouse_typ; /* Put AnyData here */6 /* AnyType properties */7 v_return PLS_INTEGER; /* Return code = status */8 9 BEGIN

10 11 /* Create an AnyType object from a user-defined type */12 /* Used to create the AnyDataSet */13 v_any_type := sys.AnyType.GetPersistent14 (user, 'WAREHOUSE_TYP');15 16 /* Start building the AnyDataSet */

Page 41: 9ib_EXT

Extensibility New Features 2-26

PL/SQL Example (continued)16 /* Start building the AnyDataSet */17 sys.AnyDataSet.BeginCreate (18 DBMS_TYPES.TYPECODE_OBJECT,19 v_any_type,20 v_any_data_set );21 22 /* Insert the 1st object into the AnyDataSet object */23 v_any_data_set.AddInstance;24 v_any_data_set.SetObject (25 warehouse_typ(1, 'Southlake, Texas', 1400) );26 27 /* Insert the 2nd object into the AnyDataSet object */28 v_any_data_set.AddInstance;29 v_any_data_set.SetObject (30 warehouse_typ(2, 'Las Cruces, NM', 1200) );31 32 /* Finish building */33 v_any_data_set.EndCreate;34 35 /* Get and print the 1st AnyDataSet instance */36 v_return := v_any_data_set.GetInstance;37 v_return := v_any_data_set.GetObject(v_warehouse);38 dbms_output.put_line (39 'Warehouse: ' || v_warehouse.warehouse_id40 || ' named ' || v_warehouse.warehouse_name );41 42 /* Get and print the next AnyDataSet instance */43 v_return := v_any_data_set.GetInstance;44 v_return := v_any_data_set.GetObject(v_warehouse);45 dbms_output.put_line (46 'Warehouse: ' || v_warehouse.warehouse_id47 || ' named ' || v_warehouse.warehouse_name );48 END;49 /

Warehouse: 1 named Southlake, TexasWarehouse: 2 named Las Cruces, NM

PL/SQL procedure successfully completed.

SQL>

Page 42: 9ib_EXT

Extensibility New Features 2-27

Summary

In this lesson, you should have learned how to:• Describe the uses of the dynamic data• Create a dynamic data type• Create an instance of a dynamic data type• Access the instance of a dynamic data type

Page 43: 9ib_EXT

Extensibility New Features 3-1

Other Extensibility Enhancements

Page 44: 9ib_EXT

Extensibility New Features 3-2

Objectives

After completing this lesson you should be able to:• User-defined Aggregates• Table functions

Page 45: 9ib_EXT

Extensibility New Features 3-3

Overview

• Extensibility is the ability to create user-defined objects in the database to extend the functionality of pre-defined objects.

• Oracle Data Cartridge Interface(ODCI) is used to extend database functionality with• User Defined aggregates• Table functions

Page 46: 9ib_EXT

Extensibility New Features 3-4

User Defined Group FunctionsOracle includes a set of aggregate, or group, functions such as MAX, MIN, SUM, and others. In Oracle9i, the ability to apply function to a set of rows has been extended to user-defined functions. User Defined Aggregate (UDAG) functions refer to aggregate functions with user specified aggregation semantics. Developers create a new aggregate function and provide the aggregation logic with a set of routines. Once created, the user defined aggregate function can be used in SQL DML statements in a manner similar to built-in aggregates. The Oracle server evaluates the UDAG by invoking the user provided aggregation routines appropriately.As databases are increasingly being used to store complex data, such as multimedia, complex data types are typically stored in the database using object types, opaque types and LOBs. User-defined aggregates are useful in specifying aggregation over such new domains of data. For example, Oracle Spatial cartridge (Spatial) provides a Geometry object type and needs to define a SpatialUnionaggregate function that returns the bounding geometry.

Of course, UDAGs can be used to create new aggregate functions over traditional scalar data types for financial or scientific applications. Since, it is not possible to provide native support for all forms of aggregates, it is desirable to provide application developers with a flexible mechanism to add new aggregate functions.

User Defined Group Functions

• Can be created in Oracle 9i

• Called User Defined Aggregate (UDAG) functions• Useful for aggregating over object types• Can include:

– DISTINCT or ALL options on input parameters– GROUPING functions, such as CUBE or ROLLUP

• Used in SELECTs and DML in the same manner as built-in group functionsSELECT sum_sal_udag(employee_object)FROM employeesGROUP BY department_id;

SELECT sum_sal_udag(employee_object)FROM employeesGROUP BY department_id;

Page 47: 9ib_EXT

Extensibility New Features 3-5

Group Function LogicAn aggregate function conceptually takes a set of values as input and returns a single value. The

sets of values for aggregation are typically identified using a GROUP BY clause.The evaluation of an aggregate function can be decomposed into three primitive operations1. Initialize: Create and initialize variables used in the computation.2. Iterate: Use the input parameters from the function invocation on the SQL statement to

perform the aggregation3. Terminate: Complete any additional computation required on the aggregated values and

return the resultThe state or context of the aggregation is the set of variables that are used in these three

primitive operations. To retain the context of the aggregation, these variables keep their values between calls to these primitives, like global variables in PL/SQL packages.

In addition, we require one more primitive operation to merge two aggregation contexts and create a new context. This operation is needed to:

• Combine the results of aggregation over subsets and obtain the aggregate over the entire set, as required when using the GROUP BY clause

• Perform serial and parallel evaluations of the aggregate function

Aggregation Logic

• The variables used in the aggregation:– Is the context or state of the aggregation– Retain their values between calls

• Aggregation logic Includes four operations:– Initialize: Initial the context– Iterate: Update the context with row values– Merge: combine context for GROUP BY– Terminate:

– Complete the computation– Return a result

Page 48: 9ib_EXT

Extensibility New Features 3-6

Aggregation ExampleFor example, the AVG group function could implement these three primitives operations using

the following logic:1. Initialize: initialize the aggregation context:

runningSum := 0;runningCount := 0;

2. Iterate: update the aggregation context by processing the new input value, inputvalrunningSum := runningSum + inputval;runningCount := runningCount + 1;

3. Merge: combine the two aggregation contexts, ctx1 and ctx2, and return a single context, ctx1

ctx1.runningSum = ctx1.runningSum + ctx2.runningSum;ctx1.runningCount = ctx1.runningCount +

ctx.runningCount;4. Terminate: return the aggregation result

return (runningSum/runningCount);In the above example, the variables runningSum and runningCount determine the state of

the aggregation.

Page 49: 9ib_EXT

Extensibility New Features 3-7

Aggregation Interface

To create a UDAG function, the developer creates an object type that implements the four primitives described earlier. The object types includes a method for each of the four primitives. This set of functions is collectively known as ODCIAggregate Interface, where ODCI is the abbreviation for Oracle Data Cartridge Interface.All of these primitives return a numeric value to indicate whether the function was successful. Use ODCIConst.Successon success or ODCIConst.Erroron error.

The aggregation interface is implemented using the method names defined below.ODCIAggregateInitialize

This routine is invoked by Oracle to initialize the computation of the UDAG. The initialized aggregation context is passed back to Oracle as an object type instance.

ODCIAggregateIterateThis routine is repeatedly invoked by Oracle as each row is processed. On each invocation, new values, as well as the current aggregation context, are passed as input. The routine processes the new values and returns the updated aggregation context back to Oracle.

ODCIAggregateMergeThis routine is invoked by Oracle to combine two aggregation contexts. This routine takes the two contexts as inputs, combines them and returns the resulting aggregate context.

ODCIAggregateterminateThis routine is invoked by oracle as the final step of aggregation. The routine takes the aggregation context as input, performs any additional computation that may be required, and returns the result aggregate value.

Aggregation Implementation

• UDAGs are implemented through the ODCIAggregate Interface

• These methods implement the aggregate primitives:– Initialize: ODCIAggregateInitialize– Iterate: ODCIAggregateIterate– Merge: ODCIAggregateMerge– Terminate: ODCIAggregateTerminate

Page 50: 9ib_EXT

Extensibility New Features 3-8

Creating the UDAG Function

• To create a UDAG function, the developer:1. Creates the object type specification for the four

primitives2. Creates the type body for the four primitives3. Creates the UDAG function4. Uses the function

• The example on the following slides:• Creates a UDAG function that returns the second

highest number• Uses:

• SecondMaxImpl as the interface object type• SecondMax as the UDAG function name

Page 51: 9ib_EXT

Extensibility New Features 3-9

ExampleAll of the code for creating the object type specification is listed below:

CREATE TYPE SecondMaxImpl AS OBJECT (Max NUMBER, --highest valueSecmax NUMBER, --second highest value

STATIC FUNCTION ODCIAggregateInitialize (self_ctx OUT SecondMaxImpl )RETURN NUMBER,

MEMBER FUNCTION ODCIAggregateIterate (self IN OUT SecondMaxImpl,value IN

NUMBER )RETURN NUMBER,

Create the Object Type Specification

CREATE TYPE SecondMaxImpl AS OBJECT (max NUMBER, --highest valuesecmax NUMBER, --second highest value

STATIC FUNCTION ODCIAggregateInitialize(self_ctx OUT SecondMaxImpl)RETURN NUMBER,

. . .MEMBER FUNCTION ODCIAggregateIterate. . .MEMBER FUNCTION ODCIAggregateMerge. . .MEMBER FUNCTION ODCIAggregateTerminate. . .

);/

CREATE TYPE SecondMaxImpl AS OBJECT (max NUMBER, --highest valuesecmax NUMBER, --second highest value

STATIC FUNCTION ODCIAggregateInitialize(self_ctx OUT SecondMaxImpl)RETURN NUMBER,

. . .MEMBER FUNCTION ODCIAggregateIterate. . .MEMBER FUNCTION ODCIAggregateMerge. . .MEMBER FUNCTION ODCIAggregateTerminate. . .

);/

Page 52: 9ib_EXT

Extensibility New Features 3-10

Example (continued)MEMBER FUNCTION ODCIAggregateMerge (

self IN OUT SecondMaxImpl,ctx2 IN

SecondMaxImpl )RETURN NUMBER,

MEMBER FUNCTION ODCIAggregateTerminate (self IN

SecondMaxImpl,result OUT

NUMBER,

flags INNUMBER )

RETURN NUMBER);/

Page 53: 9ib_EXT

Extensibility New Features 3-11

ExampleAll of the code for creating the object type body is listed below:

CREATE TYPE BODY SecondMaxImpl IS

STATIC FUNCTION ODCIAggregateInitialize (self_ctx OUT SecondMaxImpl )RETURN NUMBER

IS

BEGINself_ctx := SecondMaxImpl(0, 0);RETURN ODCIConst.Success;

END;

MEMBER FUNCTION ODCIAggregateIterate (self IN OUT SecondMaxImpl,value IN

NUMBER )RETURN NUMBER

ISBEGIN

Create the Object Type Body

CREATE OR REPLACE TYPE BODY SecondMaxImpl ISSTATIC FUNCTION ODCIAggregateinitialize (...MEMBER FUNCTION ODCIAggregateiterate (...MEMBER FUNCTION ODCIAggregateterminate (...MEMBER FUNCTION ODCIAggregatemerge (...

END;

CREATE OR REPLACE TYPE BODY SecondMaxImpl ISSTATIC FUNCTION ODCIAggregateinitialize (...MEMBER FUNCTION ODCIAggregateiterate (...MEMBER FUNCTION ODCIAggregateterminate (...MEMBER FUNCTION ODCIAggregatemerge (...

END;

Page 54: 9ib_EXT

Extensibility New Features 3-12

Example (continued)IF value > self.max THEN

self.secmax := self.max;self.max := value;

ELSIF value > self.secmax THENself.secmax := value;

END IF;RETURN ODCIConst.Success;

END;

MEMBER FUNCTION ODCIAggregateMerge (self IN OUT SecondMaxImpl,ctx2 IN

SecondMaxImpl )RETURN NUMBER

ISBEGIN

IF ctx2.max > self.max THENIF ctx2.secmax > self.secmax THEN

self.secmax := ctx2.secmax;ELSE

self.secmax := self.max;END IF;self.max := ctx2.max;

ELSIF ctx2.max > self.secmax THENself.secmax := ctx2.max;

END IF;RETURN ODCIConst.Success;

END;

MEMBER FUNCTION ODCIAggregateTerminate (self IN

SecondMaxImpl,result OUT

NUMBER,

flags INNUMBER )

RETURN NUMBERISBEGIN

result := self.secmax;RETURN ODCIConst.Success;

END;

END;/

Page 55: 9ib_EXT

Extensibility New Features 3-13

GuidelinesBecause the second parameter in ODCIAggregateTerminateis the value returned by the user-defined group function, its data type must match the data type returned by this function. This is the RESULT parameter in the example, and it has a datatype of NUMBER.

The USING clause provides the name of the PL/SQL package that implements the ODCIAggregate interface. Is is SecondMaxImpl in the example.

Create the UDAG Function

• Create the UDAG function

• Guidelines:• Match the RETURN data type with the data

type in the ODCIAggregateTerminatemethod

• The USING clause maps this function to its ODCIAggregate interface

CREATE FUNCTION SecondMax(pnum NUMBER )RETURN NUMBERAGGREGATE USING SecondMaxImpl;

CREATE FUNCTION SecondMax(pnum NUMBER )RETURN NUMBERAGGREGATE USING SecondMaxImpl;

Page 56: 9ib_EXT

Extensibility New Features 3-14

Use the UDAG Function

SQL> SELECT department_id,2 SecondMax(salary) AS sal23 FROM employees4 GROUP BY department_id5 HAVING SecondMax(salary) > 2000;

DEPTNO SAL2---------- ----------

10 245020 2975

SQL> SELECT department_id,2 SecondMax(salary) AS sal23 FROM employees4 GROUP BY department_id5 HAVING SecondMax(salary) > 2000;

DEPTNO SAL2---------- ----------

10 245020 2975

Page 57: 9ib_EXT

Extensibility New Features 3-15 4

Overview of Table Functions

• Oracle 8i:

– User functions in Oracle8i can return tables as collection types

– These functions can be used in the FROM clause with TABLE keyword

• Oracle9i Enhancements.

– Support for table functions that will allow for multiple rows as both input and output

– Allows the pipelining of results out of table functions

– Allows for partitioning input result sets to enable parallel execution of table functions

Page 58: 9ib_EXT

Extensibility New Features 3-16

Benefits of Table Functions

• Used as virtual tables in the FROM clause• Improves performance, because they:

– Allow results to be displayed as soon as they are produced

– Eliminate the need to buffer the produced rows which reduces execution time

– Eliminate the need for staging tables in data warehousing applications

– Can be performed in parallel• Parallel execution capability speeds up the

Extraction-Transformation-Load (ETL) process in data warehousing applications

Pipeline and Parallel FunctionsTable functions are defined as functions that can produce a set of rows as output. This feature allows table Functions can be used to pipeline results out of functions. It provides a flexible and powerful interface based mechanism to implement pipelined table functions. It also provides a simple and efficient native PL/SQL mechanism to implement pipelined table function.In addition table and non table functions are extended to allow parallel execution. The parallel execution capability is provided by integrating these functions with Oracle's row-source execution mechanism. Parallel execution will allow functions to directly accept a set of rows corresponding to a subquery operand. It also provides a mechanism that allows a set of input rows to be partitioned among multiple instances of a parallel function.

Page 59: 9ib_EXT

Extensibility New Features 3-17

Pipelined Table Functions

• Similar to a table returning a collection• Can return the result collection in subsets• Can be parallelized:

– Table functions follow the same model for data partitioning as that used by Oracle's parallel query framework

– Table functions do not need to be coded any differently for parallel execution

– The function will execute serially if enough slaves are not available at the run time

Pipeline and Parallel FunctionsTable functions are defined as functions that can produce a set of rows as output. The returned collection behaves like a stream that can be fetched on demand. This feature allows table Functions can be used to pipeline results out of functions. It provides a flexible and powerful interface based mechanism to implement pipelined table functions. It also provides a simple and efficient native PL/SQL mechanism to implement pipelined table function.Also, a table function can fetch multiple rows at each invocation, reducing the total number of invocations, and improving performance.In addition table and non table functions are extended to allow parallel execution. The parallel execution capability is provided by integrating these functions with Oracle's row-source execution mechanism. Parallel execution will allow functions to directly accept a set of rows corresponding to a subquery operand. It also provides a mechanism that allows a set of input rows to be partitioned among multiple instances of a parallel function.

Page 60: 9ib_EXT

Extensibility New Features 3-18

Benefits of Table Functions

• Used as virtual tables in the FROM clause• Improves performance, because they:

– Allow results to be displayed as soon as they are produced

– Eliminate the need to buffer the produced rows which reduces execution time

– Eliminate the need for staging tables in data warehousing applications

– Can be performed in parallel• Parallel execution capability speeds up the

Extraction-Transformation-Load (ETL) process in data warehousing applications

Page 61: 9ib_EXT

Extensibility New Features 3-19

Implementation of Table Functions

• Table functions can be implemented in – PL/SQL table function– Oracle Data Cartridge Interface(ODCI)

– Implemented with a user-defined type– Can be implemented in any support

internal or external language• This lesson includes the ODCI implementation• For the PL/SQL implementation, see the lesson

Enhancement to PL/SQL in the course SQL & PL/SQL Enhancements

Implementation of Table FunctionsTable functions can be implemented in

• PL/SQL: A single function includes a special instruction to pipeline results out of the function returning the whole collection. For more information on implementing table functions as PL/SQL, see the Enhancements to PL/SQL lesson in Oracle9i new features course SQL & PL/SQL Enhancements.

• Oracle Data Cartridge Interface (ODCI):– Uses a user defined type that implements a predefined interface consisting of start, fetch

and close operations. The type is associated with the table function when the table function is created. During query execution the fetch method is invoked repeatedly to iteratively retrieve the results.

– The table function can be implemented in any supported internal or external language, such as PL/SQL, C/C++, Java

Page 62: 9ib_EXT

Extensibility New Features 3-20

ODCITable Interface Method InvocationFor example, as the function is used in the FROM clause, the methods in the interface are invoked using the following logic:

• ODCITableStart is invoked when the function is first called• ODCITableFetch is invoked every time Oracle needs to fetch another row from the

virtual table represented by the function• ODCITableClose is invoked after the last fetch

ODCITable Interface

• Is used to implement pipelined table functions• Consists of a set of routines whose signatures are

specified by Oracle • Includes the following methods:

– ODCITableStart initializes the scan context– ODCITableFetch produces a subset of rows in the

result collection– ODCITableClose cleans up after the last fetch

• Is implemented by the developer by:1. Creating the object type specification2. Creating the object type body3. Creating the function

Page 63: 9ib_EXT

Extensibility New Features 3-21

Example ImplementationThe example on the following slides converts the StockTable into a different format. StockTableincludes the stock's ticker symbol, opening price, and closing price. For example, a row might contain the values: 'ORCL', 41, 42. However, there is a requirement to process the stocks using a format of ticker symbol, price type, and closing price. The price type is:

• O for an opening price• C for a closing price

The row 'ORCL', 41, 42 would be converted into two rows:ORCL, O, 41ORCL, C, 42

The objects created below are used in the example.TickerType Object

The TickerType object is the format of the rows returned from ODCITableFetch method. It returns two rows for each input row.

CREATE TYPE TickerType AS OBJECT (Ticker VARCHAR2(4),PriceType VARCHAR2(1),Price NUMBER );

/

ODCITable Interface Example

• The table function in the example:– Selects rows from the StockTable table

– Converts a single row into two rows• The example includes these objects:

– TickerType is the new row format– TickerTypeSet is a set of the new rows– StockTable is the table being processed– InputCurType is a reference cursor for

StockTable

Page 64: 9ib_EXT

Extensibility New Features 3-22

TickerTypeSet ObjectThe TickerTypeSet object is used to group the TickerType objects.

CREATE TYPE TickerTypeSet AS TABLE OF TickerType;/

StockTable TableThe StockTable includes the stock's ticker symbol, opening price, and closing price. For example, a row might contain the values: ORCL, 41, 42.

CREATE TABLE StockTable (Ticker VARCHAR2(4),OpenPrice NUMBER,ClosePrice NUMBER );

Reference CursorThe reference cursor, InputCurType, is used as a cursor into StockTable.

CREATE TYPE InputCurType ISREF CURSORRETURN StockTable%ROWTYPE;

END;/

Page 65: 9ib_EXT

Extensibility New Features 3-23

ExampleThe code for creating the object type specification is presented in the slide, and the code for creating the object type body definition is presented below.These methods all return ODCIConst.Successon success or ODCIConst.Errorotherwise.CREATE TYPE BODY StockPivotImpl IS

STATIC FUNCTION ODCITableStart ( sctx OUT StockPivotImpl,p IN InputCurType )RETURN NUMBER

ISBEGINsctx.cur := p; -- save ref cursor in scan

contextRETURN ODCIConst.Success;

END;

Create the Object Type

CREATE TYPE StockPivotImpl AS OBJECT (cur InputCurType;STATIC FUNCTION ODCITableStart ( sctx OUT StockPivotImpl,p IN InputCurType )RETURN NUMBER,

MEMBER FUNCTION ODCITableFetch (self IN OUT StockPivotImpl,outrows OUT TickerTypeSet )RETURN NUMBER,

MEMBER FUNCTION ODCITableClose (self IN StockPivotImpl )RETURN NUMBER

);

CREATE TYPE StockPivotImpl AS OBJECT (cur InputCurType;STATIC FUNCTION ODCITableStart ( sctx OUT StockPivotImpl,p IN InputCurType )RETURN NUMBER,

MEMBER FUNCTION ODCITableFetch (self IN OUT StockPivotImpl,outrows OUT TickerTypeSet )RETURN NUMBER,

MEMBER FUNCTION ODCITableClose (self IN StockPivotImpl )RETURN NUMBER

);

Page 66: 9ib_EXT

Extensibility New Features 3-24

Example (continued)MEMBER FUNCTION ODCITableFetch (self IN OUT StockPivotImpl,outrows OUT TickerTypeSet )RETURN NUMBER

ISin_rec StockTable%ROWTYPE;idx INTEGER := 1;

BEGINoutrows.extend(100); -- return 100 rows at a timeWHILE (idx <= 100) LOOPFETCH self.cur INTO in_rec;-- Create the first output rowoutrows(idx).ticker := in_rec.Ticker;outrows(idx).PriceType := "O";outrows(idx).price := in_rec.OpenPrice;-- Create the second output rowidx := idx + 1;outrows(idx).ticker := in_rec.Ticker;outrows(idx).PriceType := "C";outrows(idx).price := in_rec.ClosePrice;idx := idx + 1;

END LOOP;RETURN ODCIConst.Success;

END;

MEMBER FUNCTION ODCITableClose (self IN StockPivotImpl )RETURN NUMBER

ISBEGIN -- No action required

RETURN ODCIConst.Success;END;

END;/

Page 67: 9ib_EXT

Extensibility New Features 3-25

Creating Table Functions

• Create the Table Function

CREATE FUNCTION StockPivot (p InputCurType )RETURN TickerTypeSetPIPELINED USING StockPivotImpl;

CREATE FUNCTION StockPivot (p InputCurType )RETURN TickerTypeSetPIPELINED USING StockPivotImpl;

SELECT stk.Ticker, stk.PriceFROM TABLE ( StockPivot (

CURSOR (SELECT * FROM StockTable) ) ) stk

WHERE stk.PriceType='C';

SELECT stk.Ticker, stk.PriceFROM TABLE ( StockPivot (

CURSOR (SELECT * FROM StockTable) ) ) stk

WHERE stk.PriceType='C';

• Use the table function to return only closing prices

Page 68: 9ib_EXT

Extensibility New Features 3-26

Summary

In this lesson, you should have learned about:• User-defined Aggregates• Table functions