How To Connect your Node.js app in Docker to your Oracle Database

In this post I’ll cover how to make a connection from a Node.js application in a Docker container to your Oracle Database in three different scenarios.

  • Typical Database connection.
  • Database inside a different Docker container.
  • Oracle Autonomous Transaction Processing Cloud Database.

Simple Test App

When attempting something new, I find it’s best to make sure all of the pieces that are not part of the new thing, are as simple as possible.

For my examples I will be using a small Node.js application that:

  • Connects to the Oracle Database.
  • Runs a simple query.
  • Prints the results to the console.

Create a new file named dbConfig.js to set the database connection information.

Create a new file named server.js used to test the connection.

Install the node-oracledb driver. (If you have any questions about the node-oracledb driver, you can find the answers here.)

Create environment variables for the connection information.  (Replace my values with yours)

Test the Node.js application.  You should see something similar to the following.

Create a Docker Container for the Node.js app

Create a Dockerfile

Build the image

Now that you have an image you’ll run a container and to connect it to:

Typical Oracle Database
The container will run, execute the query and stop.  You should see something similar to this output.
An Oracle Database inside a Docker Container

In a previous post I walked through how to setup both an ORDS instance and an Oracle XE instance in Docker Containers.  Follow through the section showing how to create an Oracle XE Database in a Docker container.

When you followed the steps in that post you should have also created a Docker Network.

You’ll use that same network to connect from the Node.js container to the Oracle XE container.

First, change your NODE_ORACLEDB_CONNECTIONSTRING environment variable to use the Oracle XE container name.

Now when you run a new docker container you will attach it to the same Docker Network as the Oracle XE container.

The container will run, execute the query and stop.  You should see something similar to this output.

Since both containers are using the same Docker network, you do not need to open the port when you run the Oracle XE container.  This is useful if you’d like to keep your database private inside the Docker environment.

Oracle Autonomous Transaction Processing Cloud Database

After you create an Oracle ATP Cloud Database you’ll need to download the credentials file and extract it into a secure location.

For this database, you will be using an entry in the tnsnames.ora file to make the database connection.  Change the NODE_ORACLEDB_CONNECTIONSTRING environment variable to use the tnsnames entry:

Before you run the container, you need to modify the sqlnet.ora file found in the credentials directory.  Change the wallet location to the value that will be mapped inside the Docker container.

When you run the new container for the node app you will map a volume from the directory where you extracted your credentials file to the internal container directory.  Mapping a volume makes sure that there is not a copy of the credential files inside the Docker container.

Finally, when you run the new container, you will add an additional environment variable defining where the tns admin information is located.

The full command looks like this:

The container will run, execute the query and stop.  You should see something similar to this output.

I used the same docker image for all of the examples

You may have noticed that you only built the Docker image once at the beginning of the post.  The application in the Docker image uses environment variables to connect to the database.  This allows you to run the same application in one or more containers and each container can connect to different Oracle Databases without having to rebuild the image.

Oracle REST Data Services on Autonomous Transaction Processing Database

Whenever I give a presentation, write a blog post or make a video I like to run all of my examples and demos locally and on an Oracle Cloud instance.  I keep a Virtual Box machine or Docker Container ready on my laptop, just in case I can’t get to the internet, but for speed and dependability, you just can’t beat a cloud instance.

I like to have some automation scripts handy to create and destroy my environments and depending on what I’m doing that can sometimes take a while.

So when Oracle’s Autonomous Transaction Processing Database was released I was excited by how fast I could spin up a new instance.  It takes a few minutes instead of around an hour for other options.  Oracle wanted to make sure ATP was solid, so they initially launched with a limited feature set and new features have been making their way into Oracle’s Autonomous Transaction Processing Database almost every month.

At KScope19 it was announced that Oracle REST Data Services is now available on ATP.

I was scheduled to give my ‘Creating REST APIs Is Fast, Easy, and Secure with Oracle REST Data Services‘ talk on Wednesday and I like to live dangerously, so I decide (Tuesday afternoon) to convert my demos over to ORDS on ATP.  I figured worst case, if I couldn’t figure it out I’d just use my Docker container.

It’s going to be hard… right?

I already had a couple of ATP instances that I use for stuff and things.  Since I wanted to do a live demo, I decided to spin up a new instance just in case I expose anything that could be used to get in.  It took under 5 minutes to fully create and start up a brand new ATP database.  After that, I downloaded my Client Credentials (Wallet) and connected with SQL Developer.  There are lots of examples for this part so I’ll move on to the new stuff.

New User

I try to do as little as possible as the Admin user so I created a rest_demo user with a couple of tables and a view.

Create a test API

Then I used the SQL Developer ‘Auto REST’ feature to REST enable the schema and a table.   (PL/SQL exported below in case you want to try it.)

Get the URI

Now I just needed the URI to test my new service.  Here are the steps:

  1. Log into your Oracle Cloud Dashboard.
  2. From the menu, select ‘Autonomous Transaction Processing’.
  3. From the instance menu, select ‘Service Console’.

    Or, Click on your Instance Name then Click the ‘Service Console’ button.
  4. Click ‘Administration’.
  5. In the Rest Data Services box, click either button.
  6. Copy from the beginning of the URL up to and including ‘/ords/’
    https://someIdstuff-blaineords.adb.my-region-1.oraclecloudapps.com/ords/
    Ignore the rest.
