About Me

Database and GIS Consultant.

Friday, July 31, 2009

Oracle Error - "ORA-01762: vopdrv: view query block not in FROM"

Came across this error "ORA-01762: vopdrv: view query block not in FROM"

Here is the version and platform details:

SQL> select banner from v$version;

BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.1.0.6.0 - Production
PL/SQL Release 11.1.0.6.0 - Production
CORE 11.1.0.6.0 Production
TNS for 32-bit Windows: Version 11.1.0.6.0 - Production
NLSRTL Version 11.1.0.6.0 - Production

Here is the structure of the view:

SQL> DESC DBA_AUTOTASK_WINDOW_CLIENTS;
Name Null? Type
----------------------- -------- ----------------
WINDOW_NAME NOT NULL VARCHAR2(30)
WINDOW_NEXT_TIME TIMESTAMP(6) WITH TIME ZONE
WINDOW_ACTIVE VARCHAR2(5)
AUTOTASK_STATUS VARCHAR2(8)
OPTIMIZER_STATS VARCHAR2(8)
SEGMENT_ADVISOR VARCHAR2(8)
SQL_TUNE_ADVISOR VARCHAR2(8)
HEALTH_MONITOR VARCHAR2(8)

This query works:

SQL> SELECT * FROM DBA_AUTOTASK_WINDOW_CLIENTS

WINDOW_NAME WINDOW_NEXT_TIME WINDO AUTOTASK OPTIMIZE SEGMENT_ SQL_TUNE HEALTH_M
---------------- ---------------------------------------- ----- -------- -------- -------- -------- --------
MONDAY_WINDOW 03-AUG-09 10.00.00.000000 PM US/EASTERN FALSE ENABLED ENABLED ENABLED ENABLED DISABLED
TUESDAY_WINDOW 04-AUG-09 10.00.00.000000 PM US/EASTERN FALSE ENABLED ENABLED ENABLED ENABLED DISABLED
WEDNESDAY_WINDOW 05-AUG-09 10.00.00.000000 PM US/EASTERN FALSE ENABLED ENABLED ENABLED ENABLED DISABLED
THURSDAY_WINDOW 06-AUG-09 10.00.00.000000 PM US/EASTERN FALSE ENABLED ENABLED ENABLED ENABLED DISABLED
FRIDAY_WINDOW 31-JUL-09 10.00.00.000000 PM US/EASTERN FALSE ENABLED ENABLED ENABLED ENABLED DISABLED
SATURDAY_WINDOW 01-AUG-09 06.00.00.000000 AM US/EASTERN FALSE ENABLED ENABLED ENABLED ENABLED DISABLED
SUNDAY_WINDOW 02-AUG-09 06.00.00.000000 AM US/EASTERN FALSE ENABLED ENABLED ENABLED ENABLED DISABLED

7 rows selected.

But this one fails (or sucks! for the USA readers!):

SQL> SELECT WINDOW_NAME FROM DBA_AUTOTASK_WINDOW_CLIENTS;
SELECT WINDOW_NAME FROM DBA_AUTOTASK_WINDOW_CLIENTS
*
ERROR at line 1:
ORA-01762: vopdrv: view query block not in FROM

Any clue?

Wednesday, July 1, 2009

SECUREFILE Migration - Oracle 11g Feature

Step#1) Create a partition table:-

SQL> CREATE TABLE DOC_TAB (ID NUMBER, COLX CLOB )
2 PARTITION BY RANGE (ID) (
3 PARTITION P1 VALUES LESS THAN (10) TABLESPACE TBS_A LOB(COLX) STORE AS LOBP1,
4 PARTITION P2 VALUES LESS THAN (20) TABLESPACE TBS_B LOB(COLX) STORE AS LOBP2,
5 PARTITION P3 VALUES LESS THAN (30) TABLESPACE TBS_C LOB(COLX) STORE AS LOBP3);

Table created.

Step#2) Insert data

SQL> INSERT INTO DOC_TAB VALUES (5,'XXX');

1 row created.

SQL> INSERT INTO DOC_TAB VALUES (15,'YYY');

1 row created.

SQL> INSERT INTO DOC_TAB VALUES (25,'ZZZ');

1 row created.

SQL> commit;

Commit complete.

Step#3) Create a transient table

SQL> CREATE TABLE DOC_TAB_TEMP (ID NUMBER, COLX CLOB)
2 PARTITION BY RANGE (ID) (
3 PARTITION P1 VALUES LESS THAN (10) TABLESPACE TBS_A LOB(COLX) STORE AS SECUREFILE,
4 PARTITION P2 VALUES LESS THAN (20) TABLESPACE TBS_B LOB(COLX) STORE AS SECUREFILE,
5 PARTITION P3 VALUES LESS THAN (30) TABLESPACE TBS_C LOB(COLX) STORE AS SECUREFILE);

Table created.

Step#4) Table Redefinition

SQL> DECLARE
2 ERROR_COUNT NUMBER;
3 BEGIN
4 DBMS_REDEFINITION.START_REDEF_TABLE(
5 UNAME=>'BABU',
6 ORIG_TABLE=>'DOC_TAB',
7 INT_TABLE=>'DOC_TAB_TEMP',
8 COL_MAPPING=>'ID ID,COLX COLX');
9 DBMS_REDEFINITION.COPY_TABLE_DEPENDENTS(
10 UNAME=>'BABU',
11 ORIG_TABLE=>'DOC_TAB',
12 INT_TABLE=>'DOC_TAB_TEMP',
13 COPY_INDEXES=>1,
14 COPY_TRIGGERS=>TRUE,
15 COPY_CONSTRAINTS=>TRUE,
16 COPY_PRIVILEGES=>TRUE,
17 IGNORE_ERRORS=>FALSE,
18 NUM_ERRORS=>ERROR_COUNT);
19 DBMS_REDEFINITION.FINISH_REDEF_TABLE(
20 UNAME=>'BABU',ORIG_TABLE=>'DOC_TAB',INT_TABLE=>'DOC_TAB_TEMP');
21 DBMS_OUTPUT.PUT_LINE(ERROR_COUNT);
22 END;
23 /
DECLARE
*
ERROR at line 1:
ORA-12089: cannot online redefine table "BABU"."DOC_TAB" with no primary key
ORA-06512: at "SYS.DBMS_REDEFINITION", line 52
ORA-06512: at "SYS.DBMS_REDEFINITION", line 1631
ORA-06512: at line 4

