4 Oracle PLSQL Transactions Dynamic SQL Debugging m4 Slides
4 Oracle PLSQL Transactions Dynamic SQL Debugging m4 Slides
!!
Pankaj Jain
!
@twit_pankajj
What is Dynamic SQL?
!
SQL Statement Known at Runtime
Dynamic SQL
CREATE OR REPLACE FUNCTION get_count(
Static SQL p_where VARCHAR2) RETURN NUMBER
CREATE OR REPLACE FUNCTION IS
get_count(p_act_id accounts.act_id%TYPE) l_count NUMBER;
RETURN NUMBER IS l_select VARCHAR2(100) := 'SELECT COUNT(*) ';
l_count NUMBER; l_from VARCHAR2(60) := 'FROM orders ';
BEGIN l_query VARCHAR2(200);
SELECT COUNT(*) BEGIN
INTO l_count l_query := l_select ||
FROM orders l_from ||
WHERE order_act_id = p_act_id; p_where;
RETURN l_count; EXECUTE IMMEDIATE l_query INTO l_count;
END get_count;
RETURN l_count;
END get_count;
Static vs Dynamic SQL
Faster Slower
Do Not Place Anything in
This Space
(Add watermark during editing)
Note: Warning will not appear
during Slide Show view.
Dynamic Queries
!
Dynamic Sorts
!
Dynamic Subprogram Invocation
!
Common Uses Dynamic Optimizations
!
DDL
!
Frameworks
!
Varying Table Definitions
Invoking Dynamic SQL
!
Native Dynamic SQL DBMS_SQL
Why Use Native Dynamic SQL?
!
Easier Faster
!
EXECUTE IMMEDIATE <dynamic_sql_string>
!
[INTO {select_var1[, select_var2].. | record }
!
[USING [ IN | OUT | IN OUT ] bind_var1
! [, [ IN | OUT | IN OUT ] bind_var2]…]
▪ Create Objects
!CREATE OR REPLACE PROCEDURE create_table (p_table_name VARCHAR2,
p_table_columns VARCHAR2) IS
!BEGIN
EXECUTE IMMEDIATE 'CREATE TABLE '|| p_table_name || p_table_columns;
END create_table;
□
EXEC create_table(
'ORDERS_QUEUE_CA',
'(queue_id NUMBER,queue_act_id NUMBER,queue_item_id NUMBER)'
);
▪ Direct Grants
User demo
! CREATE OR REPLACE PROCEDURE create_table_procedure(p_table_name VARCHAR2,
p_table_columns VARCHAR2) IS
! BEGIN
EXECUTE IMMEDIATE 'CREATE TABLE '|| p_table_name || p_table_columns;
END create_table_procedure;
!
! CREATE ROLE create_table_role; EXEC
GRANT CREATE TABLE TO create_table_role; create_table_procedure(‘ORDERS_QUEUE_WA',
! GRANT create_table_role TO demo; '(queue_id NUMBER,queue_act_id
NUMBER,queue_item_id NUMBER)');
!
ORA-01031: insufficient privileges
!
GRANT CREATE TABLE TO demo;
□ 12c
Do Not Place Anything in
This Space
GRANT create_table_role to create_table_procedure;
(Add watermark during editing)
Note: Warning will not appear
during Slide Show view.
DDL Operations
▪ Drop Objects
!
CREATE OR REPLACE PROCEDURE drop_table (p_table_name VARCHAR2) IS
! BEGIN
EXECUTE IMMEDIATE 'DROP TABLE '|| p_table_name;
END drop_table;
□
EXEC drop_table('ORDERS_QUEUE_CA');
□
!
EXECUTE IMMEDIATE l_query INTO l_count;
!
RETURN l_count;
END get_count;
/
DECLARE DECLARE
l_cnt NUMBER; l_cnt NUMBER;
BEGIN BEGIN
l_cnt := get_count('ORDERS'); l_cnt := get_count('ITEMS');
DBMS_OUTPUT.PUT_LINE('Count is '||l_cnt); DBMS_OUTPUT.PUT_LINE('Count is '||l_cnt);
END; END;
/ / Do Not Place Anything in
This Space
(Add watermark during editing)
Note: Warning will not appear
during Slide Show view.
Single Row Selects
SELECT COUNT(*) FROM orders WHERE SELECT COUNT(*) FROM orders WHERE
order_act_id = 1; order_item_id = 2;
DECLARE DECLARE
l_cnt NUMBER; l_cnt NUMBER;
BEGIN BEGIN
l_cnt := get_order_count('order_act_id',1); l_cnt := get_order_count('order_item_id',2);
DBMS_OUTPUT.PUT_LINE('Count is '||l_cnt); DBMS_OUTPUT.PUT_LINE('Count is '||l_cnt);
Do Not Place Anything in
END; END; This Space
/ / (Add watermark during editing)
Note: Warning will not appear
during Slide Show view.
Passing Schema Object Names
!
Execute Immediate Ref Cursors
Ref Cursors
LOOP
FETCH cur_account INTO l_act_id;
EXIT WHEN cur_account%NOTFOUND;
UPDATE accounts SET act_bal = act_bal - 10 WHERE act_id = l_act_id; Do Not Place Anything in
COMMIT; This Space
END LOOP; (Add watermark during editing)
END apply_fees; Note: Warning will not appear
during Slide Show view.
Fetching in Records
▪ Insert Statement
!CREATE OR REPLACE PROCEDURE insert_record (p_table_name VARCHAR2,
p_col1_name VARCHAR2,
p_col1_value NUMBER,
! p_col2_name VARCHAR2,
p_col2_value NUMBER )
□ BEGIN
EXECUTE IMMEDIATE 'INSERT INTO '||p_table_name || '('||
p_col1_name||' , '||
p_col2_name||
' ) '||
‘ VALUES( :col1_value,:col2_value)'
USING p_col1_value, p_col2_value;
COMMIT;
END insert_record;
!
!
!
Do Not Place Anything in
! This Space
(Add watermark during editing)
Note: Warning will not appear
□ during Slide Show view.
Passing Nulls in Dynamic SQL
!
DECLARE
….
!
BEGIN
! EXECUTE IMMEDIATE 'INSERT INTO '||p_table_name || '('||
p_col1_name||' , '||
p_col2_name||
□
' ) '||
‘ VALUES( :col1_value,:col2_value)'
USING p_col1_value, NULL;
….
DECLARE
….
l_null VARCHAR2(1);
BEGIN
EXECUTE IMMEDIATE 'INSERT INTO '||p_table_name || '('||
p_col1_name||' , '||
p_col2_name||
' ) '||
Do Not Place Anything in
‘ VALUES( :col1_value,:col2_value)'
This Space
USING p_col1_value, l_null; (Add watermark during editing)
…. Note: Warning will not appear
during Slide Show view.
Update Statements
!
!
CREATE OR REPLACE PROCEDURE update_record (p_table_name VARCHAR2,
p_col1_name VARCHAR2,
p_col1_value NUMBER,
! p_where_col VARCHAR2,
p_where_value NUMBER )
□ BEGIN
EXECUTE IMMEDIATE 'UPDATE '||p_table_name || ' SET '||
p_col1_name||' = :p_col1_value '||
' WHERE '|| p_where_col ||’ = :p_where_value ‘
USING p_col1_value, p_where_value;
COMMIT;
END update_record;
!
!
DECLARE
l_item_value items.item_value%TYPE := 100;
!
l_act_id accounts.act_id%TYPE := 1;
l_cust_id customers.cust_id%TYPE;
□ l_act_bal accounts.act_bal%TYPE;
!
BEGIN
!
EXECUTE IMMEDIATE 'UPDATE accounts SET act_bal = act_bal - :p_item_val '||
' WHERE act_id = :p_act_id RETURNING act_cust_id,act_bal INTO :l_id, :l_bal '
USING l_item_value, l_act_id RETURNING INTO l_cust_id,l_act_bal;
COMMIT;
END;
!!
l_act_bal accounts.act_bal%TYPE;
BEGIN
! !
EXECUTE IMMEDIATE 'UPDATE accounts SET act_bal = act_bal - :p_item_val '||
□
' WHERE act_id = :p_act_id RETURNING act_cust_id,act_bal INTO :l_id, :l_bal '
USING l_item_value, l_act_id RETURNING INTO l_cust_id,l_act_bal;
COMMIT;
END;
DECLARE
l_item_value items.item_value%TYPE := 100;
l_act_id accounts.act_id%TYPE := 1;
l_cust_id customers.cust_id%TYPE;
l_act_bal accounts.act_bal%TYPE;
!
BEGIN
!
EXECUTE IMMEDIATE 'UPDATE accounts SET act_bal = act_bal - :p_item_val '||
' WHERE act_id = :p_act_id RETURNING act_cust_id,act_bal INTO :l_id, :l_bal ' Do Not Place Anything in
USING l_item_value, l_act_id, OUT l_cust_id, OUT l_act_bal; This Space
(Add watermark during editing)
COMMIT; Note: Warning will not appear
END; during Slide Show view.
Delete Statements
!
!
!
CREATE OR REPLACE PROCEDURE delete_table (p_table_name VARCHAR2)
□ BEGIN
EXECUTE IMMEDIATE ' DELETE FROM ' ||p_table_name;
COMMIT;
END delete_table;
!
! DECLARE
l_sql VARCHAR2(500);
l_inout NUMBER := 1;
! l_out NUMBER := 2 ;
l_num NUMBER := 1;
BEGIN
! l_sql := ' BEGIN :l_inout := :l_inout + :l_num *2 ; ' ||
' :l_out := :l_num / 2 ; END; ' ;
! EXECUTE IMMEDIATE l_sql USING IN OUT l_inout, l_num, OUT l_out;
END;
!
▪ Semi-Colon After End
▪ Duplicate Placeholders
! Do Not Place Anything in
This Space
! (Add watermark during editing)
Note: Warning will not appear
during Slide Show view.
Length of SQL String
!
▪ Maximum Parse Length Pre 11g : 64K
! DECLARE
l_sql1 VARCHAR2(32767):= '………. ';
! l_sql 2 VARCHAR2(32767):= '………. ‘;
BEGIN
EXECUTE IMMEDIATE l_sql1|| l_sql2;
! END;
▪ CLOB Support
DECLARE
! l_sql CLOB;
l_inout NUMBER := 1;
! l_out NUMBER := 2 ;
l_num NUMBER;
BEGIN
□ l_sql := ' BEGIN :l_inout := :l_inout + :l_num *2 ; ' ||
' :l_out := :l_num / 2 ; END; ' ; Do Not Place Anything in
This Space
EXECUTE IMMEDIATE l_sql USING IN OUT l_inout, l_num, OUT l_out; (Add watermark during editing)
END; Note: Warning will not appear
during Slide Show view.
Executing Procedures
□
DECLARE
l_act_id accounts.act_id%TYPE := 1;
l_act_bal accounts.act_bal%TYPE;
l_tier NUMBER;
BEGIN
EXECUTE IMMEDIATE ' CALL calculate_tier(:act_id,:act_bal,:tier) '
USING l_act_id, IN OUT l_act_bal, OUT l_tier;
END;
DECLARE
l_act_id accounts.act_id%TYPE := 1;
l_act_bal accounts.act_bal%TYPE;
l_tier NUMBER;
BEGIN Do Not Place Anything in
EXECUTE IMMEDIATE ' BEGIN calculate_tier(:act_id,:act_bal,:tier); END; ' This Space
USING l_act_id, IN OUT l_act_bal, OUT l_tier; (Add watermark during editing)
Note: Warning will not appear
END; during Slide Show view.
Execute Functions
DECLARE
l_act_id accounts.act_id%TYPE := 1;
l_act_bal accounts.act_bal%TYPE;
l_tier NUMBER;
l_out NUMBER;
BEGIN
EXECUTE IMMEDIATE ' BEGIN :l_out := get_tier(:act_id,:act_bal,:tier); END; '
USING OUT l_out, l_act_id, IN OUT l_act_bal, OUT l_tier;
END;
LOOP
FETCH cur_account INTO l_act_id;
EXIT WHEN cur_account%NOTFOUND;
UPDATE accounts SET act_bal = act_bal - 10 WHERE act_id = l_act_id;
COMMIT;
END LOOP; Do Not Place Anything in
END apply_fees; This Space
(Add watermark during editing)
Note: Warning will not appear
EXEC apply_fees('act_id ' , 1, '/*+ PARALLEL(accounts, 3) */' ); during Slide Show view.
Specifying Session Control Statements
!
! !
ALTER SESSION SET NLS_DATE_FORMAT = 'DD-MON-RRRR';
!
□
CREATE OR REPLACE PROCEDURE set_date_format(p_format VARCHAR2) IS
BEGIN
EXECUTE IMMEDIATE ‘ALTER SESSION SET NLS_DATE_FORMAT = '||p_format;
END;
!
EXEC set_date_format('''DD-MON-RRRR''');
!
CREATE OR REPLACE PROCEDURE create_table (p_table_name VARCHAR2,
! p_table_columns VARCHAR2)
AUTHID CURRENT_USER IS
! BEGIN
EXECUTE IMMEDIATE 'CREATE TABLE '|| p_table_name || p_table_columns;
END create_table;
□
! db2 instance
! create public database link db1link connect to demo identified by demo
using 'db1';
!
db2 instance
□
CREATE OR REPLACE PROCEDURE delete_table (p_table_name VARCHAR2,
p_dblink VARCHAR2) IS
BEGIN
EXECUTE IMMEDIATE 'DELETE FROM '||p_table_name||'@'||p_dblink;
COMMIT;
END update_record;
!▪ Statement Modification
!
CREATE OR REPLACE PROCEDURE delete_order(p_column VARCHAR2,
! l_query VARCHAR2(200);
p_value VARCHAR2 ) IS
BEGIN
□
DELETE l_query := 'DELETE FROM orders WHERE ' || DELETE
FROM orders p_column ||' = '||p_value ; FROM orders
WHERE DBMS_OUTPUT.PUT_LINE(l_query); WHERE
order_act_id = 1; ! order_act_id = 1
EXECUTE IMMEDIATE l_query; OR 1=1;
END delete_order;
/
!▪ Statement Injection
! CREATE OR REPLACE PROCEDURE calc(p_condition VARCHAR2) IS
l_block VARCHAR2(1000);
BEGIN
! l_block :=
' BEGIN IF '||p_condition||' = ''A'' THEN proc1; END IF; END; ';
□ EXECUTE IMMEDIATE l_block;
…
END calc;
BEGIN
BEGIN
IF 1=1 THEN
IF 'A' = 'A' THEN
DELETE FROM ORDERS;
proc1;
END IF;
END IF;
IF 'A' = 'A' THEN proc1;
END;
END IF;
END;
!▪ Validations
! CREATE OR REPLACE PROCEDURE calc(p_condition VARCHAR2) IS
l_block VARCHAR2(1000);
malicious_attack EXCEPTION;
! BEGIN
IF INSTR(p_condition, ';') > 0 THEN RAISE malicious_attack; END IF;
□ IF INSTR(p_condition, ‘END IF;’) > 0 THEN RAISE malicious_attack; END IF;
l_block :=
' BEGIN IF '||p_condition||' = ''A'' THEN proc1; END IF; END; ';
EXECUTE IMMEDIATE l_block;
…
EXCEPTION
WHEN malicious_attack THEN
DBMS_OUTPUT.PUT_LINE('Suspicious Input '||p_condition);
RAISE;
END calc;
Statement Injection
EXEC calc('1=1 THEN DELETE FROM orders; END IF; IF ''A'''); Do Not Place Anything in
This Space
(Add watermark during editing)
Note: Warning will not appear
during Slide Show view.
What is Dynamic SQL?
!
Usage
Summary !
Execute Immediate
!
SQL Injection