Test it

For a simple fast test, I just used an internet browser with the following URI:
https://someIdstuff-blaineords.adb.my-region-1.oraclecloudapps.com/ords/api/cool_data

Well, that was easy.

To be honest I expected this to be a lot harder and that I’d have problems.  I ran through all of the demos for my presentation and they just worked, first try.

The thing I spent the most time on was re-checking everything.  Since it was so easy, I thought I had connected to one of my pre-existing cloud databases.

Go try it!

As always, don’t take my word for it, go try it yourself.

Here are some links to help get you going:

Quick and Easy Setup – Oracle Xe and ORDS Using Docker

In this post I’ll show you how to stand up a couple of Docker containers running Oracle Database Xe and Oracle REST Data Services.

I will assume you are familiar with using Docker.  If not checkout this getting started guide.

Required Downloads

Oracle docker-images repository

Oracle provides a GitHub repository with a log of great examples.  Clone repository into the directory where you want to work.

Oracle Xe

You can find more information about Oracle Xe at https://www.oracle.com/rest.

Download the installer and place it in the docker-images/OracleDatabase/SingleInstance/dockerfiles/18.4.0 directory.

I’ll be using oracle-database-xe-18c-1.0-1.x86_64.rpm .

Oracle Rest Data Services (ORDS)

You can find more information about ORDS at https://www.oracle.com/rest.

Download the installer and place it in the docker-images/OracleRestDataServices/dockerfiles directory.

I’ll be using ords-19.1.0.092.1545.zip .

ORDS runs in Java, so you’ll need a Java JRE.  Download the Server JRE and place it in the docker-images/OracleJava/java-8 directory.

I’ll be using server-jre-8u211-linux-x64.tar.gz .

Docker Network

We’ll be running the database and ORDS in separate docker containers.  Define a docker network that they will use to communicate.

Oracle Database Xe

Change into the docker-images/OracleDatabase/SingleInstance/dockerfiles/18.4.0 directory.  Make sure the Oracle Xe install file (oracle-database-xe-18c-1.0-1.x86_64.rpm)  is in this directory.

This directory contains a Dockerfile.xe ready for us to use.  Take a minute and read through the file to see what it is going to do.

Build the Oracle Database Docker Image

The repository includes a shell script (buildDockerImage.sh) that you can use to build the docker image for Xe and other Oracle Databases.

It can be found in the docker-images/OracleDatabase/SingleInstance/dockerfiles directory.  Instructions for using this script can be found here.

I won’t be using the shell script.

The shell script will generate and run something similar to the following command that I will use:
*Notice the dot at the end, this is not a typo.

You can find an explanation of the Docker Build parameters here.

If this command doesn’t work for you, try using the shell script.

Verify that your image was created:

You should see something like this:

Once you have created the docker image it’s time to

Create a Docker Container

The following command is similar to the command you’ll find on the GitHub repository, but I’ve added a ‘-d’ to run the container in detached mode and I’m not defining any data volumes so my data will not persist when I delete the container.

You can find more information on the docker run command parameters here.

This will take a few minutes.

You can watch the progress and troubleshoot any issues with with this command:
(You can use the container name or id.)

When the last line of the log looks like this, you are ready to proceed.

Verify that your container was created and is up:

You should see something like this:

Now try to connect to your new Oracle Xe Database.

To connect with SQLcl:

Oracle REST Data Services

Before we create the ORDS container, we need to create a Docker image with Oracle Linux 7 and a Java JRE installed.  We will use this as a base image to build on top of.

Oracle Linux 7 and Java JRE Base Image

Change into the docker-images/OracleJava/java-8 directory.  In there you will find a Dockerfile and the server-jre-8uXXX-linux-x64.tar.gz file you downloaded earlier.

Take a minute and read through the Dockerfile to see what it is going to do.

Run the following to build the image:
*Notice the dot at the end, this is not a typo.

We do not need to create a Docker container from this image.  We will only need the image as a base for the ORDS image.

Verify that your image was created:

You should see something like this:

Now we can create the ORDS image.

ORDS

Change into the docker-images/OracleRestDataServices/dockerfiles directory.  In there you will find a Dockerfile and the ords-19.1.0.092.1545.zip file you downloaded earlier.

Take a minute and read through the Dockerfile to see what it is going to do.

Pre-Checks

Verify that the docker network we created earlier is ready:

You should see something like this.

Make sure your Xe database is running with the docker ps  command above.

If the Xe database container is not started, start it with the following command:

Build the ORDS Docker Image

The repository includes a shell script (buildDockerImage.sh) that you can use to build the ORDS docker image.

It can be found in the docker-images/OracleRestDataServices/dockerfiles directory.  Instructions for using this script can be found here.

If you choose to run the shell script instead of the below command, and there is not a Checksum file included for the version of ORDS you are installing, use the -i 1 command line argument to ignore the check.

The shell script will generate and run something similar to the following:
*Notice the dot at the end, this is not a typo.

Verify that your image was created:

You should see something like this:

Now we can create the ORDS container.

Create an ORDS Docker Container

The following command is similar to the command you’ll find on the GitHub repository, but I’ve added a ‘-d’ to run the container in detached mode and I’m not defining any data volumes so my data will not persist when I delete the container.