SQL> CREATE TABLE DOC_TAB (ID NUMBER PRIMARY KEY, COLX CLOB )
2 PARTITION BY RANGE (ID) (
3 PARTITION P1 VALUES LESS THAN (10) TABLESPACE TBS_A LOB(COLX) STORE AS LOBP1,
4 PARTITION P2 VALUES LESS THAN (20) TABLESPACE TBS_B LOB(COLX) STORE AS LOBP2,
5 PARTITION P3 VALUES LESS THAN (30) TABLESPACE TBS_C LOB(COLX) STORE AS LOBP3);

Table created.

Step#4) Table Redefinition (again)

SQL> DECLARE
2 ERROR_COUNT NUMBER;
3 BEGIN
4 DBMS_REDEFINITION.START_REDEF_TABLE(
5 UNAME=>'BABU',
6 ORIG_TABLE=>'DOC_TAB',
7 INT_TABLE=>'DOC_TAB_TEMP',
8 COL_MAPPING=>'ID ID,COLX COLX');
9 DBMS_REDEFINITION.COPY_TABLE_DEPENDENTS(
10 UNAME=>'BABU',
11 ORIG_TABLE=>'DOC_TAB',
12 INT_TABLE=>'DOC_TAB_TEMP',
13 COPY_INDEXES=>1,
14 COPY_TRIGGERS=>TRUE,
15 COPY_CONSTRAINTS=>TRUE,
16 COPY_PRIVILEGES=>TRUE,
17 IGNORE_ERRORS=>FALSE,
18 NUM_ERRORS=>ERROR_COUNT);
19 DBMS_REDEFINITION.FINISH_REDEF_TABLE(
20 UNAME=>'BABU',ORIG_TABLE=>'DOC_TAB',INT_TABLE=>'DOC_TAB_TEMP');
21 DBMS_OUTPUT.PUT_LINE(ERROR_COUNT);
22 END;
23 /
0

PL/SQL procedure successfully completed.

Thursday, May 28, 2009

New features in Oracle 11g Database - Reference Partition

Reference Partitioning is a new feature in Oracle 11g, it is meant for partitioning the parent and child tables using the foreign key constraint.

SQL> CREATE TABLE PARENT_TAB (
2 COL1 NUMBER(3) PRIMARY KEY,
3 COL2 DATE)
4 PARTITION BY RANGE (COL2) (
5 PARTITION Q1 VALUES LESS THAN (TO_DATE('1-4-2009','DD-MM-YYYY')),
6 PARTITION Q2 VALUES LESS THAN (TO_DATE('1-7-2009','DD-MM-YYYY')));

Table created.

SQL> CREATE TABLE CHILD_TAB (
2 COL1 NUMBER(3),
3 CONSTRAINT CHILD_FK FOREIGN KEY (COL1) REFERENCES PARENT_TAB(COL1))
4 PARTITION BY REFERENCE (CHILD_FK);
PARTITION BY REFERENCE (CHILD_FK)
*
ERROR at line 4:
ORA-14652: reference partitioning foreign key is not supported

SQL> CREATE TABLE CHILD_TAB (
2 COL1 NUMBER(3) NOT NULL,
3 CONSTRAINT CHILD_FK FOREIGN KEY (COL1) REFERENCES PARENT_TAB(COL1))
4 PARTITION BY REFERENCE (CHILD_FK);

Table created.

In Reference Partitioning, specifying NOT NULL for the FOREIGN KEY column in child table is mandatory. Otherwise it will throw the above error.

Monday, December 29, 2008

Oracle NUMBER Data Types

Introduction: This is my study about number data types present
in Oracle database. I have used Oracle 10g (10.2.0.3) for my study:-

Data types INT, INTEGER and SMALLINT all uses NUMBER in Oracle, let us see how:-

Example # 1:

drop table tab1 purge;

create table tab2 (
I INT,
S SMALLINT,
IG INTEGER);

describe tab1

Name Null? Type
------------------ -------- ----------
I NUMBER(38)
S NUMBER(38)
IG NUMBER(38)

Example # 2: Let's see about other number data types:-

drop table tab2 purge;

create table tab2 (
X number,
NUM1 NUMBER,
FLOAT1 FLOAT,
BFLOAT BINARY_FLOAT,
BDOUBLE BINARY_DOUBLE);

describe tab2

Name Null? Type
----------------------- -------- -------------
X NUMBER
NUM1 NUMBER
FLOAT1 FLOAT(126)
BFLOAT BINARY_FLOAT
BDOUBLE BINARY_DOUBLE

declare
y number;
begin for a in 1..10 loop
y:=1/(a*100);
insert into tab2 values (a,y,y,y,y);
end loop;
commit;
end;
/

col NUM1 for .99999999999999999999
col FLOAT1 for .99999999999999999999
col BFLOAT for .99999999999999999999
col BDOUBLE for .99999999999999999999
set lines 120

select * from tab2;

