Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted1
New SQL & PL/SQL Capabilities
in
Oracle Database 12c
Thomas Kyte
http://asktom.oracle.com/
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted2
The following is intended to outline our general product
direction. It is intended for information purposes only, and
may not be incorporated into any contract. It is not a
commitment to deliver any material, code, or functionality,
and should not be relied upon in making purchasing
decisions. The development, release, and timing of any
features or functionality described for Oracle’s products
remains at the sole discretion of Oracle.
Small print
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted3
PL/SQL
 More Bind Types
– Booleans
– PL/SQL Records
– PL/SQL Collections
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted4
PL/SQL
c##tkyte%CDB1> CREATE OR REPLACE PROCEDURE p
(x BOOLEAN) AUTHID CURRENT_USER AS
2 BEGIN
3 IF x THEN
4 DBMS_OUTPUT.PUT_LINE('x is true');
5 END IF;
6 END;
7 /
Procedure created.
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted5
PL/SQL
ops$tkyte%ORA11GR2> DECLARE
2 dyn_stmt VARCHAR2(200);
3 b BOOLEAN := TRUE;
4 BEGIN
5 dyn_stmt := 'BEGIN p(:x); END;';
6 EXECUTE IMMEDIATE dyn_stmt USING b;
7 END;
8 /
EXECUTE IMMEDIATE dyn_stmt USING b;
*
ERROR at line 6:
ORA-06550: line 6, column 36:
PLS-00457: expressions have to be of SQL types
ORA-06550: line 6, column 3:
PL/SQL: Statement ignored
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted6
PL/SQL
c##tkyte%CDB1> DECLARE
2 dyn_stmt VARCHAR2(200);
3 b BOOLEAN := TRUE;
4 BEGIN
5 dyn_stmt := 'BEGIN p(:x); END;';
6 EXECUTE IMMEDIATE dyn_stmt USING b;
7 END;
8 /
x is true
PL/SQL procedure successfully completed.
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted7
PL/SQL
 Query PL/SQL Table Type Directly
– No more need to create SQL Types
– Less namespace clutter
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted8
PL/SQL
c##tkyte%CDB1> create or replace package my_pkg
2 as
3 type my_collection is table of emp%rowtype;
4
5 procedure p;
6 end my_pkg;
7 /
Package created.
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted9
PL/SQL
c##tkyte%CDB1> create or replace package body my_pkg
2 as
3
4 procedure p
5 is
6 l_data my_collection;
7 begin
8 select * bulk collect into l_data from emp;
9
10 for x in (select * from TABLE(l_data))
11 loop
12 dbms_output.put_line( x.ename );
13 end loop;
14 end;
15
16 end my_pkg;
17 /
Package body created.
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted10
PL/SQL
ops$tkyte%ORA11GR2> show err
Errors for PACKAGE BODY MY_PKG:
LINE/COL ERROR
-------- -----------------------------------------------------------------
10/15 PL/SQL: SQL Statement ignored
10/29 PL/SQL: ORA-22905: cannot access rows from a non-nested table
item
10/35 PLS-00642: local collection types not allowed in SQL statements
12/9 PL/SQL: Statement ignored
12/31 PLS-00364: loop index variable 'X' use is invalid
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted11
PL/SQL
 Grant Roles to Code
– Especially useful for invokers rights routines
– Code will run with current set of privileges of the
Invoker plus that role(s)
– Role is only enabled during execution of that
procedure
– Also, INHERIT PRIVILEGES – new privilege
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted12
Granting a role to a PL/SQL unit
 Consider this best practice
• Give access to an application’s data only via PL/SQL
subprograms
• Reinforce this by having end-user sessions authorize
as a different database owner than the one that owns the
application’s artifacts
• Arrange this by using definer’s rights units in a single schema or
a couple of schemas. Then grant Execute on these to end-users
– but don’t grant privileges on the tables to end-users
 This means that each unit can access very many tables
because the owner of the units can
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted13
Granting a role to a PL/SQL unit
 12.1 lets us have a fine-grained scheme where each unit
with the same owner can have different privileges on the
owner’s tables
• The end-user is low-privileged, just as in the old scheme
• The units are invoker’s rights, so “as is” would not allow end-
users to access the data
• The privilege for each unit is elevated for exactly and only that
unit’s purpose by granting a role that has the appropriate
privileges to the unit. Such a role cannot be disabled.
• The unit’s owner must already have that same role (but it need
not be enabled)
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted14
Granting a role to a PL/SQL unit
 This scenario lets us illustrate the idea
• There are two users App and Client
• There are two tables App.t1 and App.t2
• There are two IR procedures App.Show_t1 and App.Show_t2 to
run select statements against the tables
• Client has Execute on App.Show_t1 and App.Show_t2
• App creates two roles r_Show_t1 and r_Show_t2
• App grants Select on App.t1 to r_Show_t1 – and similar for ~2
• App grants r_Show_t1 to App.Show_t1 – and similar for ~2
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted15
Granting a role to a PL/SQL unit
create procedure Show_t1 authid Current_User is
begin
for j in (select Fact from App.t1 order by 1) loop -- Notice the schema-qualification
...
end loop;
end Show_t1;
/
grant Execute on App.Show_t1 to Client
/
-- this has the side-effect of granting the role to App with Admin option
-- other non-schema object types like directories and editions behave the same
create role r_Show_t1
/
grant select on t1 to r_Show_t1
/
grant r_Show_t1 to procedure Show_t1
/
select Object_Name, Object_Type, Role
from User_Code_Role_Privs
/
....... ......... .........
SHOW_T1 PROCEDURE R_SHOW_T1
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted16
Granting a role to a PL/SQL unit
 When Client invokes App.Show_t1, then no matter what
careless mistakes the programmer of the procedure might
later make, its power is limited to just what the role confers.
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted17
PL/SQL
 White List