Make sure that you set  -e ORACLE_HOST=oracleXe to the name you used for the Oracle Xe Database container you created above.  ORDS will not find your database if you use localhost.  The containers are basically separate servers running on the same network --network=OrdsXeNet .

The parameter -e ORACLE_PWD="Password1_One" is the SYS/SYSTEM password you used when you created the Oracle Xe Database above.

The parameter -e ORDS_PWD="ORDS_Password1"  will be used as the ORDS admin password.  It does not need to be the same as the database password.

Verify that your container was created and is up:

You should see something like this:

You should now have an Oracle Xe database up and running in one container and an ORDS instance running in the other.

Connect to your database and test that ORDS is properly installed and configured.  A quick way to tell using Oracle SQL Developer is:

  1. Create a new database user.
  2. Connect as that user.
  3. Right click on the connection.
  4. Look towards the bottom of the menu for “REST Services”.

Have fun creating your new REST modules!

How to build an Oracle Database Developer Toolbox with Vagrant

I like to experiment with a lot of different things and of course, a significant number of my projects require an Oracle database and Oracle Rest Data Services (ORDS).

I often use a VirtualBox VM for my project in order to keep it’s environment “clean”.

This guide will walk through the steps to set up a VM with Oracle Xe and ORDS installed and ready to go.

Vagrant

Vagrant automates the creation of a new VM from scratch.  I can use a Vagrantfile and some shell scripts to spin up a VM quickly, saving me time and hard drive space compared to keeping a bunch of VMs laying around that I would need to maintain.  You can learn more on the Introduction to Vagrant page.

Prerequisites

Before we get started, install VirtualBox and Vagrant.  After you’ve finished, download the following.

Downloads

Versions

As of the date that I’m writing this post, I’m using the following versions of the above downloads.  This walkthrough should work if you use these versions, if you use different versions you may have to make adjustments.

  • Oracle Database 18c Express Edition 18.4.0.0.0 (18c)
  • Java JRE – jre-8u201-linux-x64.rpm
  • ORDS – ords-18.4.0.354.1002.zip
  • https://github.com/oracle/vagrant-boxes – Latest commit eb4983d on Dec 7, 2018
Working in the host and virtual machine environments

Some of the following steps will be run inside the VM others in the Host environment.  Check the title of the code blocks to make sure you’re in the correct environment.

To open an SSH connection to your new VM run the following command in the project directory created in the next step.

Create the Toolbox

Make a copy of the 18.4.0-XE directory.

When you are working in the virtual machine, the /vagrant/ directory will be mapped to the dbDevToolbox directory on the host machine.

Edit dbDevToolbox/Vagrantfile

Change the name value

Open port 8080 for ORDS to use.

Create the VM and install Oracle Database XE

Run the following command to start the vagrant build process.

This may take a few minutes to run.  When it’s finished it will generate and display the system password, you’ll want to remember it.

At this point you have a new virtual machine with Oracle Xe installed and running.

Using your preferred SQL tool, test a database connection. (localhost:1521/xepdb1)

Optional: If you would prefer to set your own password, enter the following commands in a shell.  Replace ‘newPassword’ with the password you want to use.

Install the Jave Runtime Environment (JRE)
  • Switch to the root user.
  • Use the .rpm file to install java.
  • Check the java version.
  • Exit the root user.

You should see the following output.

java version “1.8.0_201”
Java(TM) SE Runtime Environment (build 1.8.0_201-b09)
Java HotSpot(TM) 64-Bit Server VM (build 25.201-b09, mixed mode)

Create the file dbDevToolbox/ords_params.properties

This will be used to configure ORDS.  Feel free to modify the settings for your environment.  If you change the port, remember to also change it in the Vagrantfile in the above step.

For an explanation of these and other settings, you can find the documentation here.

Install ORDS
  • Switch to the oracle user.
  • Unzip ORDS into the Oracle product directory.
  • Copy the above properties file into the ORDS directory.
  • Set the LD_LIBRARY_PATH environment variable.  This is needed in order to install ORDS with a bequeath connection.
  • Run a silent installation of ORDS using the above parameter file.
  • Exit the oracle user.

Autorun ORDS on boot

Create file dbDevToolbox/oracle-ords-18-4 using the following example.

If you decide to write your own, make sure ORDS does not attempt to start until after the database is fully running.  For example, in the below file I included ‘# Required-Start: oracle-xe-18c’.

  • Switch to root user.
  • Copy the above file to /etc/init.d/
  • Set the file permissions.
  • Add the configuration.
  • Set the configuration run levels.
  • Start ORDS.
  • Exit the root user.

Test

At this point, your VM should have both Oracle Database XE and ORDS installed and running.  If you’re already familiar with ORDS you should create a test module to make sure everything is working.

If you’re new to ORDS you can create the file dbDevToolbox/setupHr.sql.  This script will enable the HR user and create an ORDS module.

  • Switch to the oracle user.
  • Use SQL*Plus to run the above script.  Replace <YourPassword> with the sys password from the beginning of the post.
  • Exit the oracle user.
  • Use curl to test the REST service.

You should see the following output.

Automate

Creating a new VM with Oracle XE installed is already fully automated.  Now, I’m going to show you how to roll the ORDS steps into the Vagrantfile.

The below file collects all of the above steps into a single shell script.