X NUM1 FLOAT1 BFLOAT BDOUBLE
-- ---------------------- ---------------------- ---------------------- ------------
1 .01000000000000000000 .01000000000000000000 .00999999978000000000 .01000000000000000000 2 .00500000000000000000 .00500000000000000000 .00499999989000000000 .00500000000000000010 3 .00333333333333333333 .00333333333333333333 .00333333341000000000 .00333333333333333350 4 .00250000000000000000 .00250000000000000000 .00249999994000000000 .00250000000000000010 5 .00200000000000000000 .00200000000000000000 .00200000009000000000 .00200000000000000000 6 .00166666666666666667 .00166666666666666667 .00166666671000000000 .00166666666666666680 7 .00142857142857142857 .00142857142857142857 .00142857141000000000 .00142857142857142860 8 .00125000000000000000 .00125000000000000000 .00124999997000000000 .00125000000000000000 9 .00111111111111111111 .00111111111111111111 .00111111114000000000 .00111111111111111110 10 .00100000000000000000 .00100000000000000000 .00100000005000000000 .00100000000000000000
10 rows selected.


In the above, the NUM1 (which is using Number data type) and FLOAT1 (which is using FLOAT data type) preserves accuracy/scale than others.

Example # 3: Now, lets us try this

delete tab2;

declare
y number;
begin for a in 1..10 loop
y:=(a+(sqrt(a))/(a*100));
insert into tab2 values (a,y,y,y,y);
end loop;
commit;
end;
/

col NUM1 for 99.99999999999999999999999999999999999999
col FLOAT1 for 99.99999999999999999999999999999999999999

select NUM1,FLOAT1 from tab2;

NUM1 FLOAT1
------------------------------------------ ------------------------------------------ 1.01000000000000000000000000000000000000 1.01000000000000000000000000000000000000
2.00707106781186547524400844362104849039 2.00707106781186547524400844362104849040
3.00577350269189625764509148780501957456 3.00577350269189625764509148780501957460
4.00500000000000000000000000000000000000 4.00500000000000000000000000000000000000
5.00447213595499957939281834733746255247 5.00447213595499957939281834733746255250
6.00408248290463863016366214012450981899 6.00408248290463863016366214012450981900
7.00377964473009227227214516536234180061 7.00377964473009227227214516536234180060
8.00353553390593273762200422181052424520 8.00353553390593273762200422181052424520
9.00333333333333333333333333333333333333 9.00333333333333333333333333333333333330
10.00316227766016837933199889354443271853 10.00316227766016837933199889354443271900

10 rows selected.

select avg(NUM1) NUM1, avg(FLOAT1) FLOAT1 from tab2;

NUM1 FLOAT1
------------------------------------------ ------------------------------------------ 5.50502099789929266650050620329386725341 5.50502099789929266650050620329386725346

select sum(NUM1) NUM1, sum(FLOAT1) FLOAT1 from tab2;

NUM1 FLOAT1
------------------------------------------ ------------------------------------------ 55.05020997899292666500506203293867253408 55.05020997899292666500506203293867253460

select max(NUM1) NUM1, max(FLOAT1) FLOAT1 from tab2;

NUM1 FLOAT1
------------------------------------------ ------------------------------------------ 10.00316227766016837933199889354443271853 10.00316227766016837933199889354443271900


Example # 4: Now, lets us compare NUMBER and FLOAT data type and try this

drop table tab3 purge;

create table tab3 (
NUM1 NUMBER,
FLOAT1 FLOAT);

delete tab3;

insert into tab3 values (
1234567891234567891234567890123456789123.45,
1234567891234567891234567890123456789123.45);

col NUM1 for 9999999999999999999999999999999999999999.99
col FLOAT1 for 9999999999999999999999999999999999999999.99

select * from tab3;

NUM1
--------------------------------------------
FLOAT1
--------------------------------------------
1234567891234567891234567890123456789123.00
1234567891234567891234567890123456789100.00


In the above when comparing the NUM1 (NUMBER data type) and FLOAT1 (FLOAT data type), it appears that NUM1 (Number data type) preserves accuracy/scale than the other.

When default is used, NUMBER datatype can preserve values upto 40 bytes and FLOAT upto 38 bytes

Wednesday, December 17, 2008

Bug in Oracle 10g while using Check Constraint

Came across this bug in the check constraint in Oracle database 10g.
This has been tested in both 32 and 64 bit Oracle 10g (10.2.0.3) running on Windows 2003 Server.

SQL> select * from v$version;
BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.3.0 - Prod
PL/SQL Release 10.2.0.3.0 - Production
CORE 10.2.0.3.0 Production
TNS for 32-bit Windows: Version 10.2.0.3.0 - Production
NLSRTL Version 10.2.0.3.0 - Production


Reproducing the bug: Create a table called STORE having filed called LOCATION, this field should accept specified values or NULL values, below is the syntax:-

SQL> CREATE TABLE STORE (LOCATION VARCHAR2(15));

Table created.

SQL> ALTER TABLE STORE
2 ADD CONSTRAINT C1 CHECK
3
(LOCATION IN ('PHILLY','HARRISBURG',NULL));

Table altered.

Bug Note: By specifying a NULL, the constraint doesn't not verifies/validates the entered value.

SQL> INSERT INTO STORE VALUES ('PHILLY');
1 row created.

SQL> INSERT INTO STORE VALUES ('philly');
1 row created.

SQL> INSERT INTO STORE VALUES ('HARRISBURG');
1 row created.

SQL> INSERT INTO STORE VALUES ('harrisburg');
1 row created.

SQL> INSERT INTO STORE VALUES (null);
1 row created.

SQL> INSERT INTO STORE VALUES ('PITTSBURGH');
1 row created.

SQL> INSERT INTO STORE VALUES ('pittsburgh');
1 row created.

SQL> commit;
Commit complete.

SQL> col SEARCH_CONDITION for a50
SQL> select
2 STATUS,
3 DEFERRABLE,
4 DEFERRED,
5 VALIDATED,
6 SEARCH_CONDITION
7 FROM ALL_CONSTRAINTS A
8 WHERE table_name='STORE';

