Sie sind auf Seite 1von 68

New Oracle9i Features for Extensible

Indexing and Extensible Optimizer

Extensibility New Features 1-1


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

Extensibility New Features 1-2


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 Indexes


In 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 Index
Local 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.
INDEXTYPE
Identifies the set of operators that can be evaluated using a domain index that is specified
using the index type.
Domain Index
The 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.
Usage
DBAs 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.

Extensibility New Features 1-3


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 Tables


Most 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.

Extensibility New Features 1-4


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 Indexes


An 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 DELETE
ALTER INDEXTYPE causes these changes take effect. Use the RANGE PARTITIONED clause
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.

Extensibility New Features 1-5


INDEXTYPE: Enhance Global DDL Routines

DDL commands and their associated OCI routines:

SQL DDL ODCIIndex Routine


CREATE INDEX ODCIIndexCreate()
ALTER TABLE ADD PARTITION
DROP INDEX ODCIIndexDrop()
ALTER TABLE DROP PARTITION
ALTER INDEX ODCIIndexAlter()
ALTER INDEX MODIFY PARTITION
TRUNCATE TABLE ODCIIndexTruncate()
ALTER TABLE TRUNCATE PARTITION

DDL Statements on Domain Indexes


Update 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

Extensibility New Features 1-6


INDEXTYPE: Create Partition DDL Routines

DDL commands and their associated OCI routines for


partition level operations:
SQL DDL ODCIIndex Routine
MERGE PARTITION ODCIIndexMergePartition()
SPLIT PARTITION ODCIIndexSplitPartition()
EXCHANGE PARTITION ODCIIndexExchangePartition()

DDL Statements on Domain Indexes


Create the routines on the slide to allow DDL statements on local domain indexes.

Extensibility New Features 1-7


INDEXTYPE: Enhance Global DML Routines

DML commands and their associated OCI routines:

Operation ODCIIndex Routine Invoked


INSERT ODCIIndexInsert()
DELETE ODCIIndexDelete()
UPDATE ODCIIndexUpdate()
SELECT ODCIIndexStart()
ODCIIndexFetch()
ODCIIndexClose()

DML Statements on Local Domain Indexes


Update the routines on the slide to allow DML statements on local domain indexes.

Extensibility New Features 1-8


CREATE and ALTER INDEXTYPE

• Create a new INDEXTYPE for local domain index:


CREATE INDEXTYPE spatial_index
FOR sdo_relate (
sdo_geometry, sdo_geometry, VARCHAR2 )
USING spatialimpltype
WITH LOCAL RANGE PARTITION;
• Alter existing INDEXTYPE for local domain index :
ALTER INDEXTYPE spatial_index
FOR sdo_relate (
sdo_geometry, sdo_geometry, VARCHAR2 )
USING spatialimpltype
WITH LOCAL RANGE PARTITION;

Examples
In both examples, the SPATIAL_INDEX INDEXTYPEis used. This INDEXTYPE
has the following properties:
• Supports the SDO_RELATE operator
• Indexes objects of type SDO_GEOMETRY
• Is implemented using the SPATIALTIMPLTYPE
CREATE INDEXTYPE
The 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 INDEXTYPE
The ALTER INDEXTYPE command alters an existing INDEXTYPE, SPATIAL_INDEX, to
specify that it now also has support for local domain indexes on range partitioned tables.

Extensibility New Features 1-9


Creating a Local Domain Index

CREATE INDEX sdo_index ON t1(c1)


INDEXTYPE IS spatial_index
LOCAL (
PARTITION p1
PARAMETERS('TABLESPACE sdo1'),
PARTITION p2
PARAMETERS('TABLESPACE sdo2'))
PARAMETERS('PCTFREE 10');

Create Local Domain Index Example


The 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 INDEXTYPE SPATIAL_INDEX has already been created or altered to
specify support for local domain indexes on range-partitioned tables.

Extensibility New Features 1-10


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 Changes
Oracle9i 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.

Extensibility New Features 1-11


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 Index