Create the file dbDevToolbox/scripts/installOrds.sh with the following.

Edit dbDevToolbox/Vagrantfile

Provision the new script

Destroy the current VM and create a new one.

WARNING:  This will completely destroy the VM we created above and create a new one from scratch.  If you have made any changes you’d like to keep, make sure to back them up first.

  • Destroy the VM.
  • Confirm that you want to destroy the VM.
  • Create a new VM.
Test the new machine.

Future project virtual machines

For future projects you’ll only need to:

  • Make a copy of the dbDevToolbox directory with a new name.
  • Edit the Vagrantfile and modify the NAME entry.
  • Run the vagrant up command.

When you’re finished with the project use vagrant destroy to clean up.

Resources

How to secure your ORDS service

Securing your Oracle Rest Data Services module only takes a couple of minutes.

As you can see in the video, this will be a fairly short how-to.

Assumptions

For this post, I’m going to assume:

  • You’re able to use SQL Developer.
  • You already have an ORDS module created that you want to secure.
  • You have at least a basic understanding of Roles, Privileges, Authentication and Authorization.

Test the Existing Service

Before we begin, I’ll test the current service with a curl command.

This returns a response with a status of “HTTP/1.1 200 OK” and a JSON object with an array of items.

 

Secure Your Service

First up I will create a Role and a Privilege that I’ll use to secure my service.

Create a Role
  1. Expand the schema connection and REST Data Services, if they are not already expanded.
  2. Right click on Roles.
  3. Click New Role…

  1. Enter a name for the role.  I’m using bc-role.
  2. Click Apply.

Create a Privilege
  1. Expand the schema connection and REST Data Services, if they are not already expanded.
  2. Right click on Privileges.
  3. Click New Privilege…

  1. Enter a name for the privilege.  I’m using bc-priv.
  2. Select the new role ‘bc-role’.
  3. Select the ORDS Module.  I’m using my Beacon module.
  4. Click Apply.

Be aware, this will only add security to the specific modules you select in the bottom section.  If you were to add a new module later and you want it to be covered with this privilege, you need to remember to edit this privilege and select it in the ‘Protect Modules’ selector.

Alternatively, you can use the ‘Protect Resources’ tab to apply security based on a URI pattern.

For my examples, I’m working from a VirtualBox VM and I have used ‘beacon’ as my schema alias.  So the base for all of my REST services in this schema would be

I entered the URI pattern