STATUS DEFERRABLE DEFERRED VALIDATED SEARCH_CONDITION
-------- -------------- --------- ------------- ----------------------------------------
ENABLED NOT DEFERRABLE IMMEDIATE VALIDATED LOCATION IN ('PHILLY','HARRISBURG',NULL)

SQL> select LOCATION from STORE;
LOCATION
---------------
PHILLY
philly
HARRISBURG
harrisburg

PITTSBURGH
pittsburgh

7 rows selected.

PROBLEM: DMLs like INSERT, UPDATE and DELETE works, but Query (SELECT) statements doesn't work in Oracle 10g (Tested in 10.2.0.3 both in 32 and 64 bit) while querying for records that actually violates the constraint rule. But works fine in Oracle 9i (tested in 9.2.0.8) and 11g (tested in 11.1.0.6)

Condition that violate the constraint rule:-
SQL> select count(*) from STORE where LOCATION='philly';

COUNT(*)
----------
0

Condition that doesn't violate the constraint rule:-
SQL> select count(*) from STORE where LOCATION='PHILLY';
COUNT(*)
----------
1

SQL> select count(*) from STORE where upper(LOCATION)=upper('philly');
COUNT(*)
----------
2

Condition that violate the constraint rule, DMLs works fine:-
SQL> update STORE set LOCATION='XYX' where LOCATION='philly';
1 row updated.

SQL> commit;
Commit complete.

Condition that violate the constraint rule:-
SQL> select count(*) from STORE where LOCATION='XYX';
COUNT(*)
----------
0

SQL> select LOCATION from STORE;
LOCATION
---------------
PHILLY
XYX
HARRISBURG
harrisburg

PITTSBURGH
pittsburgh

7 rows selected.


Condition that violate the constraint rule, DMLs works fine:-
SQL> delete from STORE where LOCATION='XYX';

1 row deleted.

SQL> select LOCATION from STORE;
LOCATION
---------------
PHILLY
HARRISBURG
harrisburg

PITTSBURGH
pittsburgh

6 rows selected.

SQL> commit;

Commit complete.

FIX for 10g

ALTER TABLE STORE drop CONSTRAINT C1 ;

Option # 1: Create a check constraint without specifying NULL. By default check constraint will accept NULL values, hence it doesn't have to be mentioned in the constraint condition

ALTER TABLE STORE
ADD CONSTRAINT C1 CHECK
(LOCATION IN ('PHILLY','HARRISBURG'));

or

ALTER TABLE STORE
ADD CONSTRAINT C1 CHECK
(LOCATION IN ('PHILLY','HARRISBURG') or LOCATION IS NULL);

Option # 2: Specify function like UPPER or LOWER in the constraint

ALTER TABLE STORE
ADD CONSTRAINT C1 CHECK
(UPPER(LOCATION) IN ('PHILLY','HARRISBURG'));

Option # 3: If NOT NULL need to be enforced along with the above condition, then use the following:-

ALTER TABLE STORE
ADD CONSTRAINT C1 CHECK
(LOCATION IN ('PHILLY','HARRISBURG') and LOCATION IS NOT NULL);

Did anyone else had similar problem?

Friday, December 21, 2007

New features in Oracle 11g Database - Virtual Columns

5. Virtual Columns
Virtual Columns are either created at the time of creating or modifying a table. Virtual Columns are defined by expressions or functions, which will be included as part of table structure and hence its metadata. Virtual Columns are like Views, they don't use additional disk space for its data.

U1> CREATE TABLE student_mark(
  2     stud_id NUMBER(5),
  3     stud_name VARCHAR2(15),
  4     subj1_mark NUMBER(3),
  5     subj2_mark NUMBER(3),
  6     subj3_mark NUMBER(3),
  7     tot_mark AS (subj1_mark + subj2_mark + subj3_mark));

Table created.

U1> DESCRIBE student_mark
 Name                    Null?    Type
 ----------------------- -------- ----------------
 STUD_ID                          NUMBER(5)
 STUD_NAME                        VARCHAR2(15)
 SUBJ1_MARK                       NUMBER(3)
 SUBJ2_MARK                       NUMBER(3)
 SUBJ3_MARK                       NUMBER(3)
 TOT_MARK                         NUMBER

U1> DROP TABLE student_mark;

Table dropped.

U1> CREATE TABLE student_mark(
  2     stud_id NUMBER(5),
  3     stud_name VARCHAR2(15),
  4     subj1_mark NUMBER(3),
  5     subj2_mark NUMBER(3),
  6     subj3_mark NUMBER(3),
  7     tot_mark NUMBER(4) AS (subj1_mark + subj2_mark + subj3_mark));

Table created.

U1> DESCRIBE student_mark
 Name                    Null?    Type
 ----------------------- -------- ----------------
 STUD_ID                          NUMBER(5)
 STUD_NAME                        VARCHAR2(15)
 SUBJ1_MARK                       NUMBER(3)
 SUBJ2_MARK                       NUMBER(3)
 SUBJ3_MARK                       NUMBER(3)
 TOT_MARK                         NUMBER(4)

U1> INSERT
  2     INTO student_mark(stud_id, stud_name, subj1_mark, subj2_mark, subj3_mark)
  3     VALUES(10, 'Rose', 75, 45, 66);

1 row created.

U1> INSERT
  2     INTO student_mark(stud_id, stud_name, subj1_mark, subj2_mark, subj3_mark)
  3     VALUES(20, 'Bose', 45, 79, 88);

1 row created.

U1> SELECT *
  2     FROM student_mark;

STUD_ID    STUD_NAME       SUBJ1_MARK SUBJ2_MARK SUBJ3_MARK   TOT_MARK
---------- --------------- ---------- ---------- ---------- ----------
        10 Rose                    75         45         66        186
        20 Bose                    45         79         88        212