A 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, Oracle9i
allows users to combine the richness of these two schemes and build function-based domain
indexes.
Cartridge developers or users who build new index types may 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.
Example
In 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_INDEX INDEXTYPE.
Extensibility New Features 1-12
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 Types


In 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.
Example
The 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.

Extensibility New Features 1-13


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 IOTs
For 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 VARCHAR2
column 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.
Example
The 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_INDEX were 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.

Extensibility New Features 1-14


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.

Extensibility New Features 1-15


Creating and Accessing Dynamic Data

Extensibility New Features 2-1


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

Extensibility New Features 2-2


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 TYPE SQL 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.
Extensibility New Features 2-3
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 Benefits


Type 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.

Extensibility New Features 2-4


Installation

• Includes the opaque types:


• SYS.AnyType
• SYS.AnyData
• SYS.AnyDataSet

Extensibility New Features 2-5


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 API
The 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 OCIAnyData
and OCIAnyDataSet.
SQL API
The 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.

Extensibility New Features 2-6


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_TYPES
The package DBMS_TYPES contains constants that used to define the type of data being accessed
when using the SYS.AnyType, SYS.AnyData, or SYS.AnyDatSet APIs. It also contains
exceptions that are raised when the data type enumerator is invalid.
Displaying DBMS_TYPES Type Codes
To see a complete list the codes in DBMS_TYPES in SQL*Plus, enter the command:
DESC SYS.DBMS_TYPES
Package 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;

Extensibility New Features 2-7


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;

Extensibility New Features 2-8


APIs: SYS.AnyType

• The SYS.AnyType API defines dynamic types


• It includes the following program units:
BeginCreate() creates a new type of AnyType
SetInfo() sets information for transient types
AddAttr() adds an attribute to an AnyType
EndCreate() ends creation of a transient AnyType
GetPersistent() returns a CREATE TYPE type
GetInfo() gets type information for the AnyType
GetAttrElemInfo() gets type attribute information

SYS.AnyType Program Units


BeginCreate() creates a new instance of AnyType which 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_OBJECT or gets the type information for a collection’s element type if the self
parameter is of a collection type.

Extensibility New Features 2-9


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 Example
SQL> CREATE PROCEDURE build_anytype_wh (
2 p_any_type IN OUT sys.anytype )
3 AS
4 /* AnyType properties
*/
5 BEGIN
6 sys.AnyType.BeginCreate
7 (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 );

Extensibility New Features 2-10


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 AS
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_aname VARCHAR2(40); /* Attribute name */
13 v_attr_type PLS_INTEGER; /* Attr. object code */
14 BEGIN