This will protect all ORDS services for this schema.  If I wanted to use this method to protect just an admin URI template in my beacon module (the full URI is https://localhost:8080/ords/beacon/beacon/admin), I would use a URI pattern like this

There are many more complex patterns you could use for your services, but for this post, I am only protecting the Beacon module so I am using the first example.

Test
This now returns a response with a status of “HTTP/1.1 401 Unauthorized”.
 

Access Your Service

I want to set up my ORDS module so it can be accessed by a third party application so I’ll set up OAuth 2.

Create an OAuth 2 Client

Using the OAUTH PL/SQL Package, I will create an OAuth2 client using the privilege I created above.

Then I will grant the new OAUTH2 client the role I created above.

Test

In order to generate an access token, I need to get my client id and secret from the user_ords_clients table.

When you create an OAuth2 client, a REST service ‘/oauth/token’ is created for you that your applications can use to generate a bearer token using the above id and secret.

Notice that this token expires in 3600 seconds.  Once it expires, you would repeat the above call to generate a new token.

Now that I have an access_token I can include it in the Authorization header to access my secure ORDS service.  Notice that since this is a Bearer token I set the Authorization value to ‘Bearer <<my token>>’.

Example Usage

The following is an example of how to make secure REST calls from an external application after you’ve followed the above steps.

On the application server

Store the client_id and client_secret in environment variables.

In your application

Summary

Setting up security on your ORDS modules is quick and fairly easy.

OAuth2 is just one way to access your secured ORDS modules.  If you’d like to setup Basic Auth checkout this post by Jeff Smith.

Console the ORDS documentation for other examples and a much more in-depth explanation.

How to use an SSH Tunnel in Oracle Developer Cloud Service Build Jobs

Oracle Developer Cloud Service is a hosted team development and delivery platform with all kinds of tools to help your team be more efficient.  In this post, I will cover how to use an SSH tunnel to connect to your database in a build job.

This is current as of October 2018.

Connecting to your database through an SSH tunnel is fairly simple and you won’t have to ask your network admin to open a port in your firewall and or load balancers.

If you’re connecting to an Oracle Cloud Database it should be pre-configured to allow database connections through an SSH tunnel.  If not check with your server admin for assistance.

If you’re not familiar with SSH tunnels you can find out more here.

However, if you’re reading this post you probably just want to skip to the how-to so let’s get started.

Configure your build job

Open your Developer Cloud Service project, click the ‘Build’ tab and select the build you want to work with.

Click the ‘Configure’ button

Authorized SSH Keys

You will need an SSH Key that has been authorized to connect to the database server.  I recommend generating a new key that will only be used from your DevCs builds.  Name the new key pair something that will let you know it’s for this DevCs project.

Helpful links:

If you generated a new key pair named DevCsProj1, you should have two files.  The file without an extension ‘DevCsProj1’ is your private key and the file with .pub ‘DevCsProj1.pub’ is your public key.

Add a build environment configuration

Select the ‘Build Environment’ tab, click ‘Add Build Environment’ and choose ‘SSH Configuration’.

  1. Open the private key (from above) in a text editor, copy everything in the file and paste it in the ‘Private Key’ file text area.
  2. You can do the same for the ‘Public Key’ text area but it is not required for this example.
  3. If you created your keys with a password, enter the password in the ‘Pass Phrase’ field.
  4. For a little extra security, you could get the public key for your Database Server and enter it in the ‘SSH Server Public Key’ text area.  This will ensure that your build job only connects to that server and will help protect against connecting to a different server if the IP address is re-assigned.  This field is optional.
  5. Check ‘Create SSH tunnel’.
  6. Enter the SSH username.  (This is not a database user, this is an authorized SSH user on the server.)
  7. If you’d rather use an SSH user/password instead of an SSH Key file, you could enter the password in the password field.  I leave it blank in order to only connect with the keys.
  8. Enter the port you want to use on the DevCs side of the tunnel in ‘Local Port’.
  9. If you leave ‘Remote Host’ empty it will default to localhost.  The remote host is used on the other side of the tunnel to make the connection as if you were on that machine.  Since I’m intending to connect to the database that is on the same server that I’m SSH’d into I can use localhost.  If I wanted to connect to a different server from that side of the tunnel, I could enter the address for the other remote server.  For example, if I had a server that was only accessible from inside of a network that includes the SSH server, I can SSH into the network and the tunnel will end on the other internal server.
  10. If you’d like to re-use your keys for other SSH commands you can check ‘Setup files in ~/.ssh for command-line ssh tools’.  It is not necessary for this example.

The ‘Connect String’ displayed at the bottom shows the ssh command DevCs will use to create the tunnel.

ssh -L localhost:1521:localhost:1521 opc@129.111.111.111

Let’s break it down:

  • Create a local ssh tunnel.  ssh -L
  • On the local DevCs server map to the ‘Local Port’ value.  localhost:1521 (The first one)
  • Once connected to the SSH server map the tunnel end to ‘Remote Host’:’Remote Port’.   localhost:1521 (The second one)
  • Make the SSH connection as ‘Username’@’SSH Server’.  opc@129.111.111.111

OK, time to use the new tunnel.  I’ll use a SQLcl Builder.

Add / Edit a builder

Select the Builders tab, click Add Builder and choose SQLcl Builder.

If you’ve used a SQLcl builder before this will all be the same, except for the connect string.

  1. Enter your database username in the ‘Username’ field.
  2. Enter your database password in the ‘Password’ field.
  3. If you’re connecting to a database that is using wallet credentials such as Oracle Exadata Express Cloud Service, enter the location of your Credentials file.  I’m not so I will leave it empty.
  4. Since I now have an SSH tunnel in place I will connect to the local (DevCs server) end of the tunnel and use the ‘Local Port’ value from the SSH Configuration.  //localhost:1521/[servicename].  Even if I had defined a remote host and/or port other than localhost / 1521 in the tunnel configuration, I would still use localhost:[Local Port].  The tunnel takes care of the mapping on the other end.
  5. Enter the SQL File or Inline SQL you want to run.
  6. Save the Job Configuration.

Run it

Click the ‘Build Now’ button and when you look at the console output you will see something similar to this.

  • SSH is set up.
  • The SSH tunnel is opened.
  • SQLcl executed my script.  (I did not enable any output in my script so none is displayed.)
  • SQLcl disconnects from my Database.
  • The SSH tunnel is closed.
  • The SSH environment is removed.

Once you’ve added an SSH Build Environment to your build job and tested it, you can start adding them to each Build Job you use a database connection in.  After that’s done you can close port 1521 on your Database server (assuming you don’t need it for other applications).

Oracle Developer Cloud Service is constantly being improved, so let me know in the comments if this guide becomes out of date and I will update it.

Join me at Oracle Open World 2018

Oracle Open World is almost here!

Oracle Open World and Oracle Code One will be happening together and I will be giving sessions in both, check out this list if you’d like to join me:

Monday

9:00 a.m. – 11:00 a.m. | Moscone West – Overlook 2A (HOL) – Along with Christopher Jones and Anthony Tuininga
Python and Oracle Database: Scripting for the Future – BYOL [HOL5052]
PLEASE NOTE: YOU MUST BRING YOUR OWN LAPTOP (BYOL) TO PARTICIPATE IN THE HANDS-ON LABS.
Get hands-on, and learn the features of the Python cx_Oracle interface for Oracle Database. Learn efficient techniques for connection management, statement handling, and more. If you want to use Python and Oracle Database, this session is for you. Basic programming skills in any language are required.Please review the prerequisite information here in preparation for the lab.

Tuesday

12:30 p.m. – 12:50 p.m. | The Exchange @ Moscone South – Theater 6
AskTOM Mini Lesson: Rapid REST Enablement with Oracle REST Data Services [THT6899]
In this session see how to REST-enable a database using Oracle REST Data Services. See the steps, including “auto REST-enabling” a table, creating a specific REST service using an Oracle REST Data Services wizard, and then exporting the SQL generated by these tools, which you can include in your deploy scripts and/or use to learn how to write your own REST services using only SQL. If there is enough time the session also includes a walk-through of the process of adding security to your new REST services. Leave this session with an understanding of how to quickly create REST services on your own database.

2:15 p.m. – 3:15 p.m. | Marriott Marquis (Yerba Buena Level) – Salon 3/4 – Along with Christopher Jones and Anthony Tuininga
Python and Oracle Database 18c: Scripting for the Future [HOL6329] Get hands-on and learn the features of the Python cx_Oracle interface for Oracle Database. In this session learn efficient techniques for connection management, statement handling, and more. If you want to use Python and Oracle Database, this session is for you. Basic programming skills in any language are required.

4:00 p.m. – 4:45 p.m. | Moscone West – Room 2010
DevOps Tools for Database Developers [DEV5055]
Are you still thinking about modernizing your database development process…someday…maybe? Do you have directories full of .sql files you use to build your application? You know that unit tests should be included as part of your build process, and you are going to start adding them…maybe next week? If you have an Oracle Cloud account, you may be surprised at what tools you already have access to and how easy it is to get started. This session takes a look at Oracle Developer Cloud Service. It discusses some of the included tools and explores mixing in some open source tools you can use to automate building and testing your applications. The sooner you get started, the more it will save you in the long run.

Thursday

2:00 p.m. – 2:45 p.m. | Moscone West – Room 3009
IoT for Oracle Database: Soldering, Python, and a Little PL/SQL [TRN4077]
Using way too much electricity and not quite sure where? Tracking usage is a great start, but analyzing data is easiest in a database. Building on the “Watch me make a Watt-watcher” project, this session begins with an overview of the steps and components used to assemble the hardware. Data ingestion to an Oracle Database Cloud is made straight forward with the Python cx_Oracle driver. Get an overview of other cx_Oracle features useful to IoT projects as well, and come away with the tools to track the data in your own projects and hopefully some new ideas. (But no electrical burns!)

My schedule could still change.  If it does, I’ll update this post.

If you can’t make my sessions and would like to meet up and chat, you can leave a comment here or send me a tweet.

There’s a lot going on all week and it’s going to be an awesome conference.  I hope to see you there!

Execute PL/SQL calls with Python and cx_Oracle

After you’ve got the hang of performing Basic CRUD operations with cx_Oracle you’re ready to start tapping into some of the real power of the Oracle Database.

Why use PL/SQL?

Python is an excellent language for most things you want your application to do, but when you’re processing data it just goes faster if you do the work where the data is.

This post will cover how to execute Oracle PL/SQL functions and procedures using Python and cx_Oracle.  I’m assuming you’re already familiar with PL/SQL if not, you can get some help from Steven Feuerstein and Bryn Llewellyn.  (Additional resources at the end.)

Prerequisites

  • Python 3
  • Oracle Database version 12+
  • Basic Oracle PL/SQL and SQL knowledge.

Setup

If you’d like to follow along with the examples you’ll need to create the following objects in a database schema that is safe to experiment in.  Make sure you have permissions to create the following objects.

To keep everything clean, I’ll be putting my PL/SQL code into a package called pet_manager.

Cleanup

To clean up the database when you are finished with the series, you need to drop the two tables and the package.  Please make sure you’re connected to the correct schema where you created the tables.

Boilerplate template

The template we will be using is:

  1. Install cx_Oracle.
  2. Import the cx_Oracle driver.
  3. Import os module used to read the environment variable.
  4. Get the connection string from the environment variable.
  5. Create the connection object.
  6. Create the cursor object.
I will include this code section with all Python examples and use the connection object “con” and the cursor object “cur” throughout the series.

For each exercise, replace the “# Your code here” line with your code.

Anonymous PL/SQL Block

I’m going to start off with the most basic process and simply execute an anonymous block of PL/SQL code to reset the database tables.

You can execute any DDL or DML statement like this, but if you’re going to run PL/SQL it’s usually best to compile it to the database.

Execute a PL/SQL Procedure

Using the code from the anonymous block I created a procedure in the PL/SQL package called reset_data.

To call this procedure from Python we use the cursor.callproc method and pass in the package.procedure name to execute.

Assuming everything works, there will not be any response.  So this works as a ‘fire and forget’ way to call database procedures.

Pass Parameters

I have a procedure in my PL/SQL package that we can use to create a new pet in the lcs_pets table.  It accepts the pet_name, owner_id and pet_type.  Using these values it will insert a new entry into the lcs_pets table.

Now on the Python side.

I prefer to set my values with variables so that my code is easier to read, so I’ll create and set pet_name, owner_id and pet_type.

Next, I’ll call the cursor.callproc method and add an array containing the values to pass in the order they are defined in the database.

If everything works there will not be any response.

You can also use keyword parameters.  This also makes your code easy to read and also makes it so you don’t need to worry about the order of the parameters.

Once again, if everything works there will not be any response.

Get PL/SQL Function Return Values

When a row is added to the lcs_pets table a new id is automatically generated.  Having this id can be useful so I created a function in my PL/SQL package that will create a new pet in the lcs_pets table, just like in the previous function, but it will return the new id.

Using Python to call a function in the database and get the return value I’ll use the cursor.callfunc method.

  1. I set the variables that I’ll use as arguments to the function.
  2. Define a new_pet_id variable and assign it the value returned from callfunc.
  3. The second argument of the callfunc method is used to define the type of the data being returned.  I’ll set it to int.  (cx_Oracle will handle the NUMBER to int conversion.)
  4. I pass in the array of values just like I did when I used callproc.
  5. Print the returned value for new_pet_id.

Out Parameters

Out parameters can be very handy when you need to pass back more than one piece of information.  I have an add_pet function in the PL/SQL package that will check to see if the pet type you’re adding needs a license or not.  The function will return the new id like before, and a ‘yes’ or ‘no’ through the out parameter.

To work with the out parameter in Python I’ll add a string variable called ‘need_license’.  It can be defined using ‘cursor.var(str)‘. Then we just add the new variable to the values array in the correct position.  This works the same when using out parameters with the callproc method.

To get the value from ‘need_license’ we call it’s getvalue() function.

Accept Argument Values

So far I’ve hard-coded the variable values in the Python code and the methods are fairly simple, so there’s a low chance of errors.  But, for most methods, we want to accept parameter values that can be passed into the Python code then on to the PL/SQL functions.  I’ll modify the Python method to accept command line arguments.

We need to import sys so that we can use sys.argv[] to grab the command line arguments and assign them to the variables.

If I run this to add a dog, I get:

Adding a fish, I get:

PL/SQL Exceptions

Now that I’m accepting outside argument values, the odds that I’ll eventually get errors with the above code is almost a certainty.  If an error happens in the Python code you can handle it as you normally would.  But, what if there’s an error thrown by the PL/SQL code?

It’s easy enough to test this.  Make the same call as before but pass in a string for the second value.

I would recommend that you handle errors as close to where they happen as you can.  In this example, you could catch the error in the PL/SQL function and either handle it or raise it.  If you don’t handle it in PL/SQL it will be passed back to cx_Oracle which will throw a cx_Oracle.DatabaseError.  At that point, you can handle it as you would when any other Error is thrown in your Python application.

Additional Resources

CI/CD for Database Developers – Export Database Objects into Version Control

With this post, I kick off a series that walks you through the process of building  database applications using a CI/CD pipeline. I will be covering:

  • Export Database Objects into Version Control (This Post)
  • Use Schema Migration
  • Unit Test PL/SQL
  • Build and Deploy
  • Automate

Links will be added for each topic as that article is published. I will use the DinoDate application (source) as my code base.

For this post, assume that I have DinoDate installed and all development to date  has been done directly in the database (source code not stored externally in files).

Since, however, it’s really not a good idea to edit and maintain code directly in the database, I’d like to switch to storing the DDL for my database schema objects in files, managed by a version control system. Let’s get going!

Export the Database Objects out to Files

I could export the code for my objects out into files by writing queries against  built-in database views like ALL_SOURCE.  I have used this method a few times, and you probably have, too. You can make it work, but it puts the onus on you to get everything right. I’d rather think about other things, so I ask myself: is there a tool that will take care of the heavy lifting on this step?

There sure is, and it’s free:  Oracle SQL Developer has a great export tool. Assuming you’ve got SQL Developer installed and you can connect to your schema, here’s what you do:

Under the Tools menu, click on Database Export.

The first step of the wizard configures the general export attributes:

  1. Choose the connection for the schema you want to export.
  2. Select the options you’d like the wizard to use when creating the export scripts.
    I like to add drop statements to my scripts.  You may also want to export grants.
  3. I want to export some of the master table data so I will leave the export data section set with defaults.
  4. Choose “Save As Separate Directories” and select the export directory.

In step 2 I left all of the default options selected.

I want all of the schema objects so I skip step 3.

I selected the tables that contain the pre-loaded master data for the application.

Everything looks good so click finish.

The export wizard also creates a master run script and opens the script in a new worksheet (I’ll come back to this later):

Now that I have everything exported, I want to get the files into version control asap.

Add the Objects to Version Control

I’ll be using Git for version control.  SQL Developer has some nice integrated tools for working with Git but for now, I’m just going to use the command line.

  1. Change to the export directory.
  2. Initialize a Git repository.
  3. Add all files to the repo.
  4. Commit the changes.
Assuming that you’re using a central Git repository, you should push the new repo up to the shared repo.  That process can differ based on which repository host you’re using so I’ll leave it up to you to consult the documentation.

With my files stored safely in Git, it’s time to

Verify / Clean up

Whenever you use any automated code generate/export tool, you should verify the results.

For example, you may want to change the generated SQL for the dinosaure_id column from

to

After you verify each file, run a code beautifier on it.  Maintaining a standard code format will make it easier to see the differences between changes.  This will make your future code reviews much easier.

Make sure you commit each file as you change it.  Don’t wait till the end to do a massive commit.

Organize

In step 1 of the wizard, I selected Save as Separate Directories so all of my object scripts have been grouped into directories by type, like this:

This is a perfectly fine way to organize your scripts.  However, I like to group mine by whether or not the scripts will be changed and re-run vs run a single time and future changes will be done with new scripts.  For example:

If I were going to run everything from scripts, I would also break down the Run_Once directory into product versions with a subdirectory for ‘create from scratch’ and one for ‘updates’, like this:

In another post, I’ll show you how to use a Schema Migration tool which makes managing schema changes much easier.

Master Build Script

Now that everything is cleaned up and organized, we need to modify the master script that was generated by the export.  It should be named with a timestamp in a format similar to this:

Generated-YYYYMMDDHH24MISS.sql.

My exported script was named Generated-20180706134514.sql.

You will want to edit this file and modify the directory for the scripts to match the changes you made above.  Also, you need to verify that the scripts are being run in the order of dependencies.  Objects should be created after the objects they depend on.

If you’re not planning to use a Schema Migration tool you’ll want to create separate master scripts for each of the create and update directories.

Test

Create a new schema that’s safe to test with, and run your master scripts.  After you get the scripts running without errors, do a schema compare to check for any differences between your new schema and the schema you exported from.

When it’s all the way you want it, you are now ready and able to work from files to build your database code.

Working From  Files

From this point, you can now follow a new and improved workflow when it comes to editing the code for your database objects:

  1. Pull the latest version of your code from the shared repository. NEVER ASSUME YOU ALREADY HAVE THE LATEST.
  2. Make your changes.
  3. Compile to the database.
  4. Commit (to your source code repository, not your transaction) often.
  5. Push your changes back up to the shared repository.

Of course, that is a very simplified workflow. You should start a discussion with your team about using more advanced methods to further automate and improve your processes.

I sincerely hope you skimmed this post because you gave up long ago on editing code directly in the database. If that is not the case, I hope this article helps you make the change. Because then the next time something goes badly wrong,  you can simply recover from Git (or your repository of choice).

No tearing your hair out. No gnashing of teeth. No self-hating recriminations. Just a quick recovery and get back to work.

And then you can move on to more interesting challenges in improving the way you write and maintain your database application code.

Tips to help PL/SQL developers get started with CI/CD

In most ways, PL/SQL development is just like working with any other language but, sometimes it can be a little different.  If you’d like to create a Continuous Deployment Pipeline for your PL/SQL application, here is a short list of tips to help you get started.

Work From Files

Do not use the Database as your source code repository.  If you are making changes to your application in a live database, stop right now and go read PL/SQL 101: Save your source code to files by Steven Feuerstein.

Now that you’re working from files, those files should be checked into…

Version Control

There are a lot of version control applications out there, the most popular right now is probably Git.  One advantage of using Git is, you work in your own local copy of the repository making frequent commits that only you see.  If you’re working in your own personal database you could compile your changes to the database at this point.

If you’re working in a database shared with other people and you’re ready to compile your code,   git pull from the central repository to get any changes since your last pull.  Handle any merge conflicts, then git push your changes back up to the shared repository.  After the push, you can compile your code to the database.  This helps ensure that people don’t overwrite each other’s changes.

Making frequent small commits will help keep everything running smoothly.

What about your schema objects?

Your schema objects, such as tables and views, are as much a part of your application as any other component and changes to these objects should be version controlled as well.  The process of keeping track of schema changes is called Schema Migration and there are open source tools you can use such as Flyway and Liquibase.

Unit Testing

In any application it’s smart to have good test coverage, If your goal is Continuous Deployment it’s critical.  A Unit Test is when you test a single unit of code, in PL/SQL that may be a function or procedure.

Unit tests typically follow these steps:

  1. Setup the environment to simulate how it will be when the application is deployed.  This might include changing configuration settings and loading test data.
  2. Execute the code unit.
  3. Validate the results.
  4. Clean up the environment, resetting it to the state it was in before running the tests.

utPLSQL is a great tool for unit testing your PL/SQL applications.  You will write a package of tests for each ‘unit’ of your application which should test all of the required functionality and potential errors.  utPLSQL is an active open source project with an impressive set of features.  Check out the docs to get started.

Build

Building a database application usually consists of running the change scripts in a specific order.  It’s common to create a master script that executes the others in order of how the objects depend on each other.  However, if the master script simply executes the other scripts, you will need to create additional scripts to track and verify changes, and more scripts to give you the ability to rollback the changes if/when there’s a problem.

There are build tools such as Gradle and Maven that can easily execute your scripts.  But you’ll still need to create the additional control scripts.  If you use a Schema Migration tool it should include a lot of these additional functions without having to write extra scripts.  For an example, check out Dino Date which has a Liquibase migration included.

How to handle the PL/SQL code

You could include your PL/SQL code in a Schema Migration changeset but adding schema migration notation to your PL/SQL introduces another layer of complexity and potential errors.

In the Dino Date runOnChange directory, you will find examples of setting up Liquibase changesets that watch for changes in the files of objects that you would rather keep ‘pure’.  When you run a migration, if the file has changed Liquibase will run the new version.

In a shared database environment, you should execute a schema migration after you pull/merge/push your changes into your version control system.

Automate!

All of these pieces can be tied together and automated with an automation server such as Hudson or Jenkins (both are open source) to create a build pipeline.

Original by Jez Humble

A simple (maybe too simple) build pipeline using the above tools could follow these steps:

  1. Developer makes a change and pushes it to the shared Git repository.
  2. Hudson notices the repository has changed and triggers the build pipeline.
  3. The project is pulled from Git.
  4. Liquibase deploys the changes to a test database.
  5. utPLSQL is trigged to run the unit tests.
  6. Liquibase deploys the changes to the production database.

Other Useful Tools

  • Edition Based Redefinition[pdf] can be used to deploy applications with little to no downtime.
  • Oracle Developer Cloud Service comes with a ton of pre-configured tools to help with almost every aspect of your development process.
  • Gitora can help you version control your application if you are not able to move out to files.