– ‘Accessible By’ clause
– Specifies a specific list of code that can invoke your
code
– Fine grained privilege to protect code
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted18
accessible by clause
package Helper authid Definer accessible by (Good_Guy, Bad_Guy)
is
procedure p;
end Helper;
package body Good_Guy is
procedure p is
begin
Helper.p();
...
end p;
end Good_Guy;
package body Bad_Guy is
procedure p is
begin
Helper.p();
...
end p;
end Bad_Guy;
PLS-00904: insufficient privilege to access object HELPER
_______
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted19
Even better
PL/SQL from SQL
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted20
Defining a PL/SQL function in the
with clause of a subquery
function Print(n in integer) return varchar2 authid Definer is
K constant number not null := 1024;
M constant number not null := K*K;
G constant number not null := M*K;
T constant number not null := G*K;
begin
return
case
when n <= K-1 then To_Char(n, '999999')||'byte'
when n/K <= K-1 then To_Char(n/K, '999999')||'K'
when n/M <= K-1 then To_Char(n/M, '999999')||'M'
when n/G <= K-1 then To_Char(n/G, '999999')||'G'
else To_Char(n/T, '999999')||'T'
end;
end Print;
 Use case: pretty-print an integer as a multiple of
an appropriate power of 1024: plain, K, M, B, or T
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted21
Use the PL/SQL function in SQL
on a table with three number columns
select PK,
Print(n1) "n1",
Print(n2) "n2",
Print(n3) "n3"
from t
1 1 K 1 G 566 G
2 1 K 157 M 416 G
3 2 K 1 G 971 G
4 578 byte 1 G 1 T
5 2 K 1 G 220 G
6 1 K 2 G 1 T
7 48 byte 1 G 2 T
8 992 byte 42 M 3 T
9 794 byte 2 G 1 T
10 2 K 302 M 672 G
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted22
Try it in pure SQL!
select
PK,
case
when n1 <= 1023 then To_Char(n1, '999999')||' byte'
when n1/1024 <= 1023 then To_Char(n1/1024, '999999')||' K'
when n1/1048576 <= 1023 then To_Char(n1/1048576, '999999')||' M'
when n1/1073741824 <= 1023 then To_Char(n1/1073741824, '999999')||' G'
else To_Char(n1/1099511627776, '999999')||' T'
end
"n1",
case
when n2 <= 1023 then To_Char(n2, '999999')||' byte'
when n2/1024 <= 1023 then To_Char(n2/1024, '999999')||' K'
when n2/1048576 <= 1023 then To_Char(n2/1048576, '999999')||' M'
when n2/1073741824 <= 1023 then To_Char(n2/1073741824, '999999')||' G'
else To_Char(n2/1099511627776, '999999')||' T'
end
"n2",
case
when n3 <= 1023 then To_Char(n3, '999999')||' byte'
when n3/1024 <= 1023 then To_Char(n3/1024, '999999')||' K'
when n3/1048576 <= 1023 then To_Char(n3/1048576, '999999')||' M'
when n3/1073741824 <= 1023 then To_Char(n3/1073741824, '999999')||' G'
else To_Char(n3/1099511627776, '999999')||' T'
end
"n3"
from t
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted23
Get the performance of SQL with the
clarity and reusability of PL/SQL
function Print(n in integer) return varchar2 authid Definer is
K constant number not null := 1024;
M constant number not null := K*K;
G constant number not null := M*K;
T constant number not null := G*K;
begin
return
case
when n <= K-1 then To_Char(n, '999999')||'byte'
when n/K <= K-1 then To_Char(n/K, '999999')||'K'
when n/M <= K-1 then To_Char(n/M, '999999')||'M'
when n/G <= K-1 then To_Char(n/G, '999999')||'G'
else To_Char(n/T, '999999')||'T'
end;
end Print;
pragma UDF;
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted24
Declare the PL/SQL function
in the subquery’s with clause
function Print(n in integer) return varchar2 is
K constant number not null := 1024;
M constant number not null := K*K;
G constant number not null := M*K;
T constant number not null := G*K;
begin
return
case
when n <= K-1 then To_Char(n, '999999')||' byte'
when n/K <= K-1 then To_Char(n/K, '999999')||' K'
when n/M <= K-1 then To_Char(n/M, '999999')||' M'
when n/G <= K-1 then To_Char(n/G, '999999')||' G'
else To_Char(n/T, '999999')||' T'
end;
end Print;
select PK,
Print(n1) "n1",
Print(n2) "n2",
Print(n3) "n3"
from t
with
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted25
Performance comparison
 Pure SQL
is fastest
 Schema-level function with pragma UDF
is close
 Function in the with clause
is similar
 Pre-12.1 ordinary schema-level function
is very much the slowest
1.0 – the baseline
3.8x
3.9x
5.0x
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted26
Better client
binding
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted27
Improved support for binding PL/SQL types in JDBC
 Before 12.1
• Generate a schema level object type to mirror the
structure of the non-SQL package type
• Populate and bind the object into a custom PL/SQL
wrapper around the desired PL/SQL subprogram
• Convert the object to the package type in the wrapper
and call the PL/SQL subprogram with the package type
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted28
Improved support for binding PL/SQL types in JDBC
 New in 12.1
• PL/SQL package types supported as binds in JDBC
• Can now execute PL/SQL subprograms with non-SQL
types
• Supported types include records, index-by tables,
nested tables and varrays
• Table%rowtype, view%rowtype and package defined
cursor%rowtype also supported. They’re technically
record types
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted29
Example1: Bind a single record from Java
into a PL/SQL procedure, modify it,
and bind it back out to Java
package Emp_Info is
type employee is record(First_Name Employees.First_Name%type,
Last_Name Employees.Last_Name%type,
Employee_Id Employees.Employee_Id%type,
Is_CEO boolean);
procedure Get_Emp_Name(Emp_p in out Employee);
end;
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted30
Example1:
 Use the EmpinfoEmployee class, generated by
