![]() | Oracle Locking mechanisms |
- locks prevent destructive interactions that incorrectly update data or incorrectly alter underlying data structures, between transactions accessing shared data.
- Two types: exclusive locks and share locks.
- Oracle's default locking mechanisms ensures data concurrency, data integrity, and statement-level read consistency.
- A row is locked only when modified by a writer.
- A writer of a row blocks a concurrent writer of the same row.
- A reader never blocks a writer.(except: SELECT .. FOR UPDATE)
- A writer never blocks a reader.
Lock modes: level of restrictiveness x degree of data concurrency
- The less restrictive the level, the more available the data is for access by other users.
- Exclusive lock mode:
- Prevents the resource from being shared. Obtained for data modification.
- The first transaction to lock a resource exclusively is the only transaction that can alter the resource until the exclusive lock is released.
- Share lock mode:
- Allows resource to be shared. Multiple users reading data can share the data, holding share locks to prevent concurrent access by a writer who needs an exclusive lock.
- Several transactions can acquire share locks on the same resource.
- If a
SELECT ... FOR UPDATE
selects a single table row, the transaction acquires (a) an exclusive row lock and (b) a row share table lock. - The row lock allows other sessions to modify any rows other than the locked row, while the table lock prevents sessions from altering the structure of the table.
- Oracle Database never escalates locks
DML_LOCKS
(init.ora)Default: Derived: 4 * TRANSACTIONS (assumes an average of 4 tables referenced for each transaction)
Modifiable: No
Range: 20 to unlimited
Automatic Locks |
- DML Lock
- also called data lock. Guarantees integrity of data concurrently accessed by multiple users.
- They are either Row Locks (TX) or Table Locks (TM).
-
DML_LOCKS
(init.ora): determines the maximum number of DML locks (one for each table modified in a transaction). You might need to increase it if you use explicit locks. - DDL Locks
- Protects the definition of a schema object while an ongoing DDL operation acts on or refers to the object.
- Users cannot explicitly request DDL locks.
- Exclusive DDL lock: prevents other sessions from obtaining a DDL or DML lock.
- Share DDL lock: prevents conflicting DDL operations, but allows similar DDL operations.
- Breakable Parse Locks
- Held by a SQL statement or PL/SQL program unit for each schema object that it references. Acquired so that the associated shared SQL area can be invalidated if a referenced object is altered or dropped.
- A parse lock is acquired in the shared pool during the parse phase of SQL statement execution. The lock is held as long as the shared SQL area for that statement remains in the shared pool.
DML Locks | |
---|---|
ROW LOCK (TX) |
|
TABLE LOCK (TM) |
|
- System Locks: Latches, Mutexes, and Internal locks
- Latches:
- Serializes access to memory structures. Protect shared memory resources from corruption when accessed by multiple processes. [ (a) Concurrent modification by multiple sessions; (b) Being read by one session while being modified by another session; (c) Deallocation (aging out) of memory while being accessed. ]
- i.e. while processing a salary update of a single employee, the database may obtain and release thousands of latches
- Increase in latching ==> decrease in concurrency. (i.e.: excessive hard parse operations create contention for the library cache latch.)
- V$LATCH: contains detailed latch usage statistics for each latch, including the number of times each latch was requested and waited for.
- Mutex (Mutual exclusion object)
- similar to a latch, but whereas a latch typically protects a group of objects, a mutex protects a single object.
- Internal Locks
- Dictionary cache locks, file and log mgmt locks, Tablespace and Undo segment locks)
Manual data Locks: overriding default |
LOCK TABLE
SELECT FOR UPDATE
clauseSET TRANSACTION
with theREAD ONLY
orISOLATION LEVEL SERIALIZABLE
option
On Isolation Levels |
---|
ALTER SESSION SET ISOLATION_LEVEL = {SERIALIZABLE | READ COMMITTED | READ ONLY}
|
LOCK TABLE
- explicitly locks one or more tables in a specified lock mode.
- The lock mode determines what other locks can be placed on the table.
- A table lock never prevents other users from querying a table, and a query never acquires a table lock
- When a LOCK TABLE statement is issued on a view, the underlying base tables are locked
LOCK TABLE employees, departments IN EXCLUSIVE MODE NOWAIT;
- MODE: [ NOWAIT | WAIT n |
] - NOWAIT: error if lock is not available immediately
- WAIT n: wait up to n secs
- <blank>: wait indefinitely to acquire the lock
what type of lock to use (check here) |
---|
|
Transactions, TCL, and Isolation Levels |
Autonomous transactions |
Using SELECT... FOR UPDATE |
- SELECT FOR UPDATE selects the rows of the result set and locks them.
- Enables you to base an update on the existing values in the rows, because it ensures that no other user can change those values before you update them.
- You can also use SELECT FOR UPDATE to lock rows that you do not want to update
- By default, SELECT FOR UPDATE waits until the requested row lock is acquired. To change this behavior, use the
[ NOWAIT | WAIT | SKIP LOCKED ]
. - When SELECT FOR UPDATE is associated with an explicit cursor, the cursor is called a FOR UPDATE cursor.
set serveroutput on declare my_emp_ln employees.last_name%type; my_emp_id number; my_job_id varchar2(10); my_sal number(8,2); newsal number(8,2); -- declare a FOR UPDATE cursor cursor c1 is select employee_id, last_name, job_id, salary from employees for update; begin open c1; loop fetch c1 into my_emp_id, my_emp_ln, my_job_id, my_sal; If my_job_id = 'SA_REP' then newsal := my_sal*1.12; -- update only the rows locked by the cursor -- identified through the "WHERE CURRENT OF" clause. update employees set salary = newsal where current of c1; dbms_output.put_line('Emp '|| my_emp_ln || ': salary increased from '|| my_sal ||' to '|| newsal); end if; exit when c1%notfound; end loop; end; anonymous block completed Emp Tucker: salary increased from 10000 to 11200 Emp Bernstein: salary increased from 9500 to 10640 ...
Dynamic SQL: DBMS_SQL package
DBMS_SQL Package |
- Defines a SQL cursor number (PL/SQL Integer): Can be passed across call boundaries and stored.
- Provides an interface to use dynamic SQL to parse ANY DML or DDL statement using PL/SQL.
- When HAS to be used?
- - you don't have the complete SELECT list
- - you don't know what placeholds in a SELECT or DML must be bound
- When you CANNOT use DBMS_SQL?
- - Dynamic SQL stmt retrieves rows into records
- - If you need to use cursor attributes
(%FOUND, %ISOPEN, %NOTFOUND, or %ROWCOUNT)
- You can switch between native dynamic SQL AND DBMS_SQL package with:
- DBMS_SQL.TO_REFCURSOR function
- DBMS_SQL.TO_CURSOR_NUMBER function
Oracle Call Interface (OCI) x DBMS_SQL Package
- The ability to use dynamic SQL from within stored procedures generally follows the model of the Oracle Call Interface (OCI).
- Addresses (also called pointers) are NOT user-visible in PL/SQL.
- The OCI uses bind by address. DBMS_SQL package uses bind by value.
- With DBMS_SQL you must call VARIABLE_VALUE to retrieve the value of an OUT parameter for an anonymous block, and you must call COLUMN_VALUE after fetching rows to actually retrieve the values of the columns in the rows into your program.
- The current release of the DBMS_SQL package does not provide CANCEL cursor procedures.
- Indicator variables are not required, because NULLs are fully supported as values of a PL/SQL variable.
SYS.DBMS_SQL Subprograms |
---|
|
New security regime: Oracle 11gR1
- Stricter than in previous versions
- Checks are made when binding and executing.
- Failure lead to
ORA-29470: Effective userid or roles are not the same as when cursor was parsed
Execution Flow:
- OPEN_CURSOR
- PARSE
- BIND_VARIABLE or BIND_ARRAY
- DEFINE_COLUMN, DEFINE_COLUMN_LONG, or DEFINE_ARRAY
- EXECUTE
- FETCH_ROWS or EXECUTE_AND_FETCH
- VARIABLE_VALUE, COLUMN_VALUE, or COLUMN_VALUE_LONG
- CLOSE_CURSOR
i.e. -- Procedure uses DBMS_SQL package to perform SELECT and DML statements. |
Task: Delete all employees of a given deparmtent who earn more than a given value.
(A) DEL_EMP procedure is composed of the three parts below:
(1) Perform a dynamic SELECT to show the number of records that will be deleted
(2) Perform the dynamic DML.
(3) Perform a dynamic SELECT to show that the records were indeed deleted.
(B) an anonymous block calls del_emp procedure
CREATE OR REPLACE PROCEDURE del_emp (dept in number, salary in number) as cursor_dml integer; cursor_select integer; rows_processed integer; v_numemp integer; sel_str varchar2(500); dml_str varchar2(500); ignore integer; BEGIN -- Part 1: Select number BEFORE DML statement -- (1) Open cursor for SELECT. cursor_select := dbms_sql.open_cursor; sel_str := 'Select count(*) nuemp from employees ' || ' where department_id = :d'; -- (2) Parse SQL statement dbms_sql.parse(cursor_select, sel_str, dbms_sql.native); -- (3) Bind variables dbms_sql.bind_variable(cursor_select, ':d', dept); sel_str := 'Select count(*) nuemp from employees ' || ' where department_id = '|| to_char(dept); dbms_output.put_line('Select is: ' || sel_str); -- (4) use define_column to specify the variables that -- are to receive the SELECT values, much the way an -- INTO clause does for a static query. dbms_sql.define_column(cursor_select, 1, v_numemp); -- (5) call the execute function to run STMT ignore := dbms_sql.execute(cursor_select); -- (6) Use fetch_rows to retrieve the query results. -- Each successive fetch retrieves another set of rows, -- until the fetch is unable to retrieve anymore rows. -- If SELECT returns only ONE row, you may prefer to use -- EXECTUVE_AND_FETCH instead. If dbms_sql.fetch_rows(cursor_select) > 0 then dbms_sql.column_value(cursor_select, 1, v_numemp); end if; dbms_output.put_line('Num emp in dept '|| to_char(dept) || ' before delete: ' || to_char(v_numemp)); -- (7) Close the cursor. dbms_sql.close_cursor(cursor_select); -- Part 2: Now proceed with the DML Statement dml_str := 'delete from employees where department_id = :d' || ' and salary > :x'; cursor_dml := dbms_sql.open_cursor; dbms_sql.parse(cursor_dml, dml_str, dbms_sql.native); dbms_sql.bind_variable(cursor_dml, ':d', dept); dbms_sql.bind_variable(cursor_dml, ':x', salary); rows_processed := dbms_sql.execute(cursor_dml); dbms_output.put_line('Num rows deleted: ' || rows_processed); dbms_sql.close_cursor(cursor_dml); -- Part 3: Select the number AFTER the DML statement cursor_select := dbms_sql.open_cursor; sel_str := 'Select count(*) nuemp from employees ' || ' where department_id = :d'; dbms_sql.parse(cursor_select, sel_str, dbms_sql.native); dbms_sql.bind_variable(cursor_select, ':d', dept); dbms_sql.define_column(cursor_select, 1, v_numemp); sel_str := 'Select count(*) nuemp from employees ' || ' where department_id = '|| to_char(dept); dbms_output.put_line('Select is: ' || sel_str); dbms_sql.define_column(cursor_select, 1, v_numemp); ignore := dbms_sql.execute(cursor_select); If dbms_sql.fetch_rows(cursor_select) > 0 then dbms_sql.column_value(cursor_select, 1, v_numemp); end if; dbms_output.put_line('Num emp in dept '|| to_char(dept) || ' after delete: ' || to_char(v_numemp)); dbms_sql.close_cursor(cursor_select); EXCEPTION when others then if dbms_sql.is_open(cursor_select) then dbms_sql.close_cursor(cursor_select); end if; if dbms_sql.is_open(cursor_dml) then dbms_sql.close_cursor(cursor_dml); end if; -- Use Function SQLCODE to return error number dbms_output.put_line('Error code: ' || to_char(sqlcode)); -- Use Function SQLERRM to return error Message dbms_output.put_line('Error Message: ' || to_char(sqlerrm)); -- Starting on 10gR2, Oracle recommends that you use -- DBMS_UTILITY.FORMAT_ERROR_STACK() instead of SQLERRM. -- While SQLERRM is limited to 512bytes, the other function is not. dbms_output.put_line('Error stack: ' || dbms_utility.format_error_stack()); -- You can also use DBMS_UTILITY.FORMAT_ERROR_BACKTRACE() -- this function lists the complete error stack, including the line number -- that generated the exception. dbms_output.put_line('Error backtrace: ' || dbms_utility.format_error_backtrace()); END del_emp;
(B) Anonymous block calls DEL_EMP.
set serveroutput on declare nemp integer; begin del_emp(110, 6000); commit; end; / anonymous block completed Select is: Select count(*) nuemp from employees where department_id = 110 Num emp in dept 110 before delete: 2 Num rows deleted: 2 Select is: Select count(*) nuemp from employees where department_id = 110 Num emp in dept 110 after delete: 0
-- If the table employees is dropped or renamed, execution of del_emp will fail:
set serveroutput on declare nemp integer; begin del_emp(110, 6000); commit; end; / anonymous block completed Error code: -942 Error Message: ORA-00942: table or view does not exist Error stack: ORA-00942: table or view does not exist Error backtrace: ORA-06512: at "SYS.DBMS_SQL", line 1199 ORA-06512: at "DEVEL.DEL_EMP", line 17
(15) Dynamic SQL
[ Oracle PL/SQL ] |
"From all old seamy throats of elders, musty books, I've salvaged not a word." (Cormac McCarthy) |
Dynamic SQL statements are not embedded in your source program and checked at compile time.
Instead, they are stored in character strings that are input to, or built by, the program at runtime.
(i.e. dynamic SQL lets you create a procedure that operates on a table whose name is not known until runtime.)
Programming methodology for generating and running SQL statements at run time. Good for:
- Writing general-purpose and flexible programs like ad hoc query systems
- Writing programs that must run DDL statements
- When number and datatypes of IN/OUT variables are unknown at compilation time
- When the full text of a SQL stmt needs to be obtained at run-time only.
- i.e. a SELECT stmt that includes an identifier (a table name) that is unknown at compile time.
- i.e. a WHERE clause in which the number of subclauses is unknown at compile time.
How to write dynamic SQL ? (two ways)
- (1) Native dynamic SQL: PL/SQL language feature for building and running dynamic SQL statements
- (2)
DBMS_SQL
package: , an API for building, running, and describing dynamic SQL statements
Native dynamic SQL x DBMS_SQL package:
- native dynamic SQL: Faster, and more readable (even more when optimized by compiler)
- Native dynamic SQL: requires complete specification of IN/OUT vars (number and datatype) at compile time.
- Switch between native dynamic SQL and DBMS_SQL package using
DBMS_SQL.TO_REFCURSOR and DBMS_SQL.TO_CURSOR_NUMBER.
Using EXECUTE IMMEDIATE (Advantages over DBMS_SQL)
- DBMS_SQL: Oracle 8 and earlier
- EXECUTE IMMEDIATE: Oracle 8i and later
- Native dynamic SQL:
- Integral part of the SQL language that is built into Pl/SQL, thus making it simpler to use and faster than the DBMS_SQL package.
- Native dynamic SQL also supports the usage of object types and collections not supported by the DBMS_SQL package
- Faster than DBMS_SQL because it parses, binds, and executes the statements immediately.
- DBMS_SQL requires calls to procedures and functions.
Question: Can I use TCL or DDL within a PL/SQL Block? A: No. You HAVE to use DYNAMIC SQL for that. (Native Dyn SQL or DBMS_SQL). Static SQL is limited to DML (SELECT, INSERT, UPDATE, DELETE, MERGE), TCL (COMMIT, ROLLBACK, SAVEPOINT, SET TRANSACTION) and LOCK TABLE. |
Native Dynamic SQL: EXECUTE IMMEDIATE |
EXECUTE IMMEDIATE
: Builds and runs a dynamic SQL statement in a single operation.- If dynamic_sql_stmt has a
RETURNING INTO
clause, using_clause can contain only IN bind arguments. The bind arguments in theRETURNING INTO
clause are OUT bind arguments by definition. - When using dynamic SQL, beware of SQL injection, a security risk.
- The value of bind_argument cannot be TRUE, FALSE, or NULL
Type of dynamic SQL statement | USE of EXECUTE IMMEDIATE |
---|---|
SELECT returns at most one row | OUT-bind arguments (defines): in the INTO clause.IN-bind arguments: in the USING clause. EXECUTE IMMEDIATE SELECT ... INTO <OUT-vars> USING <bind_arg>; |
SELECT returns multiple rows | OUT-bind arguments: in the BULK COLLECT INTO clause. IN-bind arguments: in the USING clause.EXECUTE IMMEDIATE SELECT ... BULK COLLECT INTO <OUT-vars> USING <bind_arg>; |
DML with RETURNING INTO clause | IN-bind arguments: in the USING clause. OUT-bind arguments: in the RETURNING INTO clause. |
DMLw/o RETURNING INTO clause | all bind arguments in the USING clause |
Using dynamic SQL with EXECUTE IMMEDIATE:
-- create procedure to insert new record on departments table create or replace procedure new_dept (deptid in out number, dname in varchar2, mgrid in varchar2, locid in varchar2) as begin deptid:= departments_seq.nextval; insert into departments ( department_id, department_name, manager_id, location_id) values (deptid, dname, mgrid, locid); end; -- Use dynamic SQL to call the procedure new_dept set serveroutput on declare plsql_block varchar2(500); new_deptid number(4); new_dname varchar2(30) := 'Advertising'; new_mgrid number(6) := 200; new_locid number(4) := 1700; numdep number; begin select count(*) into numdep from departments; dbms_output.put_line('# depts: ' || numdep); -- enter the dynamic SQL statement -- note that the statement is complete. Only dynamic binding of the -- procedure parameters occur. -- note that the SQL stmt has placeholders for bind arguments. plsql_block := 'begin new_dept(:a, :b, :c, :d); end;'; -- use EXECUTE IMMEDIATE to run the SQL stmt and specify the -- binding variables. EXECUTE IMMEDIATE plsql_block USING IN OUT new_deptid, new_dname, new_mgrid, new_locid; select count(*) into numdep from departments; dbms_output.put_line('# depts: ' || numdep); end; anonymous block completed # depts: 27 # depts: 28
![]() | Using SELECT, DDL and DML with Execute Immediate Using Conditional Compilation |
What the example below does (3 procedures):
(a) Check whether a table exists in the database (SELECT)
(b) DROP and Recreate or CREATE table test and GRANT access on the table to another user (DDL)
(c) Insert data on the created table (DML)
(1) Procedure
check_object
:(SELECT returns one row only):
Check whether a table named TESTE already exists in the database- procedure call: check_object('TESTE', 'TABLE');
CREATE OR REPLACE Procedure check_object (p_objname in varchar2, p_objtype in varchar2, p_created OUT boolean) IS query varchar2(200); vcount varchar2(40); BEGIN -- using SELECT with EXECUTE IMMEDIATE query := 'select count(*) from user_objects '|| 'where object_type = :b '|| 'and object_name = :c '; -- If the dynamic SQL statement is a SELECT statement that can return -- at most one row, put out-bind arguments (defines) in the INTO clause -- and in-bind arguments in the USING clause. EXECUTE IMMEDIATE query into vcount USING IN p_objtype, p_objname; IF vcount = 0 THEN $IF $$my_debug $THEN dbms_output.put_line(p_objtype || ' ' || p_objname || ' does not yet exist on the database.'); $END p_created := FALSE; ELSE $IF $$my_debug $THEN dbms_output.put_line(p_objtype || ' ' || p_objname || ' already exist on the database.'); $END p_created := TRUE; END IF; EXCEPTION When others then dbms_output.put_line('Error Procedure check_object'); dbms_output.put_line(sqlerrm); dbms_output.put_line(dbms_utility.format_error_backtrace()); END;
alter session set plsql_ccflags = 'my_debug:TRUE'; set serveroutput on declare v_created boolean; begin check_object('TESTE', 'TABLE',v_created); end; / Anonymous block completed TABLE TESTE already exist on the database.
(2) Procedure
create_table
:(DDL):
If table exists, drop table and recreate it.(DDL):
Grant SELECT on table TESTE to userA.- procedure call: cr_tbl('TRUE', 'create table TESTE (name varchar2(20), salary number)';');
- For the procedure to succeed, the procedure owner MUST have been granted the CREATE TABLE privilege directly, not via a role.
- Role privileges are not applied in procedures
CREATE OR REPLACE procedure create_table (p_created in boolean, p_stmt in varchar2) IS e_leave_drop exception; e_leave_create exception; stmt varchar2(200); v_created boolean; BEGIN -- USING DDL with EXECUTE IMMEDIATE IF p_created then -- table exist. Drop before creating. stmt := 'drop table teste'; begin execute immediate stmt; exception when others then dbms_output.put_line('Error dropping table'); dbms_output.put_line(sqlerrm); raise e_leave_drop; end; dbms_output.put_line('Table dropped.'); END IF; stmt := p_stmt; begin execute immediate stmt; exception when others then dbms_output.put_line('Error creating table'); dbms_output.put_line(sqlerrm); raise e_leave_create; end; dbms_output.put_line('Table teste created.'); v_created := TRUE; dbms_output.put_line('Calling check_object..'); check_object('TESTE', 'TABLE', v_created); stmt := 'grant select on teste to userb'; execute immediate stmt; dbms_output.put_line('grant select completed'); EXCEPTION when e_leave_drop then dbms_output.put_line('leaving procedure...'); when e_leave_create then dbms_output.put_line('leaving procedure...'); END;
alter procedure check_object compile; alter session set PLSQL_CCFLAGS = 'my_debug:TRUE'; set serveroutput on declare stmt varchar2(200); vcreated boolean default TRUE; begin stmt := 'create table UserA.teste (name varchar2(20), salary number)'; create_table(vcreated, stmt); end; / Anonymous block completed Table dropped. Table teste created. Calling check_object.. TABLE TESTE already exist on the database. grant select completed
(3) Procedure
insert_tbl
:(DML):
Insert values on table TESTE- If the dynamic SQL statement is a DML statement WITHOUT a RETURNING INTO clause, other than SELECT, put all bind arguments in the USING clause.
CREATE OR REPLACE procedure insert_tbl (p_name in varchar2, n in integer, p_salinit number) as vsal number; stmt varchar2(200); vname varchar2(20); BEGIN stmt := 'INSERT into TESTE values (:b, :c)'; vsal := p_salinit; vname := p_name; for i in 1..n loop vname := vname || to_char(i); vsal := 10000 + i; execute immediate stmt USING vname, vsal; dbms_output.put_line('Inserted row '|| i); end loop; EXCEPTION when others then dbms_output.put_line('Insert error...'); dbms_output.put_line(sqlerrm); END;
set serveroutput on begin insert_tbl('Mary', 4, 5000); end; / anonymous block completed Inserted row 1 Inserted row 2 Inserted row 3 Inserted row 4 SQL> Select * from teste; NAME SALARY -------------------- ---------------------- Mary1 10001 Mary12 10002 Mary123 10003 Mary1234 10004
What the example below does:
(a) Check the columns of a given table in the data dictionary (Mulitple-row SELECT: BULK COLLECT INTO)
(b) Delete a row from the table. Returns data from the deleted row using RETURNIG clause (DML)
(1) Procedure
list_tbl
(SELECT):
Get column name list withBULK COLLECT INTO
.- If the dynamic SQL statement is a SELECT statement that can return MULTIPLE rows,
put out-bind arguments (defines) in theBULK COLLECT INTO
clause and in-bind arguments in the USING clause. - You CANNOT use bind values to pass in the names of schema objects, such as table names or column names.
- SO, names of schema objects have to be added to the dynamic sql statement, instead of passed as bind vars.
CREATE OR REPLACE procedure list_tbl (p_tblname in varchar2) as type t_recdata is RECORD (nm varchar2(20), salary number); type t_aadata is TABLE of t_recdata index by pls_integer; vdata t_aadata; type t_colnm is table of varchar2(20) index by pls_integer; vcolnm t_colnm; vb varchar2(30); stmt varchar2(200); BEGIN stmt := 'SELECT column_name FROM user_tab_columns '|| 'WHERE table_name = :b'; vb := p_tblname; EXECUTE IMMEDIATE stmt BULK COLLECT INTO vcolnm USING p_tblname; for i IN vcolnm.first..vcolnm.last loop if i = 1 then vb := vcolnm(i); else vb := vb || ', '|| vcolnm(i); end if; end loop; dbms_output.put_line('columns are: '|| vb); -- You CANNOT use bind values to pass in the names of schema objects, -- such as table names or column names. -- SO, names of schema objects have to be added to the dynamic sql -- statement, instead of passed as bind vars. stmt := 'select '|| vb || ' from teste'; BEGIN EXECUTE IMMEDIATE stmt BULK COLLECT INTO vdata; EXCEPTION when others then dbms_output.put_line('Execute immediate: error SELECT'); dbms_output.put_line(sqlerrm); END; for i IN vcolnm.first..vcolnm.last loop dbms_output.put(vcolnm(i) || ' -- '); end loop; dbms_output.new_line(); for i in vdata.first..vdata.last loop dbms_output.put_line(vdata(i).nm || ' '|| vdata(i).salary); end loop; END list_tbl;
set serveroutput on begin list_tbl('TESTE'); end; / columns are: NAME, SALARY NAME -- SALARY -- Ximenes12 10002 Ximenes123 10003
(2) Procedure
delete_table
:- procedure call: delete_table('Mary');
- If the dynamic SQL statement is a DML statement with a RETURNING INTO clause,
put in-bind arguments in the USING clause and out-bind arguments in the RETURNING INTO clause.
set serveroutput on CREATE OR REPLACE procedure del_tbl(p_name in varchar2) as type t_recdata is RECORD (nm varchar2(20), salary number); vrec t_recdata; stmt varchar2(200); BEGIN stmt := 'DELETE FROM teste '|| 'WHERE name = :b ' || 'RETURNING name, salary INTO :c, :d'; execute immediate stmt USING IN p_name returning into vrec; dbms_output.put_line('Deleted rec: ' || vrec.nm || ' ' || vrec.salary); dbms_output.new_line; dbms_output.put_line('Listing table...'); list_tbl('TESTE'); EXCEPTION when others then dbms_output.put_line(sqlerrm); dbms_output.put_line(dbms_utility.format_error_backtrace()); END;
set serveroutput on begin del_tbl('Mary123'); end; / anonymous block completed Deleted rec: Mary123 10003 Listing table... columns are: NAME, SALARY NAME -- SALARY -- Mary1 10001 Mary12 10002 Mary1234 10004
Running all together:
set serveroutput on declare vcreated boolean default TRUE; begin check_object('TESTE', 'TABLE', vcreated); create_table(vcreated, 'create table teste (name varchar2(20), salary number)'); insert_table('Ximenes', 3, 9700); list_tbl('TESTE'); delete_table('Ximenes1'); end; nonymous block completed TABLE TESTE already exist on the database. Table dropped. Table teste created. Calling check_object.. TABLE TESTE already exist on the database. grant select completed Inserted row 1 Inserted row 2 Inserted row 3 columns are: NAME, SALARY NAME -- SALARY -- Ximenes1 10001 Ximenes12 10002 Ximenes123 10003 Deleted rec: Ximenes1 10001 Listing table... columns are: NAME, SALARY NAME -- SALARY -- Ximenes12 10002 Ximenes123 10003
![]() | Native Dynamic SQL: OPEN FOR, FETCH and CLOSE |
![]() | DBMS_SQL Package |
Other examples using DBMS_SQL |
SQL Injection |
Subscribe to:
Posts (Atom)