Saturday, February 21, 2009

How to run ddl statements within pl/sql

You can't simply run any DDL statements within PL/SQL. Running simply DDL will return PLS-00103 as below.

SQL> begin
2 create table t(a number);
3 end;
4 /

create table t(a number);
*
ERROR at line 2:
ORA-06550: line 2, column 1:
PLS-00103: Encountered the symbol "CREATE" when expecting one of the following:
begin case declare exit for goto if loop mod null pragma
raise return select update while with <an identifier>
<a double-quoted delimited-identifier> <a bind variable> <<
close current delete fetch lock insert open rollback
savepoint set sql execute commit forall merge pipe

There are various methods by which you can run DDL statements within PL/SQL. Starting with oracle 8i you can run DDL statements by simply writing "execute immediate" and then DDL statements within single quote as below.

SQL> begin
2 execute immediate'create table t(a number)';
3 end;
4 /


PL/SQL procedure successfully completed.

SQL> desc t
Name Null? Type
------ ------ -------------
A NUMBER

If you are inside a procedure then simply execute immediate will not enough to perform DDL operation. Execution of the procedure will return ORA-01031: insufficient privileges as below.

SQL> create or replace procedure p as
2 begin
3 execute immediate'create table t2(a number)';
4 end;
5 /


Procedure created.

SQL> exec p
BEGIN p; END;

*
ERROR at line 1:
ORA-01031: insufficient privileges
ORA-06512: at "ARJU.P", line 3
ORA-06512: at line 1

To overcome this error just add "grant create table to user_name" statement before actual DDL statements. Note that if you run your procedure as SYS user then this will not result error but to run as other user extra grant permission is needed before execution. Remember that it is very bad practice to use SYS user as normal operation.


SQL> create or replace procedure p as
2 begin
3 execute immediate'grant create table to arju';
4 execute immediate'create table t2(a number)';
5 end;
6 /

Procedure created.

SQL> exec p

PL/SQL procedure successfully completed.

SQL> desc t2
Name Null? Type
--------- --------- --------
A NUMBER

Another method is using of DBMS_SQL package.

SQL> CREATE OR REPLACE PROCEDURE dynamic_sql AS
2 v_cursor integer;
3 row_process integer;
4 BEGIN
5 v_cursor := DBMS_SQL.OPEN_CURSOR;
6 DBMS_SQL.PARSE(v_cursor, 'GRANT CREATE TABLE TO ARJU',DBMS_SQL.NATIVE);
7 row_process := DBMS_SQL.EXECUTE(v_cursor);
8 DBMS_SQL.PARSE(v_cursor, 'CREATE TABLE Test_SQL (col1 DATE)',DBMS_SQL.NATIVE);
9 row_process := DBMS_SQL.EXECUTE(v_cursor);
10 DBMS_SQL.CLOSE_CURSOR(v_cursor);
11 END;
12 /


Procedure created.

SQL> exec dynamic_sql

PL/SQL procedure successfully completed.

SQL> desc test_sql
Name Null? Type
----------------------------------------- -------- ----------------------------
COL1 DATE

No comments:

Post a Comment