JPub, to implement the Employee formal parameter
{ …
EmpinfoEmployee Employee = new EmpinfoEmployee();
Employee.setEmployeeId(new java.math.BigDecimal(100)); // Use Employee ID 100
// Call Get_Emp_Name() with the Employee object
OracleCallableStatement cstmt =
(OracleCallableStatement)conn.prepareCall("call EmpInfo.Get_Emp_Name(?)");
cstmt.setObject(1, Employee, OracleTypes.STRUCT);
// Use "PACKAGE.TYPE NAME" as the type name
cstmt.registerOutParameter(1, OracleTypes.STRUCT, "EMPINFO.EMPLOYEE");
cstmt.execute();
// Get and print the contents of the Employee object
EmpinfoEmployee oraData =
(EmpinfoEmployee)cstmt.getORAData(1, EmpinfoEmployee.getORADataFactory());
System.out.println("Employee: " + oraData.getFirstName() + " " + oraData.getLastName());
System.out.println("Is the CEO? " + oraData.getIsceo());
}
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted31
Example 2: populate a collection of table%rowtype
using a bulk collect statement, and pass the collection
as an out parameter back to the caller
package EmpRow is
type Table_of_Emp is table of Employees%Rowtype;
procedure GetEmps(Out_Rows out Table_of_Emp);
end;
package Body EmpRow is
procedure GetEmps(Out_Rows out Table_of_Emp) is
begin
select *
bulk collect into Out_Rows
from Employees;
end;
end;
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted32
Example 2:
{ …
// Call GetEmps() to get the ARRAY of table row data objects
CallableStatement cstmt = conn.prepareCall("call EmpRow.GetEmps(?)");
// Use "PACKAGE.COLLECTION NAME" as the type name
cstmt.registerOutParameter(1, OracleTypes.ARRAY, "EMPROW.TABLE_OF_EMP");
cstmt.execute();
// Print the Employee Table rows
Array a = cstmt.getArray(1);
String s = Debug.printArray ((ARRAY)a, "",
((ARRAY)a).getSQLTypeName () +"( ", conn);
System.out.println(s);
}
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted33
Improved
Introspection
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted34
Improved call stack introspection
 Before 12.1, you used three functions in the
DBMS_Utility package
• Format_Call_Stack()
• Format_Error_Stack()
• Format_Error_Backtrace()
 New in 12.1
• The package UTL_Call_Stack solves the
same problem properly
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted35
Code to be introspected
package body Pkg is
procedure p is
procedure q is
procedure r is
procedure p is
begin
Print_Call_Stack();
end p;
begin
p();
end r;
begin
r();
end q;
begin
q();
end p;
end Pkg;
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted36
Pre 12.1 Print_Call_Stack()
procedure Print_Call_Stack authid Definer is
Depth pls_integer := UTL_Call_Stack.Dynamic_Depth();
begin
DBMS_Output.Put_Line(DBMS_Utility.Format_Call_Stack());
end;
----- PL/SQL Call Stack -----
object line object
handle number name
0x631f6e88 12 procedure USR.PRINT_CALL_STACK
0x68587700 7 package body USR.PKG
0x68587700 10 package body USR.PKG
0x68587700 13 package body USR.PKG
0x68587700 16 package body USR.PKG
0x69253ca8 1 anonymous block
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted37
12.1 Print_Call_Stack()
procedure Print_Call_Stack authid Definer is
Depth pls_integer := UTL_Call_Stack.Dynamic_Depth();
begin
for j in reverse 2..Depth loop
DBMS_Output.Put_Line(
(j - 1)||
To_Char(UTL_Call_Stack.Unit_Line(j), '99')||
UTL_Call_Stack.Concatenate_Subprogram(UTL_Call_Stack.Subprogram(j)));
end loop;
end;
5 1 __anonymous_block
4 16 PKG.P
3 13 PKG.P.Q
2 10 PKG.P.Q.R
1 7 PKG.P.Q.R.P
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted38
Improved call stack introspection
 Symmetrical subprograms for error stack and
backtrace
 Plus
• Owner(Depth)
• Current_Edition(Depth)
• Lexical_Depth(Depth)
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted39
Agenda
 Improved client <> PL/SQL <> SQL