Extensibility New Features 2-11


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> DECLARE
2 v_any_type sys.AnyType; /* AnyType variable */
3 BEGIN
4 /* 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 /

Extensibility New Features 2-12


PL/SQL Example (continued)
The anonymous PL/SQL block produces the following output:
Properties for the 1st attribute
type code: 2
aname: warehouse_id
prec: 3
scale: 0
len:
csid:
csfrm:
.
Properties for the 2nd attribute
type code: 9
aname: warehouse_name
prec:
scale:
len: 35
csid: 0
csfrm: 1
.
Properties for the 3rd attribute
type code: 2
aname: location_id
prec: 4
scale: 0
len:
csid:
csfrm:

PL/SQL procedure successfully completed.

SQL>

Extensibility New Features 2-13


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 Instance


There 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

Extensibility New Features 2-14


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 Units


Convert*() 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 collection
EndCreate() ends Creation of a AnyData. Other creation functions cannot be called after this
call.
Extensibility New Features 2-15
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 type
GetTypeName() 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 AnyData
piece 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 called
The Get*() function returns DBMS_TYPES.SUCCESS or 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_DATA signifies the end of the collection when all elements have been
accessed.

Extensibility New Features 2-16


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 Example


SQL> CREATE TABLE any_data_table (
2 any_data SYS.AnyData );

Table created.

SQL> CREATE TYPE warehouse_typ AS OBJECT


2 ( 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.
Extensibility New Features 2-17
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> DECLARE
2 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
Extensibility New Features 2-18
21 CURSOR any_data_c IS
SQL and PL/SQL Example (continued)
27 LOOP
28 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 THEN
36 /* 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) THEN
41 /* 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 = USER
54 AND (v_type_name = 'WAREHOUSE_TYP') THEN
55 /* 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);

Extensibility New Features 2-19


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_id
68 || ' 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 EXCEPTION
83 WHEN DBMS_TYPES.TYPE_MISMATCH THEN
84 DBMS_OUTPUT.PUT_LINE('Invalid data type');
85 END;
86 /

Extensibility New Features 2-20


SQL and PL/SQL Example (continued)
The anonymous PL/SQL block produces the following output:
The value for the number datatype is: 5
1st attribute
type code: 2
aname: WAREHOUSE_ID
prec: 3
scale: 0
len:
csid:
csfrm:
.
2nd attribute
type code: 9
aname: WAREHOUSE_NAME
prec:
scale:
len: 35
csid: 31
csfrm: 1
.
3rd attribute
type code: 2
aname: LOCATION_ID
prec: 4
scale: 0
len:
csid:
csfrm:
Warehouse: 1 named Southlake, Texas

PL/SQL procedure successfully completed.

SQL>

Extensibility New Features 2-21


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 Instances


The 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.

Extensibility New Features 2-22


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 Units


BeginCreate() creates a new AnyDataSet which 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 collection
EndCreate() 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.
Extensibility New Features 2-23
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, self
is the AnyDataSet being accessed. The value returned from the function indicates whether the
get was successful:
• DBMS_TYPES.SUCCESSindicates that the AnyData instance was available
• DBMS_TYPES.NO_DATAsignifies the end of the AnyDataSet, that is, all instances
have been accessed
Get*() 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.

Extensibility New Features 2-24


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 Example
SQL> 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.GetPersistent
14 (user, 'WAREHOUSE_TYP');
15
16 /* Start building the AnyDataSet */

Extensibility New Features 2-25


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_id
40 || ' 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_id
47 || ' named ' || v_warehouse.warehouse_name );
48 END;
49 /
Warehouse: 1 named Southlake, Texas
Warehouse: 2 named Las Cruces, NM

PL/SQL procedure successfully completed.

SQL>
Extensibility New Features 2-26
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

Extensibility New Features 2-27


Other Extensibility Enhancements

Extensibility New Features 3-1


Objectives

After completing this lesson you should be able to:


• User-defined Aggregates
• Table functions

Extensibility New Features 3-2


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

Extensibility New Features 3-3


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 functions
SELECT
SELECT sum_sal_udag(employee_object)
sum_sal_udag(employee_object)
FROM
FROM employees
employees
GROUP
GROUP BY
BY department_id;
department_id;

User Defined Group Functions


Oracle 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 SpatialUnion aggregate 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.

Extensibility New Features 3-4


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

Group Function Logic


An 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 operations
1. 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 aggregation
3. Terminate: Complete any additional computation required on the aggregated values and
return the result
The 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

Extensibility New Features 3-5


Aggregation Example
For 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, inputval
runningSum := 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.

Extensibility New Features 3-6


Aggregation Implementation

• UDAGs are implemented through the


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

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.Success on success or ODCIConst.Error on 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.
ODCIAggregateIterate
This 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.
ODCIAggregateMerge
This 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.
ODCIAggregateterminate
This 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.

Extensibility New Features 3-7


Creating the UDAG Function

• To create a UDAG function, the developer:


1. Creates the object type specification for the four
primitives
2. Creates the type body for the four primitives
3. Creates the UDAG function
4. 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

Extensibility New Features 3-8


Create the Object Type Specification

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