U1> ALTER TABLE student_mark
  2     ADD avg_mark NUMBER(3) AS (((subj1_mark + subj2_mark + subj3_mark) / 3));

Table altered.

U1> DESCRIBE student_mark
 Name                    Null?    Type
 ----------------------- -------- ----------------
 STUD_ID                          NUMBER(5)
 STUD_NAME                        VARCHAR2(15)
 SUBJ1_MARK                       NUMBER(3)
 SUBJ2_MARK                       NUMBER(3)
 SUBJ3_MARK                       NUMBER(3)
 TOT_MARK                         NUMBER(4)
 AVG_MARK                         NUMBER(3)

U1> INSERT
  2     INTO student_mark(stud_id, stud_name, subj1_mark, subj2_mark, subj3_mark)
  3     VALUES(30, 'Jose', 63, 68, 72);

1 row created.

U1> SELECT *
  2 FROM student_mark;

STUD_ID    STUD_NAME       SUBJ1_MARK SUBJ2_MARK SUBJ3_MARK   TOT_MARK   AVG_MARK
---------- --------------- ---------- ---------- ---------- ---------- ----------
        10 Rose                    75         45         66        186         62
        20 Bose                    45         79         88        212         71
        30 Jose                    63         68         72        203         68

U1> ALTER TABLE student_mark DROP COLUMN avg_mark;

Table altered.

Attaching a user defined function with a virtual column:-

U1> CREATE OR REPLACE FUNCTION get_avg(stud_no IN NUMBER)
  2     RETURN NUMBER deterministic IS subj_avg NUMBER(3);
  3     BEGIN
  4         SELECT((subj1_mark + subj2_mark + subj3_mark) / 3)
  5         INTO subj_avg
  6         FROM student_mark
  7         WHERE stud_id = stud_no;
  8         RETURN(subj_avg);
  9     END;
 10 /

Function created.

U1> ALTER TABLE student_mark
 2     ADD avrg_mark AS (get_avg(stud_id));

Table altered.

U1> DESCRIBE student_mark
 Name                    Null?    Type
 ----------------------- -------- ----------------
 STUD_ID                          NUMBER(5)
 STUD_NAME                        VARCHAR2(15)
 SUBJ1_MARK                       NUMBER(3)
 SUBJ2_MARK                       NUMBER(3)
 SUBJ3_MARK                       NUMBER(3)
 TOT_MARK                         NUMBER(4)
 AVRG_MARK                        NUMBER


U1> SELECT * FROM student_mark;

STUD_ID    STUD_NAME       SUBJ1_MARK SUBJ2_MARK SUBJ3_MARK   TOT_MARK  AVRG_MARK
---------- --------------- ---------- ---------- ---------- ---------- ----------
        10 Rose                    75         45         66        186         62
        20 Bose                    45         79         88        212         71
        30 Jose                    63         68         72        203         68

Lets see what happens when we drop the function:-

U1> DROP FUNCTION get_avg;

Function dropped.

U1> SELECT *
  2 FROM student_mark;
SELECT *
*
ERROR at line 1:
ORA-00904: "U1"."GET_AVG": invalid identifier


U1> DESCRIBE student_mark
 Name                    Null?    Type
 ----------------------- -------- ----------------
 STUD_ID                          NUMBER(5)
 STUD_NAME                        VARCHAR2(15)
 SUBJ1_MARK                       NUMBER(3)
 SUBJ2_MARK                       NUMBER(3)
 SUBJ3_MARK                       NUMBER(3)
 TOT_MARK                         NUMBER(4)
 AVRG_MARK                        NUMBER

U1> CREATE OR REPLACE FUNCTION get_avg(stud_no IN NUMBER)
  2     RETURN NUMBER deterministic IS subj_avg NUMBER(3);
  3     BEGIN
  4         SELECT((subj1_mark + subj2_mark + subj3_mark) / 3)
  5         INTO subj_avg
  6         FROM student_mark
  7         WHERE stud_id = stud_no;
  8         RETURN(subj_avg);
  9     END;
 10 /

Function created.

U1> SELECT * FROM student_mark;

STUD_ID    STUD_NAME       SUBJ1_MARK SUBJ2_MARK SUBJ3_MARK   TOT_MARK  AVRG_MARK
---------- --------------- ---------- ---------- ---------- ---------- ----------
        10 Rose                    75         45         66        186         62
        20 Bose                    45         79         88        212         71
        30 Jose                    63         68         72        203         68

Partition on Virtual Columns

This enables to partition the table based on the expression or function that were used to create a virtual column. Lets take the below example:-


U1> CREATE TABLE phone_cust (
  2     cust_id NUMBER(5),
  3     name VARCHAR2(15),
  4     street VARCHAR2(15),
  5     city VARCHAR2(10),
  6     zip NUMBER(5),
  7     phone NUMBER(10),
  8     area_code AS (SUBSTR(phone,1,3)||'-'||SUBSTR(phone,4,3)));

Table created.

U1> DESCRIBE phone_cust
 Name                    Null? Type
 ----------------------- -------- ----------------
 CUST_ID                          NUMBER(5)
 NAME                             VARCHAR2(15)
 STREET                           VARCHAR2(15)
 CITY                             VARCHAR2(10)
 ZIP                              NUMBER(5)
 PHONE                            NUMBER(10)
 AREA_CODE                        VARCHAR2(7)

U1> ALTER TABLE phone_cust modify area_code AS (SUBSTR(phone, 1, 3));

Table altered.

U1> DESCRIBE phone_cust
 Name                    Null? Type
 ----------------------- -------- ----------------
 CUST_ID                          NUMBER(5)
 NAME                             VARCHAR2(15)
 STREET                           VARCHAR2(15)
 CITY                             VARCHAR2(10)
 ZIP                              NUMBER(5)
 PHONE                            NUMBER(10)
 AREA_CODE                        VARCHAR2(3)