interoperability
 A new security capability
 Improved programmer usability
 Miscellaneous
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted40
Invisible Columns
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted41
Invisible Columns
ops$tkyte%ORA12CR1> create table t
2 ( x int,
3 y int
4 )
5 /
Table created.
ops$tkyte%ORA12CR1> insert into t values ( 1, 2 );
1 row created.
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted42
Invisible Columns
ops$tkyte%ORA12CR1> alter table t add
( z int INVISIBLE );
Table altered.
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted43
Invisible Columns
ops$tkyte%ORA12CR1> desc t
Name Null? Type
----------------- -------- ------------
X NUMBER(38)
Y NUMBER(38)
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted44
Invisible Columns
ops$tkyte%ORA12CR1> insert into t values ( 3, 4 );
1 row created.
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted45
Invisible Columns
ops$tkyte%ORA12CR1> select * from t;
X Y
---------- ----------
1 2
3 4
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted46
Invisible Columns
ops$tkyte%ORA12CR1> insert into t (x,y,z)
values ( 5,6,7 );
1 row created.
ops$tkyte%ORA12CR1> select x, y, z from t;
X Y Z
---------- ---------- ----------
1 2
3 4
5 6 7
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted47
Invisible Columns
ops$tkyte%ORA12CR1> alter table t modify z visible;
Table altered.
ops$tkyte%ORA12CR1> select * from t;
X Y Z
---------- ---------- ----------
1 2
3 4
5 6 7
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted48
Multiple Same
Column Indexes
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted49
Indexing
ops$tkyte%ORA11GR2> create table t ( x int, y int, z int );
Table created.
ops$tkyte%ORA11GR2> create index t_idx on t(x,y);
Index created.
ops$tkyte%ORA11GR2> create bitmap index t_idx2 on t(x,y);
create bitmap index t_idx2 on t(x,y)
*
ERROR at line 1:
ORA-01408: such column list already indexed
ops$tkyte%ORA11GR2> create bitmap index t_idx2 on t(x,y) invisible;
create bitmap index t_idx2 on t(x,y) invisible
*
ERROR at line 1:
ORA-01408: such column list already indexed
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted50
Indexing
ops$tkyte%ORA12CR1> create table t ( x int, y int, z int );
Table created.
ops$tkyte%ORA12CR1> create index t_idx on t(x,y);
Index created.
ops$tkyte%ORA12CR1> create bitmap index t_idx2 on t(x,y) invisible;
Index created.
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted51
Indexing
ops$tkyte%ORA12CR1> alter session set
optimizer_use_invisible_indexes=true;
Session altered.
ops$tkyte%ORA12CR1> exec dbms_stats.set_table_stats( user, 'T',
numrows => 1000000, numblks => 100000 );
PL/SQL procedure successfully completed.
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted52
Indexing
ops$tkyte%ORA12CR1> set autotrace traceonly explain
ops$tkyte%ORA12CR1> select count(*) from t;
Execution Plan
----------------------------------------------------------
Plan hash value: 1106681275
---------------------------------------------------------------------
| Id | Operation | Name | Rows | Cost (%CPU)|
---------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 0 (0)|
| 1 | SORT AGGREGATE | | 1 | |
| 2 | BITMAP CONVERSION COUNT | | 1000K| |
| 3 | BITMAP INDEX FAST FULL SCAN| T_IDX2 | | |
---------------------------------------------------------------------
ops$tkyte%ORA12CR1> set autotrace off
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted53
Temporal Validity
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted54
Temporal Validity
ops$tkyte%ORA12CR1> create table addresses
2 ( empno number,
3 addr_data varchar2(30),
4 start_date date,
5 end_date date,
6 period for valid(start_date,end_date)
7 )
8 /
Table created.
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted55
Temporal Validity
ops$tkyte%ORA12CR1> insert into addresses (empno, addr_data, start_date, end_date )
2 values ( 1234, '123 Main Street', trunc(sysdate-5), trunc(sysdate-2) );
1 row created.
ops$tkyte%ORA12CR1> insert into addresses (empno, addr_data, start_date, end_date )
2 values ( 1234, '456 Fleet Street', trunc(sysdate-1), trunc(sysdate+1) );
1 row created.
ops$tkyte%ORA12CR1> insert into addresses (empno, addr_data, start_date, end_date )
2 values ( 1234, '789 1st Ave', trunc(sysdate+2), null );
1 row created.
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted56
Temporal Validity
ops$tkyte%ORA12CR1> select * from addresses;
EMPNO ADDR_DATA START_DAT END_DATE
---------- ------------------------------ --------- ---------
1234 123 Main Street 12-MAY-13 15-MAY-13
1234 456 Fleet Street 16-MAY-13 18-MAY-13
1234 789 1st Ave 19-MAY-13
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted57
Temporal Validity
ops$tkyte%ORA12CR1> select * from addresses as of period for valid sysdate-3;
EMPNO ADDR_DATA START_DAT END_DATE
---------- ------------------------------ --------- ---------
1234 123 Main Street 12-MAY-13 15-MAY-13
ops$tkyte%ORA12CR1> select * from addresses as of period for valid sysdate;
EMPNO ADDR_DATA START_DAT END_DATE
---------- ------------------------------ --------- ---------
1234 456 Fleet Street 16-MAY-13 18-MAY-13
ops$tkyte%ORA12CR1> select * from addresses as of period for valid sysdate+3;
EMPNO ADDR_DATA START_DAT END_DATE
---------- ------------------------------ --------- ---------
1234 789 1st Ave 19-MAY-13
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted58
SQL Text
Expansion
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted59
SQL Text Expansion
ops$tkyte%ORA12CR1> variable x clob
ops$tkyte%ORA12CR1> begin
2 dbms_utility.expand_sql_text
3 ( input_sql_text => 'select * from all_users',
4 output_sql_text => :x );
5 end;
6 /
PL/SQL procedure successfully completed.
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted60
SQL Text Expansion
ops$tkyte%ORA12CR1> print x
X
--------------------------------------------------------------------------------
SELECT "A1"."USERNAME" "USERNAME","A1"."USER_ID" "USER_ID","A1"."CREATED" "CREAT
ED","A1"."COMMON" "COMMON" FROM (SELECT "A4"."NAME" "USERNAME","A4"."USER#" "US
ER_ID","A4"."CTIME" "CREATED",DECODE(BITAND("A4"."SPARE1",128),128,'YES','NO') "
COMMON" FROM "SYS"."USER$" "A4","SYS"."TS$" "A3","SYS"."TS$" "A2" WHERE "A4"."DA
TATS#"="A3"."TS#" AND "A4"."TEMPTS#"="A2"."TS#" AND "A4"."TYPE#"=1) "A1"
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted61
SQL Text Expansion
ops$tkyte%ORA12CR1> create or replace
2 function my_security_function( p_schema in varchar2,
3 p_object in varchar2 )
4 return varchar2
5 as
6 begin
7 return 'owner = USER';
8 end;
9 /
Function created.
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted62
SQL Text Expansion
ops$tkyte%ORA12CR1> create table my_table
2 ( data varchar2(30),
3 OWNER varchar2(30) default USER
4 )
5 /
Table created.
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted63
SQL Text Expansion
ops$tkyte%ORA12CR1> begin
2 dbms_rls.add_policy
3 ( object_schema => user,
4 object_name => 'MY_TABLE',
5 policy_name => 'MY_POLICY',
6 function_schema => user,
7 policy_function => 'My_Security_Function',
8 statement_types => 'select, insert, update, delete' ,
9 update_check => TRUE );
10 end;
11 /
PL/SQL procedure successfully completed.
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted64
SQL Text Expansion
ops$tkyte%ORA12CR1> begin
2 dbms_utility.expand_sql_text
3 ( input_sql_text => 'select * from my_table',
4 output_sql_text => :x );
5 end;
6 /
PL/SQL procedure successfully completed.
ops$tkyte%ORA12CR1> print x
X
--------------------------------------------------------------------------------
SELECT "A1"."DATA" "DATA","A1"."OWNER" "OWNER" FROM (SELECT "A2"."DATA" "DATA",
"A2"."OWNER" "OWNER" FROM "OPS$TKYTE"."MY_TABLE" "A2" WHERE "A2"."OWNER"=USER@!)
"A1"
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted65
Etc…
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted66
Other enhancements brought by 12.1
 Improved Defaults
 Row Limiting Clause
 Row Pattern Matching
 Partitioning Improvements
 Temporary Undo
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted67
Other enhancements brought by 12.1
 You can now result-cache an invoker’s rights function
(the current user becomes part of the cache lookup key)
 Safe callouts (implemented via extproc) are faster
(motivated by Oracle R Enterprise – which saw a 20x
speedup)
 Edition-based redefinition can now be adopted without
needing to change how objects are disposed among
schemas – so no reason at all for you not to use EBR for
every patch that changes only PL/SQL, views, or synonyms
Copyright © 2012, Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted68