STATIC
STATIC FUNCTION
FUNCTION ODCIAggregateInitialize
ODCIAggregateInitialize
(self_ctx
(self_ctx OUT
OUT SecondMaxImpl)
SecondMaxImpl)
RETURN
RETURN NUMBER,
NUMBER,
.. .. ..
MEMBER
MEMBER FUNCTION
FUNCTION ODCIAggregateIterate.
ODCIAggregateIterate. .. ..
MEMBER
MEMBER FUNCTION
FUNCTION ODCIAggregateMerge.
ODCIAggregateMerge. .. ..
MEMBER
MEMBER FUNCTION
FUNCTION ODCIAggregateTerminate.
ODCIAggregateTerminate. .. ..
);
);
//

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

CREATE TYPE SecondMaxImpl AS OBJECT (


Max NUMBER, --highest value
Secmax 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,

Extensibility New Features 3-9


Example (continued)
MEMBER FUNCTION ODCIAggregateMerge (
self IN OUT SecondMaxImpl,
ctx2 IN
SecondMaxImpl )
RETURN NUMBER,

MEMBER FUNCTION ODCIAggregateTerminate (


self IN
SecondMaxImpl,
result OUT
NUMBER,
flags IN
NUMBER )
RETURN NUMBER
);
/

Extensibility New Features 3-10


Create the Object Type Body