U1> SELECT * FROM phone_cust;

   CUST_ID NAME            STREET          CITY              ZIP      PHONE ARE
---------- --------------- --------------- ---------- ---------- ---------- ---
        10 John            660 Boas Street Harrisburg      17102 7171234567 717
        20 Raju            123 Mkt Street  Lemoyne         17011 7174567891 717

U1> DROP TABLE phone_cust;

Table dropped.

U1> CREATE TABLE phone_cust(
  2     cust_id NUMBER(5),
  3     name VARCHAR2(15),
  4     street VARCHAR2(15),
  5     city VARCHAR2(10),
  6     zip NUMBER(5),
  7     phone NUMBER(10),
  8     area_code AS (SUBSTR(phone, 1, 3)))
  9   PARTITION BY range(area_code)(
 10   PARTITION p1 VALUES less than(500) TABLESPACE encr_tbs_1,
 11   PARTITION p2 VALUES less than(999) TABLESPACE encr_tbs_2)
 12   enable ROW movement;

Table created.

U1> INSERT
  2  INTO phone_cust(cust_id, name, street, city, zip, phone)
  3  VALUES(10, 'Chel', '456 Walnut St', 'Philly', '19139', 2154567891);

1 row created.

U1> INSERT
  2  INTO phone_cust(cust_id, name, street, city, zip, phone)
  3  VALUES(20, 'John', '660 Boas Street', 'Harrisburg', '17102', 7171234567);

1 row created.

U1> INSERT
  2  INTO phone_cust(cust_id, name, street, city, zip, phone)
  3  VALUES(30, 'Raju', '123 Mkt Street', 'Lemoyne', '17011', 7174567891);

1 row created.

U1> INSERT
  2  INTO phone_cust(cust_id, name, street, city, zip, phone)
  3  VALUES(40, 'Appu', '3 Bridge Trc', 'Woodbridge', '07085', 7324567891);

1 row created.

U1> INSERT
  2 INTO phone_cust(cust_id, name, street, city, zip, phone)
  3 VALUES(50, 'Babu', '5 1st Ave', 'Manhattan', '10037', 2124567891);

1 row created.

U1> INSERT
  2 INTO phone_cust(cust_id, name, street, city, zip, phone)
  3 VALUES(60, 'Rangasamy', '12 Circle Dr', 'Redlands', '92415', 9094567891);

1 row created.

U1> commit;

Commit complete.

U1> DESCRIBE phone_cust
 Name                    Null? Type
 ----------------------- -------- ----------------
 CUST_ID                          NUMBER(5)
 NAME                             VARCHAR2(15)
 STREET                           VARCHAR2(15)
 CITY                             VARCHAR2(10)
 ZIP                              NUMBER(5)
 PHONE                            NUMBER(10)
 AREA_CODE                        VARCHAR2(3)

U1> SELECT * FROM phone_cust;

   CUST_ID NAME            STREET          CITY              ZIP      PHONE ARE
---------- --------------- --------------- ---------- ---------- ---------- ---
        10 Chel            456 Walnut St   Philly          19139 2154567891 215
        50 Babu            5 1st Ave       Manhattan       10037 2124567891 212
        20 John            660 Boas Street Harrisburg      17102 7171234567 717
        30 Raju            123 Mkt Street  Lemoyne         17011 7174567891 717
        40 Appu            3 Bridge Trc    Woodbridge       7085 7324567891 732
        60 Rangasamy       12 Circle Dr    Redlands        92415 9094567891 909

U1> SELECT * FROM phone_cust PARTITION(p1);

   CUST_ID NAME            STREET          CITY              ZIP      PHONE ARE
---------- --------------- --------------- ---------- ---------- ---------- ---
        10 Chel            456 Walnut St   Philly          19139 2154567891 215
        50 Babu            5 1st Ave       Manhattan       10037 2124567891 212

U1> SELECT * FROM phone_cust PARTITION(p2);

   CUST_ID NAME            STREET          CITY              ZIP      PHONE ARE
---------- --------------- --------------- ---------- ---------- ---------- ---
        20 John            660 Boas Street Harrisburg      17102 7171234567 717
        30 Raju            123 Mkt Street  Lemoyne         17011 7174567891 717
        40 Appu            3 Bridge Trc    Woodbridge       7085 7324567891 732
        60 Rangasamy       12 Circle Dr    Redlands        92415 9094567891 909

U1> UPDATE phone_cust SET phone = 2121234567 WHERE cust_id = 20;

1 row updated.

U1> commit;

Commit complete.

U1> SELECT * FROM phone_cust;

   CUST_ID NAME            STREET          CITY              ZIP      PHONE ARE
---------- --------------- --------------- ---------- ---------- ---------- ---
        10 Chel            456 Walnut St   Philly          19139 2154567891 215
        50 Babu            5 1st Ave       Manhattan       10037 2124567891 212
        20 John            660 Boas Street Harrisburg      17102 2121234567 212
        30 Raju            123 Mkt Street  Lemoyne         17011 7174567891 717
        40 Appu            3 Bridge Trc    Woodbridge       7085 7324567891 732
        60 Rangasamy       12 Circle Dr    Redlands        92415 9094567891 909

6 rows selected.

U1> SELECT * FROM phone_cust PARTITION(p1);

   CUST_ID NAME            STREET          CITY              ZIP      PHONE ARE
---------- --------------- --------------- ---------- ---------- ---------- ---
        10 Chel            456 Walnut St   Philly          19139 2154567891 215
        50 Babu            5 1st Ave       Manhattan       10037 2124567891 212
        20 John            660 Boas Street Harrisburg      17102 2121234567 212