New PLSQL in Oracle Database 12c

  • 1.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted1 New SQL & PL/SQL Capabilities in Oracle Database 12c Thomas Kyte http://asktom.oracle.com/
  • 2.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted2 The following is intended to outline our general product direction. It is intended for information purposes only, and may not be incorporated into any contract. It is not a commitment to deliver any material, code, or functionality, and should not be relied upon in making purchasing decisions. The development, release, and timing of any features or functionality described for Oracle’s products remains at the sole discretion of Oracle. Small print
  • 3.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted3 PL/SQL  More Bind Types – Booleans – PL/SQL Records – PL/SQL Collections
  • 4.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted4 PL/SQL c##tkyte%CDB1> CREATE OR REPLACE PROCEDURE p (x BOOLEAN) AUTHID CURRENT_USER AS 2 BEGIN 3 IF x THEN 4 DBMS_OUTPUT.PUT_LINE('x is true'); 5 END IF; 6 END; 7 / Procedure created.
  • 5.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted5 PL/SQL ops$tkyte%ORA11GR2> DECLARE 2 dyn_stmt VARCHAR2(200); 3 b BOOLEAN := TRUE; 4 BEGIN 5 dyn_stmt := 'BEGIN p(:x); END;'; 6 EXECUTE IMMEDIATE dyn_stmt USING b; 7 END; 8 / EXECUTE IMMEDIATE dyn_stmt USING b; * ERROR at line 6: ORA-06550: line 6, column 36: PLS-00457: expressions have to be of SQL types ORA-06550: line 6, column 3: PL/SQL: Statement ignored
  • 6.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted6 PL/SQL c##tkyte%CDB1> DECLARE 2 dyn_stmt VARCHAR2(200); 3 b BOOLEAN := TRUE; 4 BEGIN 5 dyn_stmt := 'BEGIN p(:x); END;'; 6 EXECUTE IMMEDIATE dyn_stmt USING b; 7 END; 8 / x is true PL/SQL procedure successfully completed.
  • 7.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted7 PL/SQL  Query PL/SQL Table Type Directly – No more need to create SQL Types – Less namespace clutter
  • 8.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted8 PL/SQL c##tkyte%CDB1> create or replace package my_pkg 2 as 3 type my_collection is table of emp%rowtype; 4 5 procedure p; 6 end my_pkg; 7 / Package created.
  • 9.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted9 PL/SQL c##tkyte%CDB1> create or replace package body my_pkg 2 as 3 4 procedure p 5 is 6 l_data my_collection; 7 begin 8 select * bulk collect into l_data from emp; 9 10 for x in (select * from TABLE(l_data)) 11 loop 12 dbms_output.put_line( x.ename ); 13 end loop; 14 end; 15 16 end my_pkg; 17 / Package body created.
  • 10.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted10 PL/SQL ops$tkyte%ORA11GR2> show err Errors for PACKAGE BODY MY_PKG: LINE/COL ERROR -------- ----------------------------------------------------------------- 10/15 PL/SQL: SQL Statement ignored 10/29 PL/SQL: ORA-22905: cannot access rows from a non-nested table item 10/35 PLS-00642: local collection types not allowed in SQL statements 12/9 PL/SQL: Statement ignored 12/31 PLS-00364: loop index variable 'X' use is invalid
  • 11.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted11 PL/SQL  Grant Roles to Code – Especially useful for invokers rights routines – Code will run with current set of privileges of the Invoker plus that role(s) – Role is only enabled during execution of that procedure – Also, INHERIT PRIVILEGES – new privilege
  • 12.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted12 Granting a role to a PL/SQL unit  Consider this best practice • Give access to an application’s data only via PL/SQL subprograms • Reinforce this by having end-user sessions authorize as a different database owner than the one that owns the application’s artifacts • Arrange this by using definer’s rights units in a single schema or a couple of schemas. Then grant Execute on these to end-users – but don’t grant privileges on the tables to end-users  This means that each unit can access very many tables because the owner of the units can
  • 13.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted13 Granting a role to a PL/SQL unit  12.1 lets us have a fine-grained scheme where each unit with the same owner can have different privileges on the owner’s tables • The end-user is low-privileged, just as in the old scheme • The units are invoker’s rights, so “as is” would not allow end- users to access the data • The privilege for each unit is elevated for exactly and only that unit’s purpose by granting a role that has the appropriate privileges to the unit. Such a role cannot be disabled. • The unit’s owner must already have that same role (but it need not be enabled)
  • 14.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted14 Granting a role to a PL/SQL unit  This scenario lets us illustrate the idea • There are two users App and Client • There are two tables App.t1 and App.t2 • There are two IR procedures App.Show_t1 and App.Show_t2 to run select statements against the tables • Client has Execute on App.Show_t1 and App.Show_t2 • App creates two roles r_Show_t1 and r_Show_t2 • App grants Select on App.t1 to r_Show_t1 – and similar for ~2 • App grants r_Show_t1 to App.Show_t1 – and similar for ~2
  • 15.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted15 Granting a role to a PL/SQL unit create procedure Show_t1 authid Current_User is begin for j in (select Fact from App.t1 order by 1) loop -- Notice the schema-qualification ... end loop; end Show_t1; / grant Execute on App.Show_t1 to Client / -- this has the side-effect of granting the role to App with Admin option -- other non-schema object types like directories and editions behave the same create role r_Show_t1 / grant select on t1 to r_Show_t1 / grant r_Show_t1 to procedure Show_t1 / select Object_Name, Object_Type, Role from User_Code_Role_Privs / ....... ......... ......... SHOW_T1 PROCEDURE R_SHOW_T1
  • 16.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted16 Granting a role to a PL/SQL unit  When Client invokes App.Show_t1, then no matter what careless mistakes the programmer of the procedure might later make, its power is limited to just what the role confers.
  • 17.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted17 PL/SQL  White List – ‘Accessible By’ clause – Specifies a specific list of code that can invoke your code – Fine grained privilege to protect code
  • 18.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted18 accessible by clause package Helper authid Definer accessible by (Good_Guy, Bad_Guy) is procedure p; end Helper; package body Good_Guy is procedure p is begin Helper.p(); ... end p; end Good_Guy; package body Bad_Guy is procedure p is begin Helper.p(); ... end p; end Bad_Guy; PLS-00904: insufficient privilege to access object HELPER _______
  • 19.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted19 Even better PL/SQL from SQL
  • 20.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted20 Defining a PL/SQL function in the with clause of a subquery function Print(n in integer) return varchar2 authid Definer is K constant number not null := 1024; M constant number not null := K*K; G constant number not null := M*K; T constant number not null := G*K; begin return case when n <= K-1 then To_Char(n, '999999')||'byte' when n/K <= K-1 then To_Char(n/K, '999999')||'K' when n/M <= K-1 then To_Char(n/M, '999999')||'M' when n/G <= K-1 then To_Char(n/G, '999999')||'G' else To_Char(n/T, '999999')||'T' end; end Print;  Use case: pretty-print an integer as a multiple of an appropriate power of 1024: plain, K, M, B, or T
  • 21.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted21 Use the PL/SQL function in SQL on a table with three number columns select PK, Print(n1) "n1", Print(n2) "n2", Print(n3) "n3" from t 1 1 K 1 G 566 G 2 1 K 157 M 416 G 3 2 K 1 G 971 G 4 578 byte 1 G 1 T 5 2 K 1 G 220 G 6 1 K 2 G 1 T 7 48 byte 1 G 2 T 8 992 byte 42 M 3 T 9 794 byte 2 G 1 T 10 2 K 302 M 672 G
  • 22.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted22 Try it in pure SQL! select PK, case when n1 <= 1023 then To_Char(n1, '999999')||' byte' when n1/1024 <= 1023 then To_Char(n1/1024, '999999')||' K' when n1/1048576 <= 1023 then To_Char(n1/1048576, '999999')||' M' when n1/1073741824 <= 1023 then To_Char(n1/1073741824, '999999')||' G' else To_Char(n1/1099511627776, '999999')||' T' end "n1", case when n2 <= 1023 then To_Char(n2, '999999')||' byte' when n2/1024 <= 1023 then To_Char(n2/1024, '999999')||' K' when n2/1048576 <= 1023 then To_Char(n2/1048576, '999999')||' M' when n2/1073741824 <= 1023 then To_Char(n2/1073741824, '999999')||' G' else To_Char(n2/1099511627776, '999999')||' T' end "n2", case when n3 <= 1023 then To_Char(n3, '999999')||' byte' when n3/1024 <= 1023 then To_Char(n3/1024, '999999')||' K' when n3/1048576 <= 1023 then To_Char(n3/1048576, '999999')||' M' when n3/1073741824 <= 1023 then To_Char(n3/1073741824, '999999')||' G' else To_Char(n3/1099511627776, '999999')||' T' end "n3" from t
  • 23.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted23 Get the performance of SQL with the clarity and reusability of PL/SQL function Print(n in integer) return varchar2 authid Definer is K constant number not null := 1024; M constant number not null := K*K; G constant number not null := M*K; T constant number not null := G*K; begin return case when n <= K-1 then To_Char(n, '999999')||'byte' when n/K <= K-1 then To_Char(n/K, '999999')||'K' when n/M <= K-1 then To_Char(n/M, '999999')||'M' when n/G <= K-1 then To_Char(n/G, '999999')||'G' else To_Char(n/T, '999999')||'T' end; end Print; pragma UDF;
  • 24.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted24 Declare the PL/SQL function in the subquery’s with clause function Print(n in integer) return varchar2 is K constant number not null := 1024; M constant number not null := K*K; G constant number not null := M*K; T constant number not null := G*K; begin return case when n <= K-1 then To_Char(n, '999999')||' byte' when n/K <= K-1 then To_Char(n/K, '999999')||' K' when n/M <= K-1 then To_Char(n/M, '999999')||' M' when n/G <= K-1 then To_Char(n/G, '999999')||' G' else To_Char(n/T, '999999')||' T' end; end Print; select PK, Print(n1) "n1", Print(n2) "n2", Print(n3) "n3" from t with
  • 25.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted25 Performance comparison  Pure SQL is fastest  Schema-level function with pragma UDF is close  Function in the with clause is similar  Pre-12.1 ordinary schema-level function is very much the slowest 1.0 – the baseline 3.8x 3.9x 5.0x
  • 26.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted26 Better client binding
  • 27.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted27 Improved support for binding PL/SQL types in JDBC  Before 12.1 • Generate a schema level object type to mirror the structure of the non-SQL package type • Populate and bind the object into a custom PL/SQL wrapper around the desired PL/SQL subprogram • Convert the object to the package type in the wrapper and call the PL/SQL subprogram with the package type
  • 28.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted28 Improved support for binding PL/SQL types in JDBC  New in 12.1 • PL/SQL package types supported as binds in JDBC • Can now execute PL/SQL subprograms with non-SQL types • Supported types include records, index-by tables, nested tables and varrays • Table%rowtype, view%rowtype and package defined cursor%rowtype also supported. They’re technically record types
  • 29.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted29 Example1: Bind a single record from Java into a PL/SQL procedure, modify it, and bind it back out to Java package Emp_Info is type employee is record(First_Name Employees.First_Name%type, Last_Name Employees.Last_Name%type, Employee_Id Employees.Employee_Id%type, Is_CEO boolean); procedure Get_Emp_Name(Emp_p in out Employee); end;
  • 30.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted30 Example1:  Use the EmpinfoEmployee class, generated by JPub, to implement the Employee formal parameter { … EmpinfoEmployee Employee = new EmpinfoEmployee(); Employee.setEmployeeId(new java.math.BigDecimal(100)); // Use Employee ID 100 // Call Get_Emp_Name() with the Employee object OracleCallableStatement cstmt = (OracleCallableStatement)conn.prepareCall("call EmpInfo.Get_Emp_Name(?)"); cstmt.setObject(1, Employee, OracleTypes.STRUCT); // Use "PACKAGE.TYPE NAME" as the type name cstmt.registerOutParameter(1, OracleTypes.STRUCT, "EMPINFO.EMPLOYEE"); cstmt.execute(); // Get and print the contents of the Employee object EmpinfoEmployee oraData = (EmpinfoEmployee)cstmt.getORAData(1, EmpinfoEmployee.getORADataFactory()); System.out.println("Employee: " + oraData.getFirstName() + " " + oraData.getLastName()); System.out.println("Is the CEO? " + oraData.getIsceo()); }
  • 31.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted31 Example 2: populate a collection of table%rowtype using a bulk collect statement, and pass the collection as an out parameter back to the caller package EmpRow is type Table_of_Emp is table of Employees%Rowtype; procedure GetEmps(Out_Rows out Table_of_Emp); end; package Body EmpRow is procedure GetEmps(Out_Rows out Table_of_Emp) is begin select * bulk collect into Out_Rows from Employees; end; end;
  • 32.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted32 Example 2: { … // Call GetEmps() to get the ARRAY of table row data objects CallableStatement cstmt = conn.prepareCall("call EmpRow.GetEmps(?)"); // Use "PACKAGE.COLLECTION NAME" as the type name cstmt.registerOutParameter(1, OracleTypes.ARRAY, "EMPROW.TABLE_OF_EMP"); cstmt.execute(); // Print the Employee Table rows Array a = cstmt.getArray(1); String s = Debug.printArray ((ARRAY)a, "", ((ARRAY)a).getSQLTypeName () +"( ", conn); System.out.println(s); }
  • 33.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted33 Improved Introspection
  • 34.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted34 Improved call stack introspection  Before 12.1, you used three functions in the DBMS_Utility package • Format_Call_Stack() • Format_Error_Stack() • Format_Error_Backtrace()  New in 12.1 • The package UTL_Call_Stack solves the same problem properly
  • 35.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted35 Code to be introspected package body Pkg is procedure p is procedure q is procedure r is procedure p is begin Print_Call_Stack(); end p; begin p(); end r; begin r(); end q; begin q(); end p; end Pkg;
  • 36.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted36 Pre 12.1 Print_Call_Stack() procedure Print_Call_Stack authid Definer is Depth pls_integer := UTL_Call_Stack.Dynamic_Depth(); begin DBMS_Output.Put_Line(DBMS_Utility.Format_Call_Stack()); end; ----- PL/SQL Call Stack ----- object line object handle number name 0x631f6e88 12 procedure USR.PRINT_CALL_STACK 0x68587700 7 package body USR.PKG 0x68587700 10 package body USR.PKG 0x68587700 13 package body USR.PKG 0x68587700 16 package body USR.PKG 0x69253ca8 1 anonymous block
  • 37.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted37 12.1 Print_Call_Stack() procedure Print_Call_Stack authid Definer is Depth pls_integer := UTL_Call_Stack.Dynamic_Depth(); begin for j in reverse 2..Depth loop DBMS_Output.Put_Line( (j - 1)|| To_Char(UTL_Call_Stack.Unit_Line(j), '99')|| UTL_Call_Stack.Concatenate_Subprogram(UTL_Call_Stack.Subprogram(j))); end loop; end; 5 1 __anonymous_block 4 16 PKG.P 3 13 PKG.P.Q 2 10 PKG.P.Q.R 1 7 PKG.P.Q.R.P
  • 38.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted38 Improved call stack introspection  Symmetrical subprograms for error stack and backtrace  Plus • Owner(Depth) • Current_Edition(Depth) • Lexical_Depth(Depth)
  • 39.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted39 Agenda  Improved client <> PL/SQL <> SQL interoperability  A new security capability  Improved programmer usability  Miscellaneous
  • 40.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted40 Invisible Columns
  • 41.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted41 Invisible Columns ops$tkyte%ORA12CR1> create table t 2 ( x int, 3 y int 4 ) 5 / Table created. ops$tkyte%ORA12CR1> insert into t values ( 1, 2 ); 1 row created.
  • 42.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted42 Invisible Columns ops$tkyte%ORA12CR1> alter table t add ( z int INVISIBLE ); Table altered.
  • 43.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted43 Invisible Columns ops$tkyte%ORA12CR1> desc t Name Null? Type ----------------- -------- ------------ X NUMBER(38) Y NUMBER(38)
  • 44.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted44 Invisible Columns ops$tkyte%ORA12CR1> insert into t values ( 3, 4 ); 1 row created.
  • 45.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted45 Invisible Columns ops$tkyte%ORA12CR1> select * from t; X Y ---------- ---------- 1 2 3 4
  • 46.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted46 Invisible Columns ops$tkyte%ORA12CR1> insert into t (x,y,z) values ( 5,6,7 ); 1 row created. ops$tkyte%ORA12CR1> select x, y, z from t; X Y Z ---------- ---------- ---------- 1 2 3 4 5 6 7
  • 47.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted47 Invisible Columns ops$tkyte%ORA12CR1> alter table t modify z visible; Table altered. ops$tkyte%ORA12CR1> select * from t; X Y Z ---------- ---------- ---------- 1 2 3 4 5 6 7
  • 48.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted48 Multiple Same Column Indexes
  • 49.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted49 Indexing ops$tkyte%ORA11GR2> create table t ( x int, y int, z int ); Table created. ops$tkyte%ORA11GR2> create index t_idx on t(x,y); Index created. ops$tkyte%ORA11GR2> create bitmap index t_idx2 on t(x,y); create bitmap index t_idx2 on t(x,y) * ERROR at line 1: ORA-01408: such column list already indexed ops$tkyte%ORA11GR2> create bitmap index t_idx2 on t(x,y) invisible; create bitmap index t_idx2 on t(x,y) invisible * ERROR at line 1: ORA-01408: such column list already indexed
  • 50.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted50 Indexing ops$tkyte%ORA12CR1> create table t ( x int, y int, z int ); Table created. ops$tkyte%ORA12CR1> create index t_idx on t(x,y); Index created. ops$tkyte%ORA12CR1> create bitmap index t_idx2 on t(x,y) invisible; Index created.
  • 51.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted51 Indexing ops$tkyte%ORA12CR1> alter session set optimizer_use_invisible_indexes=true; Session altered. ops$tkyte%ORA12CR1> exec dbms_stats.set_table_stats( user, 'T', numrows => 1000000, numblks => 100000 ); PL/SQL procedure successfully completed.
  • 52.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted52 Indexing ops$tkyte%ORA12CR1> set autotrace traceonly explain ops$tkyte%ORA12CR1> select count(*) from t; Execution Plan ---------------------------------------------------------- Plan hash value: 1106681275 --------------------------------------------------------------------- | Id | Operation | Name | Rows | Cost (%CPU)| --------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 0 (0)| | 1 | SORT AGGREGATE | | 1 | | | 2 | BITMAP CONVERSION COUNT | | 1000K| | | 3 | BITMAP INDEX FAST FULL SCAN| T_IDX2 | | | --------------------------------------------------------------------- ops$tkyte%ORA12CR1> set autotrace off
  • 53.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted53 Temporal Validity
  • 54.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted54 Temporal Validity ops$tkyte%ORA12CR1> create table addresses 2 ( empno number, 3 addr_data varchar2(30), 4 start_date date, 5 end_date date, 6 period for valid(start_date,end_date) 7 ) 8 / Table created.
  • 55.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted55 Temporal Validity ops$tkyte%ORA12CR1> insert into addresses (empno, addr_data, start_date, end_date ) 2 values ( 1234, '123 Main Street', trunc(sysdate-5), trunc(sysdate-2) ); 1 row created. ops$tkyte%ORA12CR1> insert into addresses (empno, addr_data, start_date, end_date ) 2 values ( 1234, '456 Fleet Street', trunc(sysdate-1), trunc(sysdate+1) ); 1 row created. ops$tkyte%ORA12CR1> insert into addresses (empno, addr_data, start_date, end_date ) 2 values ( 1234, '789 1st Ave', trunc(sysdate+2), null ); 1 row created.
  • 56.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted56 Temporal Validity ops$tkyte%ORA12CR1> select * from addresses; EMPNO ADDR_DATA START_DAT END_DATE ---------- ------------------------------ --------- --------- 1234 123 Main Street 12-MAY-13 15-MAY-13 1234 456 Fleet Street 16-MAY-13 18-MAY-13 1234 789 1st Ave 19-MAY-13
  • 57.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted57 Temporal Validity ops$tkyte%ORA12CR1> select * from addresses as of period for valid sysdate-3; EMPNO ADDR_DATA START_DAT END_DATE ---------- ------------------------------ --------- --------- 1234 123 Main Street 12-MAY-13 15-MAY-13 ops$tkyte%ORA12CR1> select * from addresses as of period for valid sysdate; EMPNO ADDR_DATA START_DAT END_DATE ---------- ------------------------------ --------- --------- 1234 456 Fleet Street 16-MAY-13 18-MAY-13 ops$tkyte%ORA12CR1> select * from addresses as of period for valid sysdate+3; EMPNO ADDR_DATA START_DAT END_DATE ---------- ------------------------------ --------- --------- 1234 789 1st Ave 19-MAY-13
  • 58.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted58 SQL Text Expansion
  • 59.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted59 SQL Text Expansion ops$tkyte%ORA12CR1> variable x clob ops$tkyte%ORA12CR1> begin 2 dbms_utility.expand_sql_text 3 ( input_sql_text => 'select * from all_users', 4 output_sql_text => :x ); 5 end; 6 / PL/SQL procedure successfully completed.
  • 60.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted60 SQL Text Expansion ops$tkyte%ORA12CR1> print x X -------------------------------------------------------------------------------- SELECT "A1"."USERNAME" "USERNAME","A1"."USER_ID" "USER_ID","A1"."CREATED" "CREAT ED","A1"."COMMON" "COMMON" FROM (SELECT "A4"."NAME" "USERNAME","A4"."USER#" "US ER_ID","A4"."CTIME" "CREATED",DECODE(BITAND("A4"."SPARE1",128),128,'YES','NO') " COMMON" FROM "SYS"."USER$" "A4","SYS"."TS$" "A3","SYS"."TS$" "A2" WHERE "A4"."DA TATS#"="A3"."TS#" AND "A4"."TEMPTS#"="A2"."TS#" AND "A4"."TYPE#"=1) "A1"
  • 61.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted61 SQL Text Expansion ops$tkyte%ORA12CR1> create or replace 2 function my_security_function( p_schema in varchar2, 3 p_object in varchar2 ) 4 return varchar2 5 as 6 begin 7 return 'owner = USER'; 8 end; 9 / Function created.
  • 62.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted62 SQL Text Expansion ops$tkyte%ORA12CR1> create table my_table 2 ( data varchar2(30), 3 OWNER varchar2(30) default USER 4 ) 5 / Table created.
  • 63.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted63 SQL Text Expansion ops$tkyte%ORA12CR1> begin 2 dbms_rls.add_policy 3 ( object_schema => user, 4 object_name => 'MY_TABLE', 5 policy_name => 'MY_POLICY', 6 function_schema => user, 7 policy_function => 'My_Security_Function', 8 statement_types => 'select, insert, update, delete' , 9 update_check => TRUE ); 10 end; 11 / PL/SQL procedure successfully completed.
  • 64.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted64 SQL Text Expansion ops$tkyte%ORA12CR1> begin 2 dbms_utility.expand_sql_text 3 ( input_sql_text => 'select * from my_table', 4 output_sql_text => :x ); 5 end; 6 / PL/SQL procedure successfully completed. ops$tkyte%ORA12CR1> print x X -------------------------------------------------------------------------------- SELECT "A1"."DATA" "DATA","A1"."OWNER" "OWNER" FROM (SELECT "A2"."DATA" "DATA", "A2"."OWNER" "OWNER" FROM "OPS$TKYTE"."MY_TABLE" "A2" WHERE "A2"."OWNER"=USER@!) "A1"
  • 65.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted65 Etc…
  • 66.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted66 Other enhancements brought by 12.1  Improved Defaults  Row Limiting Clause  Row Pattern Matching  Partitioning Improvements  Temporary Undo
  • 67.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted67 Other enhancements brought by 12.1  You can now result-cache an invoker’s rights function (the current user becomes part of the cache lookup key)  Safe callouts (implemented via extproc) are faster (motivated by Oracle R Enterprise – which saw a 20x speedup)  Edition-based redefinition can now be adopted without needing to change how objects are disposed among schemas – so no reason at all for you not to use EBR for every patch that changes only PL/SQL, views, or synonyms
  • 68.
    Copyright © 2012,Oracle and/or its affiliates. All rights reserved. Confidential – Oracle Restricted68