CREATE
CREATE OR
OR REPLACE
REPLACE TYPE
TYPE BODY
BODY SecondMaxImpl
SecondMaxImpl IS
IS
STATIC
STATIC FUNCTION
FUNCTION ODCIAggregateinitialize
ODCIAggregateinitialize ((
...
...
MEMBER
MEMBER FUNCTION
FUNCTION ODCIAggregateiterate
ODCIAggregateiterate ((
...
...
MEMBER
MEMBER FUNCTION
FUNCTION ODCIAggregateterminate
ODCIAggregateterminate ((
...
...
MEMBER
MEMBER FUNCTION
FUNCTION ODCIAggregatemerge
ODCIAggregatemerge ((
...
...
END;
END;

Example
All 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
BEGIN
self_ctx := SecondMaxImpl(0, 0);
RETURN ODCIConst.Success;
END;

MEMBER FUNCTION ODCIAggregateIterate (


self IN OUT SecondMaxImpl,
value IN
NUMBER )
RETURN NUMBER
IS
BEGIN

Extensibility New Features 3-11


Example (continued)
IF value > self.max THEN
self.secmax := self.max;
self.max := value;
ELSIF value > self.secmax THEN
self.secmax := value;
END IF;
RETURN ODCIConst.Success;
END;

MEMBER FUNCTION ODCIAggregateMerge (


self IN OUT SecondMaxImpl,
ctx2 IN
SecondMaxImpl )
RETURN NUMBER
IS
BEGIN
IF ctx2.max > self.max THEN
IF 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 THEN
self.secmax := ctx2.max;
END IF;
RETURN ODCIConst.Success;
END;

MEMBER FUNCTION ODCIAggregateTerminate (


self IN
SecondMaxImpl,
result OUT
NUMBER,
flags IN
NUMBER )
RETURN NUMBER
IS
BEGIN
result := self.secmax;
RETURN ODCIConst.Success;
END;

END;
/

Extensibility New Features 3-12


Create the UDAG Function

• Create the UDAG function


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

• Guidelines:
• Match the RETURN data type with the data
type in the ODCIAggregateTerminate
method
• The USING clause maps this function to its
ODCIAggregate interface

Guidelines
Because 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.

Extensibility New Features 3-13


Use the UDAG Function

SQL>
SQL> SELECT
SELECT department_id,
department_id,
22 SecondMax(salary)
SecondMax(salary) AS
AS sal2
sal2
33 FROM
FROM employees
employees
44 GROUP
GROUP BY
BY department_id
department_id
55 HAVING
HAVING SecondMax(salary)
SecondMax(salary) >> 2000;
2000;

DEPTNO
DEPTNO SAL2
SAL2
----------
---------- ----------
----------
10
10 2450
2450
20
20 2975
2975

Extensibility New Features 3-14


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

Extensibility New Features 3-15 4


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 Functions


Table 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.

Extensibility New Features 3-16


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 Functions


Table 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.

Extensibility New Features 3-17


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

Extensibility New Features 3-18


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 Functions


Table 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

Extensibility New Features 3-19


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 specification
2. Creating the object type body
3. Creating the function

ODCITable Interface Method Invocation


For 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

Extensibility New Features 3-20


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

Example Implementation
The example on the following slides converts the StockTable into a different format. StockTable
includes 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, 41
ORCL, 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 );
/

Extensibility New Features 3-21


TickerTypeSet Object
The TickerTypeSet object is used to group the TickerType objects.
CREATE TYPE TickerTypeSet AS TABLE OF TickerType;
/
StockTable Table
The 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 Cursor
The reference cursor, InputCurType, is used as a cursor into StockTable.
CREATE TYPE InputCurType IS
REF CURSOR
RETURN StockTable%ROWTYPE;
END;
/

Extensibility New Features 3-22


Create the Object Type
CREATE
CREATE TYPE
TYPE StockPivotImpl
StockPivotImpl AS
AS OBJECT
OBJECT ((
cur
cur InputCurType;
InputCurType;
STATIC
STATIC FUNCTION
FUNCTION ODCITableStart
ODCITableStart ((
sctx
sctx OUT
OUT StockPivotImpl,
StockPivotImpl,
pp IN
IN InputCurType
InputCurType ))
RETURN
RETURN NUMBER,
NUMBER,
MEMBER
MEMBER FUNCTION
FUNCTION ODCITableFetch
ODCITableFetch ((
self
self IN
IN OUT
OUT StockPivotImpl,
StockPivotImpl,
outrows
outrows OUT
OUT TickerTypeSet
TickerTypeSet ))
RETURN
RETURN NUMBER,
NUMBER,
MEMBER
MEMBER FUNCTION
FUNCTION ODCITableClose
ODCITableClose ((
self
self IN
IN StockPivotImpl
StockPivotImpl ))
RETURN
RETURN NUMBER
NUMBER
);
);

Example
The 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.Success on success or ODCIConst.Error
otherwise.
CREATE TYPE BODY StockPivotImpl IS

STATIC FUNCTION ODCITableStart (


sctx OUT StockPivotImpl,
p IN InputCurType )
RETURN NUMBER
IS
BEGIN
sctx.cur := p; -- save ref cursor in scan
context
RETURN ODCIConst.Success;
END;

Extensibility New Features 3-23


Example (continued)
MEMBER FUNCTION ODCITableFetch (
self IN OUT StockPivotImpl,
outrows OUT TickerTypeSet )
RETURN NUMBER
IS
in_rec StockTable%ROWTYPE;
idx INTEGER := 1;
BEGIN
outrows.extend(100); -- return 100 rows at a time
WHILE (idx <= 100) LOOP
FETCH self.cur INTO in_rec;
-- Create the first output row
outrows(idx).ticker := in_rec.Ticker;
outrows(idx).PriceType := "O";
outrows(idx).price := in_rec.OpenPrice;
-- Create the second output row
idx := 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
IS
BEGIN -- No action required
RETURN ODCIConst.Success;
END;
END;
/

Extensibility New Features 3-24


Creating Table Functions
• Create the Table Function
CREATE
CREATE FUNCTION
FUNCTION StockPivot
StockPivot ((
pp InputCurType
InputCurType ))
RETURN
RETURN TickerTypeSet
TickerTypeSet
PIPELINED
PIPELINED USING
USING StockPivotImpl;
StockPivotImpl;
• Use the table function to return only closing prices
SELECT
SELECT stk.Ticker,
stk.Ticker, stk.Price
stk.Price
FROM
FROM TABLE
TABLE (( StockPivot
StockPivot ((
CURSOR
CURSOR ((
SELECT
SELECT ** FROM
FROM StockTable)
StockTable) )) )) stk
stk
WHERE
WHERE stk.PriceType='C';
stk.PriceType='C';

Extensibility New Features 3-25


Summary

In this lesson, you should have learned about:


• User-defined Aggregates
• Table functions

Extensibility New Features 3-26

Das könnte Ihnen auch gefallen