U1> SELECT * FROM phone_cust PARTITION(p2);

   CUST_ID NAME            STREET          CITY              ZIP      PHONE ARE
---------- --------------- --------------- ---------- ---------- ---------- ---
        30 Raju            123 Mkt Street  Lemoyne         17011 7174567891 717
        40 Appu            3 Bridge Trc    Woodbridge       7085 7324567891 732
        60 Rangasamy       12 Circle Dr    Redlands        92415 9094567891 909
 

Tuesday, December 18, 2007

New features in Oracle 11g Database

What's new in an Oracle 11g Database?

1. Lets check some INIT parameters first:-

MEMORY_TARGET: Specifies the Oracle system-wide usable memory. The database tunes memory to the MEMORY_TARGET value, increasing or decreasing SGA and PGA as needed.

MEMORY_MAX_TARGET: Maximum value that MEMORY_TARGET initialization parameter can use.

DIAGNOSTIC_DEST: Diagnostics for each database instance are located in this dedicated directory

2. Password is now Case Sensitive.

SQL> create user u1 identified by U1 default tablespace users quota 50m on users;

User created.

SQL> grant create session, create table, create procedure, create view to u1;

Grant succeeded.

SQL> create user u2 identified by u2 default tablespace users quota 50m on users;

User created.

SQL> grant create session, create table, create procedure, create view to u2;

Grant succeeded.

SQL> connect u1/u1
ERROR:
ORA-01017: invalid username/password; logon denied


Warning: You are no longer connected to ORACLE.

SQL> connect u1/U1
Connected.

SQL> connect u2/U2
ERROR:
ORA-01017: invalid username/password; logon denied


Warning: You are no longer connected to ORACLE.
SQL> connect u2/u2
Connected.

3. READ-ONLY Table

SQL> connect u1/U1
Connected.

SQL> create table t1 (a number) ;

Table created.

SQL> begin
   2 for x in 1..20 loop
   3 insert into t1 values (x);
   4 end loop;
   5 commit;
   6 end;
   7 /


PL/SQL procedure successfully completed.

SQL> select READ_ONLY from user_tables where table_name='T1';

REA
---
NO

1 row selected.

SQL> alter table t1 READ ONLY;

Table altered.

SQL> select READ_ONLY from user_tables where table_name='T1';

REA
---
YES

1 row selected.

SQL> insert into t1 values (99);
insert into t1 values (99)
*
ERROR at line 1:
ORA-12081: update operation not allowed on table "U1"."T1"


SQL> alter table t1 READ WRITE;

Table altered.

SQL> insert into t1 values (99);

1 row created.

SQL> commit;

Commit complete.

4. Tablespace Encryption

As we all know, in an Oracle database all the data are finally stored in the datafiles, what if the datafiles containing sensitive data were stolen? there are always chances that these datafiles can either be disseminated or attached to a different database and the sensitive data can be exposed or revealed.

In order to overcome this, Oracle introduced Transparent Data Encryption (TDE), in Oracle 10g version, a column of a table can be encrypted based on a (master) key, and that key is not stored within the same database, but externally in an Oracle wallet.

Now in Oracle 11g, you can encrypt an entire tablespace, i.e., a whole table or all the tables in an encrypted tablespace using tablespace encryption.

Tablespace encryption is supported on all data stored in an encrypted tablespace including internal large objects (LOBs) such as BLOBs and CLOBs. But data stored externally, like BFILE data is not encrypted.

If a table is created with BFILE column in an encrypted tablespace, then this BFILE column will not be encrypted, but the rest of the table will be encrypted.

Configure wallet location by setting the ENCRYPTION_WALLET_LOCATION parameter in sqlnet.ora:-

ENCRYPTION_WALLET_LOCATION=(SOURCE=(METHOD=FILE)(METHOD_DATA=(DIRECTORY=C:\oracle\ora11\admin\ORA11\wallet)))

Tablespace Level
ENCRYPTION algorithms supported in Oracle11g are 3DES168, AES128, AES192 and AES256

SYS> ALTER SYSTEM SET ENCRYPTION KEY IDENTIFIED BY "b1b1";

System altered.

SYS> CREATE TABLESPACE ENCR_TBS_1
   2     DATAFILE 'C:\ORACLE\ORADATA\ORA11\ENCR_TBS_01.DBF' SIZE 20M
   3     AUTOEXTEND ON NEXT 1M MAXSIZE 128M
   4     EXTENT MANAGEMENT LOCAL UNIFORM SIZE 1M
   5     SEGMENT SPACE MANAGEMENT AUTO
   6     ENCRYPTION
   7     DEFAULT STORAGE(ENCRYPT);

Tablespace created.

SYS> CREATE TABLESPACE ENCR_TBS_2
   2     DATAFILE 'C:\ORACLE\ORADATA\ORA11\ENCR_TBS_02.DBF' SIZE 20M
   3     AUTOEXTEND ON NEXT 1M MAXSIZE 128M
   4     EXTENT MANAGEMENT LOCAL UNIFORM SIZE 1M
   5     SEGMENT SPACE MANAGEMENT AUTO
   6     ENCRYPTION USING 'AES256'
   7     DEFAULT STORAGE(ENCRYPT);

Tablespace created.

SQL> select * from V$ENCRYPTED_TABLESPACES;

       TS# ENCRYPT ENC
---------- ------- ---
         5 AES128  YES
         6 AES256  YES

SYS> select tablespace_name,encrypted from dba_tablespaces;

TABLESPACE_NAME     ENC
----------------    ---
SYSTEM              NO
SYSAUX              NO
UNDOTBS1            NO
TEMP                NO
USERS               NO
TEST_TS1            NO
ENCR_TBS_1          YES
ENCR_TBS_2          YES

8 rows selected.

