Oracle Developer Tools for VS Code

The HR Employee table as seen from VS Code

This post shows you how to configure the Oracle Developer Tools extension for VS Code and then use it to query an existing table, create or alter database objects and execute PL/SQL.


The versions I have used are shown in brackets

  • Microsoft VS Code (1.35.1)
  • Oracle Database ( XE


Start VS Code and navigate to extensions then search for Oracle Developer Tools. At the time of writing the home page for this extension was:

Select install.


There are several methods of connecting to the database from VS Code, in this guide I will be using the tnsnames.ora approach.

Check where Oracle Developer Tools extension looks for the tnsnames.ora file by:

  • Selecting the Oracle Developer Tools extension in VS Code and selecting the manage icon.
  • Select Configure Extension Settings
  • Look for Config Files Location
  • If required amend the location to point to where the tnsnames.ora file is located.
  • Restart VS Code.

Connecting to the Oracle Database

Create a new file and from the lower status bar click Plain Text and then select Oracle-SQL and PLSQL (oraclesql).

Press F1 to open Command Palette and select Oracle:Connect from the drop down

Select New Connection using TNSNAMES.ORA

Select the alias name you wish to connect to

Select Non-Administrator

Enter user id and then press return. I connected as the HR user.

Enter password and then press return

Save connection info if desired

Provide profile name or press return for default name

Once you have successfully connected the VS Code status bar will show pertinent information:


Construct the SQL statement you want to execute. Using the schema name followed by a period to utilise intellisense to view and select available database objects.

To execute the statement you can use the CTRL + E keyboard shortcut or select the statement, right click and choose Execute Query. The results are displayed in a new tab.

This image has an empty alt attribute; its file name is hremployeesfromvscode.png

Create or alter database objects

Construct the statement required; CREATE TABLE, CREATE PACKAGE, ALTER USER…

Execute the statement using the same method used for querying. Once the statement has completed, the results are displayed in a new tab.

Table T created successfully

Executing PL/SQL

Executing PL/SQL is identical to the methods above; construct the statement and use CTRL + E to execute.

A limitation at the time of writing is that I have not yet found a way to inspect output from a call to dbms_output.put_line. So whilst I can see that the anonymous block has executed successfully, the expected output of “Hello World” is not shown.

  dbms_output.put_line('Hello World');

I will update this guide once I discover this feature or it becomes available.


Quickstart:Get Started with Oracle and VS Code

SQL Developer: New worksheet, new session?

SQL Developer loading. Yesterday.

Default Behaviour

The out of the box behaviour of SQL Developer is that SQL worksheets share the same connection.

What does that mean?

If you perform a insert, update or delete in one worksheet without issuing a commit, the result(s) can be viewed in another shared worksheet. This can be illustrated by the following example.

After launching SQL Developer and connecting to a database, I start two new SQL worksheets

The next two screen shots show that for both SQL worksheets that the table t is empty

Next using using the first worksheet, an insert into table t operation is performed. No commit has been issued.

Navigating to the second worksheet and querying the table again and the newly inserted row can be seen.

Unshared Connections

It is possible to open a SQL Worksheet with a dedicated database connection. In SQL Developer this is called an unshared connection.

From an existing worksheet the keyboard shortcut on Windows is CTL + SHIFT + N. This will only work from a shared worksheet. It is not possible to open a new unshared worksheet from an existing unshared worksheet.

The following screenshots demonstrates how an unshared connection differs from a shared connection.

Two shared SQL Worksheets: hr and hr~1 are started along with and one unshared: hr (Unshared). In the first worksheet I perform an insert operation which has not been committed.

Switching to the second shared worksheet, the uncommitted record is shown after querying the table.

Moving to the unshared connection and querying the table no row is returned.

The unshared worksheet is working as expected as a new session will not see uncommitted records.


Jeff Smith, the Oracle Product manager for SQL Developer has a superb blog where he shares many SQL Developer hints and tips. One of the posts
Opening Unshared Worksheets was the inspiration and source for this post.

The incremental commit Anti-pattern

This is a far more opinionated post than usual. It is not meant to inflammatory, my goal for this post is to have something tangible that I can point to the next time an Oracle Developer thinks they want or need to “do” incremental commits.

In this post an incremental commit is defined as code which commits a transaction but the cursor is kept open.  They are also known as a fetch across commit.

I encounter incremental commits in PL/SQL code that issues a commit inside a  loop such as the examples below:


CURSOR customers_cur
  SELECT columns
    FROM some_tables;
  FOR i in customers_cur
    -- doing something interesting with the row
    COMMIT; -- ARGH!

The commit may be decorated with variations of:

IF rows_processed > some_arbitary_number


IF mod(customers_cur%rowcount, v_commit_limit) = 0 

Why are they an Anti-Pattern?

They introduce side effects that the Developer is not aware of, usually a self inflicted ORA-01555 Snapshot too old exception.  I will come back to this in the final part of this post.

Why are Incremental commits used?

Over the years I have had many conversations with other Oracle Developers regarding the problems incremental commits cause. The common explanation I have heard for the introduction of incremental commits is that the developer didn’t want to “blow” the rollback segments.

I disagree with this. You should never commit inside a loop. You should commit when your transaction is complete and only then. If your rollback segments are too small to support your transactions then you need to work with your DBA and get them resized.

ORA-01555 Snapshot too old

I am going to spend the remainder of this post explaining why you will see this error when you perform an incremental commit. It will not be a deep dive into all the nuances of this exception just it’s relevance to incremental commits. The best explanation for ORA-01555 is this AskTom post which originally started some 18 years old. Much of what follows is distilled from this thread.

An ORA-01555 occurs when the database is unable to obtain a read consistent image. In order to obtain this information the database uses the rollback segment but if that information has been overwritten then the database can not use it and the ORA-01555 is raised. So what causes this information to be overwritten? In the context of incremental commits the fuse is lit when a commit is issued…

Here is the steps leading to this error taken from Oracle Support  Note:40689.1

1. Session 1 starts query at time T1 and Query Environment 50

2. Session 1 selects block B1 during this query

3. Session 1 updates the block at SCN 51

4. Session 1 does some other work that generates rollback information.

5. Session 1 commits the changes made in steps ‘3’ and ‘4’.
(Now other transactions are free to overwrite this rollback information)

6. Session 1 revisits the same block B1 (perhaps for a different row).

Now, Oracle can see from the block’s header that it has been changed and it is later than the required Query Environment (which was 50). Therefore we need to get an image of the block as of this Query Environment.

If an old enough version of the block can be found in the buffer cache then we will use this, otherwise we need to rollback the current block to generate another version of the block as at the required Query Environment.

It is under this condition that Oracle may not be able to get the required rollback information because Session 1’s changes have generated rollback information that has overwritten it and returns the ORA-1555 error.

I have marked the key point – 5. By issuing a commit you are saying I have finished with this data, other transactions feel free to reuse it. Except you haven’t finished with it and when you really need it, it will have been overwritten.

Edge Cases?

I am not aware of any edge cases that require incremental commits. If you know of any please let me know via the comments.


This post would not have been possible without the help from the following sources:

AskTom question Snapshot too old

Stackoverflow Question Commit After opening cursor

New book: Oracle Incident Response and Forensics: Preparing for and Responding to Data Breaches

Looks like the first technical book for 2018 I will be reading has already be decided. Pete Finnigan has a new book coming out in early January.


More details from the publishers, Apress can be found here.  At the time of this post there was no preview available. Fortunately the listing on Amazon does so you can check out the contents here.

I will add a further post once I have read it.

Is there more than one reason to use PL/SQL WHERE CURRENT OF ?

I can’t remember using the PL/SQL construct where current of  in code I have written so along with my usual article style of how use to use this feature, this is also an experiment to find out if there are any other reasons to use where current of.

The code examples in this post have been developed using the Oracle Database App Development VM for Oracle VirtualBox which at the time of this post was using Oracle database (Although nothing in this post is 12c specific)

First I create a table that can be used for the experiment

create table t
select *
from all_objects

With the table created, I then use it in the following example which I will explain below.  At this point I would like to say that I appreciate the example could be rewritten as a single SQL statement however I wanted to concentrate on illustrating the use of where current of  without an overtly complicated example where the point of this post is lost in a forest of code.


  cursor c 
  select t.object_name
    from t
   where t.object_type in ('PACKAGE', 'PACKAGE BODY')
     and t.owner = 'APEX_040200'
     for update of object_name; 

  ln_count pls_integer := 1;


  for i in c
    update t
       set t.object_name = 'X - ' || ln_count
     where current of c;
    ln_count := ln_count + 1;
  end loop;



At line 3 I declare a cursor that identifies the records of interest, which are the package specifications and bodies owned by the APEX user.  Note the use of the for update clause. This is mandatory when using where current of . If you remove it and try to run the example you will see the following error message

PLS-00404: cursor 'C' must be declared with FOR UPDATE to use with CURRENT OF

Moving on to the execution section,  for each iteration of the cursor for loop,  the object name is updated (to something not very useful!) and you can see at line 20 what I think is the primary benefit of using where current of is that instead of repeating the where clause used by the cursor I have used where current of c. So when the cursor has to change to return different records the only change that needs to be made is to the cursor.

The final part of the example is once the loop completes I release the lock on the table by committing the changes.

The primary benefit of where current of is the reduction in duplicated code which is a good thing but am I missing anything else? Please use the comments to let me know.


In this post I have demonstrated how to use the PL/SQL construct where current of along with what I believe is it’s primary benefit, the reduction of duplicated code.


The inspiration for this post came from Steven Feuerstein’s book, Oracle PL/SQL Programming  5th Edition.


The auditing capabilities of Flashback Data Archive in Oracle 12c.

The goal of this post is to build a prototype that demonstrates the auditing capabilities of Flashback Data Archive in Oracle 12c.

Although the documentation mentions that Flashback Data Archive provides the ability to track and store transactional changes to a table I was struggling to see how this functionality actually worked and what audit information was available hence my need to build something that I could test drive.

This post is not a deep dive into Flashback Data Archive for that I would refer you to the landing page of Flashback Data Archive within the documentation.

The prototype was developed using the pre-built developer app vm for virtual box which at the time of writing used Oracle database version

The goal of the demo is show how a table is audited for changes, the audit will show who changed the record and when the change was made.

Creating the prototype is split into the following steps:

  1. Create a new user (optional).
  2. Creation of a table that you wish to audit changes to.
  3. Creation of the Flashback Data Archive objects.
  4. Creation of a new context and the dependent package.
  5. Executing DML statements against the table of interest.
  6. Viewing the audit information.

Create a new user (optional).

Logging on as a user with SYSDBA role, create a new user called: fda_user

create user fda_user identified by fda_user;
alter user fda_user quota unlimited on users;

fda_user is then given the following grants:

grant create table to fda_user;
grant alter user to fda_user;
grant alter session to fda_user;
grant create session to fda_user;
grant create any context to fda_user;
grant create procedure to fda_user;

Creation of a table that you wish to audit changes to.

For this prototype I am using a copy of the employees table owned by the HR user. The command below was run using whilst logged in with the SYSDBA role.

create table fda_user.employees as select * from hr.employees;

Creation of the Flashback Data Archive objects.

Still logged in as a user with SYSDBA role create a new tablespace and allow the fda_user to utilise it.

create tablespace fda2 datafile 'FDA2.dbf' size 1M autoextend on next 1M;

alter user fda_user quota unlimited on fda2; 

The next step is to create the Flashback Data Archive. In this example the audit information will be kept for 1 year and then automatically purged.

create flashback archive fda_one_year_data tablespace fda2 quota 1G retention 1 year;

Next the fda_user is granted permissions in order to utilise Flashback Data Archive.

grant flashback archive on fda_one_year_data to fda_user;

grant execute on dbms_flashback_archive to fda_user;

In the file step with the sysdba role, the table that is to be audited, employees is pointed to the Flashback Data Archive that was created earlier.

alter table fda_user.employees flashback archive fda_one_year_data;

Creation of a new context and the dependent package.

Log in to the database as the fda_user create the following context and PL/SQL package spec and body. This will used to assign who made the changes to the Employees table what those changes where.

CREATE OR REPLACE CONTEXT employee_context USING employee_ctx_api;

  PROCEDURE set_value (p_name  IN VARCHAR2,
                       p_value IN VARCHAR2);

END employee_ctx_api;

  PROCEDURE set_value (p_name IN VARCHAR2,
                       p_value IN VARCHAR2)
    dbms_session.set_context('employee_context', p_name, p_value);
  END set_value;

END employee_ctx_api;

For the sake of keeping the example on track the context and dependent package has been created in the same schema but in a production environment both the context and package would live in a different schema.

With this step, the required set up and configuration of Flashback Data Archive is now complete.

Executing DML statements against the table of interest.

In the following statements, a call is made to dbms_session and the package used by our context to record who is making the change and the action they are undertaking. This is then followed by the insert, update or delete statement.




  insert into employees
    TO_DATE('01-JAN-1978', 'DD-MON-YYYY'),






 update employees e
    set e.salary = 100009
  where e.employee_id = 9999;





 delete from employees
 where employee_id = 9999;



Viewing the audit information

With committed changes to the Employees table the audit information can be viewed using a Flashback Table Query such as the following:

SELECT employee_id,
       versions_operation vo,
       DBMS_FLASHBACK_ARCHIVE.get_sys_context(versions_xid, 'USERENV','SESSION_USER') AS session_user,
       DBMS_FLASHBACK_ARCHIVE.get_sys_context(versions_xid, 'USERENV','CLIENT_IDENTIFIER') AS client_identifier,
       DBMS_FLASHBACK_ARCHIVE.get_sys_context(versions_xid, 'employee_context','action') AS action
FROM   employees
WHERE  employee_id = 9999
ORDER BY versions_startscn;

Reviewing the query results shows a record being inserted, updated and finally deleted along with who did it (session_user and client_identifier columns), when it was done (versions_starttime column) and what was done (action column). Although this last column is not really useful as the information is already provided by the versions_operation (vo column) in the screenshot but is included as an example of what can be recorded.



In this post I have shown how you can build a prototype to see if the Audit capabilities of Flashback Data Archive would work with your existing application.


The inspiration for this post came from two sources. First was Connor McDonald’s superb presentation on Flashback Data Archive at the 2015 UKOUG conference and Tim Hall’s fantastic and generous site

DBMS_UTILITY.FORMAT_ERROR_BACKTRACE and the perils of the RAISE statement

Since dbms_utility.format_error_backtrace has been available from Oracle 10g this isn’t another what it ishow to use it post. Instead I will be taking this opportunity to discuss a nuance of dbms_utility.format_error_backtrace that you may not be aware of.

dbms_utility.format_error_backtrace reports the call stack back to the exception or the last raise statement which if you are not aware of could catch you out.

A quick word on the examples that follow, I am not proposing you should use this functionality in its raw format as I have done here. I believe that for production code calls to dbms_utility.format_error_backtrace should be encapsulated within your exception handling package.

The following code creates 3 procedures. procedure a calls b and b calls c. Within procedure c an exception is raised. There is no intermediate exception handling and the exception passes back to procedure a which makes a call to dbms_utility.format_errror_backtrace.

create or replace procedure a
 dbms_output.put_line('In procedure a');
 when no_data_found then
end a;

create or replace procedure b
 dbms_output.put_line('In procedure b');
end b;

create or replace procedure c
 dbms_output.put_line('In procedure c');
end c;

When procedure a is run, the following results are observed:


In procedure a
In procedure b
In procedure c
ORA-06512: at "HR.C", line 5
ORA-06512: at "HR.B", line 5
ORA-06512: at "HR.A", line 5

The error stack shows the exception started on line 5 (line 24) . Excellent, when things go wrong we can track the problem down to the line number! However procedure b needs to change and the developer, Gary Careless makes the required enhancements, one of the changes is the introduction of a new exception handling block that includes a RAISE statement.

The amended version of procedure b is now:

create or replace procedure b
 dbms_output.put_line('In procedure b');
 -- lots of new functionality here
 -- new exception handler for the new functionality
 when others then
 -- do something here and re-raise the exception
end b;

Now when procedure a is run again we see the following:


In procedure a
In procedure b
In procedure c
ORA-06512: at "HR.B", line 11
ORA-06512: at "HR.A", line 5

Oh no! we have lost the line number where the exception occurred. Instead of displaying that the exception was raised by line 5 of procedure c as it did in the first example, the callstack reports the exception location is now at the the location of the RAISE statement within procedure b!

To get the accurate output from dbms_utility.format_error_backtrace you need to call it

  • In the exception section that first raised the exception


  • Call it from the outermost PL/SQL block and ensure that the intermediate routines do not raisere raise the exception.

The location of exception handling within an application is a project wide decision which should be agreed before development begins. However if your error handling package includes a call to dbms_utility.format_error_backtrace then you should keep this nuance in mind.