SQL> desc DBA_ENCRYPTED_COLUMNS
Name                Null?    Type
------------------- -------- -------------
OWNER NOT           NULL     VARCHAR2(30)
TABLE_NAME          NOT NULL VARCHAR2(30)
COLUMN_NAME         NOT NULL VARCHAR2(30)
ENCRYPTION_ALG               VARCHAR2(29)
SALT                         VARCHAR2(3)

SQL> col owner for a5
SQL> col table_name for a10
SQL> col column_name for a14
SQL> select * from DBA_ENCRYPTED_COLUMNS;

OWNER TABLE_NAME COLUMN_NAME    ENCRYPTION_ALG                SAL
----- ---------- -------------- ----------------------------- ---
U1    CUST       CRED_CARD_NUM  AES 192 bits key              NO
U1    CUST_2     CRED_CARD_NUM  3 Key Triple DES 168 bits key NO


SYS> CREATE TABLE CUST_1(
   2     cust_id VARCHAR2(4),
   3     cust_name VARCHAR2(10),
   4     cred_card_num NUMBER(16))
   5     TABLESPACE ENCR_TBS_1;

Table created.

Above table is created in an encrypted tablespace, hence all data in this table is stored encrypted on the disk.

SYS> insert into CUST_1 values (30,'Kate',1234567812345678);

1 row created.

SYS> insert into CUST_1 values (40,'Deep',5678123456781234);

1 row created.

SYS> commit;

Commit complete.

SYS> col CRED_CARD_NUM for 9999999999999999
SYS> select * from CUST_1;

CUST CUST_NAME  CRED_CARD_NUM
---- ---------- -----------------
30   Kate       1234567812345678
40   Deep       5678123456781234

SYS> alter system set encryption wallet close;

System altered.

C:\>cd C:\oracle\ora11\admin\ORA11\wallet

C:\oracle\ora11\admin\ORA11\wallet>C:\oracle\ora11\BIN\orapki wallet export -wallet . -dn "CN=oracle" -request oracle.req -pwd "b1b1"

Table Level
SQL> ALTER SYSTEM SET ENCRYPTION KEY IDENTIFIED BY "b1b1";

System altered.

SQL> ALTER SYSTEM SET ENCRYPTION WALLET OPEN IDENTIFIED BY "b1b1";
ALTER SYSTEM SET ENCRYPTION WALLET OPEN IDENTIFIED BY "b1b1"
*
ERROR at line 1:
ORA-28354: wallet already open

A wallet is automatically opened when you set or reset the master encryption key. Once you set the encryption, you will be see a file created in the above DIRECTORY location.

SQL> ALTER SYSTEM SET ENCRYPTION WALLET CLOSE ;

System altered.

SQL> ALTER SYSTEM SET ENCRYPTION WALLET OPEN IDENTIFIED BY "b1b1";

System altered.


Creating a table with an encrypted column using the default AES192 algorithm

SQL> conn u1/u1
Connected.
SQL> create table CUST (
   2     cust_id VARCHAR2(4),
   3     cust_name VARCHAR2(10),
   4     cred_card_num NUMBER(16) ENCRYPT
   5     );

Table created.

U1> desc cust
Name                Null?    Type
------------------- -------- --------------------
CUST_ID                      VARCHAR2(4)
CUST_NAME                    VARCHAR2(10)
CRED_CARD_NUM                NUMBER(16) ENCRYPT

U1> insert into CUST values (10,'Tom',1234567812345678);

1 row created.

U1> insert into CUST values (20,'Sam',5678123456781234);

1 row created.

U1> commit;

Commit complete.

U1> CREATE INDEX cust_card_idx ON CUST (cred_card_num);
CREATE INDEX cust_card_idx ON CUST (cred_card_num)
*
ERROR at line 1:
ORA-28338: cannot encrypt indexed column(s) with salt

U1> ALTER TABLE CUST MODIFY (cred_card_num ENCRYPT NO SALT);

Table altered.

U1> CREATE INDEX cust_card_idx ON CUST (cred_card_num);

Index created.

U1> col CRED_CARD_NUM for 9999999999999999
U1> select * from CUST;

CUST CUST_NAME  CRED_CARD_NUM
---- ---------- -----------------
10   Tom        1234567812345678
20   Sam        5678123456781234

Creating a table with an encrypted column using NO SALT parameter

U1> create table CUST_2 (
  2     cust_id VARCHAR2(4),
  3     cust_name VARCHAR2(10),
  4     cred_card_num NUMBER(16) ENCRYPT NO SALT
  5     );

Table created.

U1> insert into CUST_2 select * from CUST;

2 rows created.

U1> commit;

Commit complete.

U1> select * from CUST_2;

CUST CUST_NAME  CRED_CARD_NUM
---- ---------- -----------------
10   Tom        1234567812345678
20   Sam        5678123456781234

Adding Salt to an Encrypted Column

U1> ALTER TABLE CUST_2 MODIFY (cred_card_num ENCRYPT SALT);

Table altered.


Removing Salt to an Encrypted Column

U1> ALTER TABLE CUST_2 MODIFY (cred_card_num ENCRYPT NO SALT);

Table altered.

U1> ALTER TABLE CUST_2 REKEY;

Table altered.

U1> ALTER TABLE CUST_2 REKEY USING '3DES168';

Table altered.


Creating a table with an encrypted column using 3DES168 algorithm

create table CUST_3 (
    cust_id VARCHAR2(4),
    cust_name VARCHAR2(10),
    cred_card_num NUMBER(16) ENCRYPT USING '3DES168'
    );

Adding and modifying encrypted columns

ALTER TABLE CUST_3 ADD (cust_addr VARCHAR2(15) ENCRYPT);

ALTER TABLE CUST_3 modify (cust_name ENCRYPT);


Disable Column Encryption

ALTER TABLE CUST_3 MODIFY (cust_name DECRYPT);