19. Februar 2015

Installation von "node-oracledb": Node.js und die Oracle-Datenbank

External calls as a different Unix user: DBMS_SCHEDULER or Java?
Letztes Jahr im Herbst hatte ich bereits ein Blog Posting zum Thema Node.js und die Oracle-Datenbank veröffentlicht. Als Datenbanktreiber hatte ich den Open-Source Treiber von Joe Ferner hergenommen, da es von Oracle noch keinen gab. Das hat sich nun geändert - der "offizielle" node.js-Treiber von Oracle ist Seit Januar auf GitHub verfügbar. Stand heute steht die Early Adopter Version 0.3.1 zum Download bereit.
In diesem Blog Posting beschreibe ich die Installation und ein erstes node.js-Programm - durchaus auch für solche Entwickler, die bislang noch nicht mit node.js garbeitet haben. Während der Installation von node-oracledb wird etwas kompiliert; die dazu nötigen Compiler sind auf einem Linux-System out-of-the-box enthalten; auf Windows muss eine C/C++ Compilerumgebung (etwa Microsoft Visual Studio 2013) installiert sein. Ich habe ein Linux-System verwendet; da dort alles bereits vorhanden ist.

Zutaten

Ihr braucht folgende Software-Downloads
  • Auf eurem Rechner muss eine Python-Version zwischen 2.5 und 3.0 installiert sein. Python wird benötigt, um den Oracle-Treiber node-oracledb zu kompilieren und zu installieren. Zur Installation von Python ist reichlich Material verfügbar; im folgenden wird also davon ausgegangen, dass Python installiert ist.
  • Node.js selbst - Download von www.nodejs.org. Am einfachsten ist es, Ihr ladet euch das tar.gz File herunter; damit gelingt die Installation überall und auch ohne "Root"-Privilegien. Nehmt im Augenblick nicht die jüngste Version 0.12.0 (mit der läuft node-oracledb noch nicht), sondern 0.10.36.
  • node-oracledb - den bekommt Ihr entweder vom OTN Node.js Developer Center oder von Github.
  • node-oracledb setzt einen Oracle-Client voraus. Am einfachsten ist die Installation des Instant Client. Den bekommt Ihr aus dem OTN: Oracle Database Instant Client. Wichtig: Ihr müsst hier zwei Pakete herunterladen: Instantclient-Basic und Instantclient-SDK.

Los geht's: Herunterladen und auspacken

Nach dem Download sollten diese Dateien in eurem Verzeichnis sein,
$ ls -lah
total 67M
-rw-r--r--  1 oracle oinstall  61M Feb 19 12:54 instantclient-basic-linux.x64-12.1.0.2.0.zip
-rw-r--r--  1 oracle oinstall 652K Feb 19 12:54 instantclient-sdk-linux.x64-12.1.0.2.0.zip
-rw-r--r--  1 oracle oinstall 103K Feb 19 12:54 node-oracledb-master.zip
-rw-r--r--  1 oracle oinstall 5.5M Feb 19 12:54 node-v0.10.36-linux-x64.tar.gz
[oracle@sccloud037 node-download]$
Nun alles auspacken.
$ tar -xzf node-v0.10.36-linux-x64.tar.gz
$ unzip -q node-oracledb-master.zip
$ unzip -q instantclient-basic-linux.x64-12.1.0.2.0.zip
$ unzip -q instantclient-sdk-linux.x64-12.1.0.2.0.zip
$ ls -lahd */

drwxr-xr-x  3 oracle oinstall 4.0K Feb 19 12:56 instantclient_12_1
drwxr-xr-x  6 oracle oinstall 4.0K Feb 16 18:32 node-oracledb-master
drwxr-xr-x  6 oracle oinstall 4.0K Jan 26 20:33 node-v0.10.36-linux-x64

Initiale Einrichtung

Zunächst ist es hilfreich, sich einige Umgebnungsvariablen zu setzen, damit die node.js Executables node und npm immer verfügbar sind. Am besten baut Ihr euch ein kleines Skript dazu. Für node.js selbst muss PATH gesetzt werden, für unsere Arbeit mit der Oracle-Datenbank braucht es auch LD_LIBRARY_PATH (achtet darauf, die Pfade an eure Umgebung anzupassen).
#!/bin/sh
export PATH=/path/to/node-v0.10.36-linux-x64/bin:$PATH
export LD_LIBRARY_PATH=/path/to/instantclient_12_1:$LD_LIBRARY_PATH

echo "**** node.js environment set ***"

node -v
Dieses Skript dann einfach wie folgt aufrufen.
$ . sh node-env.sh
**** node.js environment set ***
v0.10.36
Als nächstes braucht es eine Arbeitsumgebung. Das ist ein ganz normales Verzeichnis; nennen wir es work. Darin werden die node.js-Skripte (.js-Dateien) liegen. Unterhalb von work legt Ihr dann noch ein Verzeichnis namens node_modules an. In dieses werden dann später die zusätzlichen node.js Pakete gelegt (der Oracle-Datenbanktreiber ebenfalls).

Oracle-Treiber "node-oracledb" aufsetzen

Nun muss der Oracle-Treiber node-oracledb installiert werden - die folgenden Schritte sind einmalig; zum späteren Ausführen der node.js-Programme sind sie nichr mehr nötig.
  • Setzt die Umgebungsvariablen OCI_LIB_DIR und OCI_INC_DIR
    $ export OCI_LIB_DIR=/path/to/instantclient_12_1
    $ export OCI_INC_DIR=/path/to/instantclient_12_1/sdk/include
    
  • Im Verzeichnis des Oracle Instant Client wird eine Datei unter einem anderen Namen erwartet. Kopiert also die Datei libclntsh.so.12.1 nach libclntsh.so (oder legt einen symbolischen Link an).
    cd /path/to/instantclient_12_1
    ln -s libclntsh.so.12.1 libclntsh.so
    
  • Wechselt nun ins Verzeichnis, in das Ihr den Treiber node-oracledb ausgepackt habt und kompiliert diesen mit npm install.
    $ cd /path/to/node-oracledb-master
    $ npm install
    
    > oracledb@0.3.1 install /path/to/node-oracledb-master
    > node-gyp rebuild
    
    make: Entering directory `/path/to/node-oracledb-master/build'
      CXX(target) Release/obj.target/oracledb/src/njs/src/njsOracle.o
      CXX(target) Release/obj.target/oracledb/src/njs/src/njsPool.o
      CXX(target) Release/obj.target/oracledb/src/njs/src/njsConnection.o
    
      :
    
      COPY Release/oracledb.node
    make: Leaving directory `/path/to/node-oracledb-master/build'
    $
    
  • Nun benennt Ihr das Verzeichnis node-oracledb-master nach oracledb um und verschiebt es in den Ordner node_modules eures bereits angelegten Arbeitsverzeichnisses.
Damit sind wir fertig. Die Verzeichnisstruktur sieht damit wie folgt aus.
Die Datei emp.js ist das erste node.js Programm. Es soll eine Zeile aus der Tabelle EMP lesen und auf der Konsole ausgeben. Der Code ist der folgende.
var oracledb = require('oracledb');

function showEmp(conn) {
    conn.action = "Action EMP";
    conn.module = "Node.js Module EMP";
    console.log("... and here is THE KING");
    conn.execute(
      "SELECT * from EMP where EMPNO = 7839",
      [],
      function(err, result)
      {
        if (err) {
          console.log('%s', err.message);
          return;
        }
        console.log(result.rows);
      });
  }

oracledb.getConnection(
  {
    user          : "scott",
    password      : "tiger",
    connectString : "datenbank-server:1521/service-name"
  },
  function(err, connection)
  {
    if (err) {
      console.error(err.message);
      return;
    }
    showEmp(connection);
  }
);

console.log("Finished. Really????");
Den Connection-String, Usernamen und Passwort in den Zeilen 22 bis 24 müsst Ihr natürlich an eure Umgebung anpassen. Wenn Ihr das Skript dann startet, seht ihr folgende Ausgabe.
$ node emp.js
Finished. Really????
... and here is THE KING
[ [ 7839,
    'KING',
    'PRESIDENT',
    null,
    Tue Nov 17 1981 00:00:00 GMT+0100 (CET),
    5000,
    null,
    10 ] ]
Dass Ihr die Ausgabe Finished ... zuerst sieht, liegt an der asynchronen Natur von node.js - das ist unter anderem hier und an vielen anderen Stellen im Internet beschrieben. Darauf aufbauend, lassen sich nun viele Dinge mit node.js und der Oracle-Datenbank realisieren. Einige Beispiele wurden im Oracle-Webinar am 10. Februar vorgestellt und stehen auf apex.oracle.com/folien zum Download bereit.
Viel Spaß beim Ausprobieren.
In September 2014, I had a blog posting about Node.js and the Oracle database. In that posting, I used the Open Source Oracle Driver authored by Joe Ferner, since Oracle did not provide one. In the meantime, this has changed: There is an "official" node.js driver available from Oracle - it's called node-oracledb and is currently in the Early Adopter Stage. As of today (Feb 19th, 2015), the most recent version is 0.3.1.
In this blog posting I'll describe how to get started with node-oracledb. You need to perform a few steps for installation but it isn't that difficult. During installation, something will be compiled, so a compiler suite must be available on your machine. On a linux box, this is present out-of-the-box - on windows, you need to install a C/C++ build environment (such as Microsoft Visual Studio 2013) beforehand. To create this blog posting, I used a linux box.

Ingredients

You need the following software packages.
  • As a prerequisite, you need a Python installation on your machine. Its version must be at least 2.5, but lower than 3.0. Python is needed for the compilation process of node-oracledb. Since there are plenty of tutorials on installing python on a machine, I'll skip this and assume that python is present.
  • You need Node.js itself - download it from www.nodejs.org. The most easy variant is to download the tar.gz file; then you can install everywhere, and without root privileges. At the moment, don't take the latest version 0.12.0 (node-oracledb does not run on it). Choose 0.10.36 instead.
  • node-oracledb - download it either from OTN Node.js Developer Center or from Github.
  • You'll need Oracle Client libraries on your machine. The most easy approach is to use Instant Client. It is available from OTN: Oracle Database Instant Client. Important: You need to download two packages: Instantclient-Basic and Instantclient-SDK.

Let's get started: Download and extract

After downloading, you should have the following files present.
$ ls -lah
total 67M
-rw-r--r--  1 oracle oinstall  61M Feb 19 12:54 instantclient-basic-linux.x64-12.1.0.2.0.zip
-rw-r--r--  1 oracle oinstall 652K Feb 19 12:54 instantclient-sdk-linux.x64-12.1.0.2.0.zip
-rw-r--r--  1 oracle oinstall 103K Feb 19 12:54 node-oracledb-master.zip
-rw-r--r--  1 oracle oinstall 5.5M Feb 19 12:54 node-v0.10.36-linux-x64.tar.gz
[oracle@sccloud037 node-download]$
Now extract everything.
$ tar -xzf node-v0.10.36-linux-x64.tar.gz
$ unzip -q node-oracledb-master.zip
$ unzip -q instantclient-basic-linux.x64-12.1.0.2.0.zip
$ unzip -q instantclient-sdk-linux.x64-12.1.0.2.0.zip
$ ls -lahd */

drwxr-xr-x  3 oracle oinstall 4.0K Feb 19 12:56 instantclient_12_1
drwxr-xr-x  6 oracle oinstall 4.0K Feb 16 18:32 node-oracledb-master
drwxr-xr-x  6 oracle oinstall 4.0K Jan 26 20:33 node-v0.10.36-linux-x64

Configure your node.js environment

It's useful to set some environment variables: The path to the node.js executables node and npm should be part of your PATH environment variable. Since we will work with the Oracle database, we'll also need to have the Oracle Client libraries within LD_LIBRARY_PATH. The following shell script does the job for you (note to adjust the paths to your environment).
#!/bin/sh
export PATH=/path/to/node-v0.10.36-linux-x64/bin:$PATH
export LD_LIBRARY_PATH=/path/to/instantclient_12_1:$LD_LIBRARY_PATH

echo "**** node.js environment set ***"

node -v
Then call the script as follows.
$ . sh node-env.sh
**** node.js environment set ***
v0.10.36
Next, you'll need a working directory; this is a simple folder called work. In this folder we'll place our node.js scripts. Also within work, you need a subdirectory node_modules. This will hold all additional node.js packages - node-oracledb will be placed there as well. The following image illustrates the folder structure.

Install "node-oracledb"

Now we'll install the node-oracledb driver in our node.js environment. These installation steps are only to be executed once.
  • Create two environment variables: OCI_LIB_DIR and OCI_INC_DIR
    $ export OCI_LIB_DIR=/path/to/instantclient_12_1
    $ export OCI_INC_DIR=/path/to/instantclient_12_1/sdk/include
    
  • The Oracle Instant Client folder contains a file named libclntsh.so.12.1. Node.js expects it under the name libclntsh.so. So create either a copy or a symbolic link.
    cd /path/to/instantclient_12_1
    ln -s libclntsh.so.12.1 libclntsh.so
    
  • Now change to the folder which has been created by extracting the downloaded file node-oracledb-master.zip. Compile the driver using npm install.
    $ cd /path/to/node-oracledb-master
    $ npm install
    
    > oracledb@0.3.1 install /path/to/node-oracledb-master
    > node-gyp rebuild
    
    make: Entering directory `/path/to/node-oracledb-master/build'
      CXX(target) Release/obj.target/oracledb/src/njs/src/njsOracle.o
      CXX(target) Release/obj.target/oracledb/src/njs/src/njsPool.o
      CXX(target) Release/obj.target/oracledb/src/njs/src/njsConnection.o
    
      :
    
      COPY Release/oracledb.node
    make: Leaving directory `/path/to/node-oracledb-master/build'
    $
    
  • After that, rename this folder from node-oracledb-master to oracledb and then move it into the node_modules folder in your already created directory work.
Then you are finished. Your folder structure should look like this:
You now can create an run node.js scripts working with the Oracle Database. The followng file emp.js is our first node.js Program - it is supposed to select one row from the EMP table and to print it to the console.
var oracledb = require('oracledb');

function showEmp(conn) {
    conn.action = "Action EMP";
    conn.module = "Node.js Module EMP";
    console.log("... and here is THE KING");
    conn.execute(
      "SELECT * from EMP where EMPNO = 7839",
      [],
      function(err, result)
      {
        if (err) {
          console.log('%s', err.message);
          return;
        }
        console.log(result.rows);
      });
  }

oracledb.getConnection(
  {
    user          : "scott",
    password      : "tiger",
    connectString : "datenbank-server:1521/service-name"
  },
  function(err, connection)
  {
    if (err) {
      console.error(err.message);
      return;
    }
    showEmp(connection);
  }
);

console.log("Finished. Really????");
Of course, you must adjust the connection string, username and password in lines 22 to 24 to your environment. After that, run the script by typing node emp.js and see its results.
$ node emp.js
Finished. Really????
... and here is THE KING
[ [ 7839,
    'KING',
    'PRESIDENT',
    null,
    Tue Nov 17 1981 00:00:00 GMT+0100 (CET),
    5000,
    null,
    10 ] ]
You'll recognize that the output Finished ... comes first and the table contents afterwards. This is due to the asychronous nature of node.js. I'll not elaborate on this within that blog posting - as always, there are plenty of tutorials which describe this behaviour much better than I am able to. Based on this, you can start building applications or services with Node.js and the Oracle Database. Some examples have been introduced in a german Webinar at Feb 10th, 2015. This sample code can be downloaded from apex.oracle.com/folien.
Have fun!

3. Februar 2015

"node-oracledb"-Treiber für Node.js: Webseminar am 10. Februar

This blog posting is about the upcoming webinar on the Oracle Database and "node.js" and therefore in German only. After the webinar I'll post some code snippets and tutorials in both english and german language.
Letztes Jahr im Herbst hatte ich bereits ein Blog Posting zum Thema Node.js und die Oracle-Datenbank veröffentlicht. Als Datenbanktreiber hatte ich den Open-Source Treiber von Joe Ferner hergenommen, da es von Oracle noch keinen gab.
Das hat sich nun geändert - der node.js-Treiber von Oracle ist auf GitHub als Early Adopter Version (0.2) verfügbar. Diesen stelle ich in einem Webseminar am 10. Februar um 11:00 Uhr vor. Mehr Details zur Einwahl findet Ihr auf der Webseite des Oracle Developer Monthly.
Vorgestellt werden Node.js selbst, der Treiber für die Oracle-Datenbank, dessen Installation und einige Code-Beispiele (Einfacher REST Service, IMAP-Integration mit der Datenbank, HTML5-Websocket-Beispiel).
Nach dem Webcast wird ein weiteres Blog Posting mit mehr Details zur Installation und Nutzung des node.js Treibers geben. Bis dahin (für die, die es nicht erwarten können) hier ein wenig Code: Das folgende Beispiel implementiert einen sehr einfachen REST Webservice (nur GET) für die Tabelle EMP.
var oracledb = require('oracledb');
var express = require('express');

var pool;

//
// Diese Javascript-Funktion behandelt einen HTTP-Request /emp/*
//
function processEmp(req, res) {
  pool.getConnection(function(err, connection){
    connection.execute(
      "select * from emp where (empno=:1 or empno is null)", 
      [req.params[0]],
      function(err, results) {
        connection.release(function (err) {}),
        res.writeHead(200, {'Content-Type': 'application/json'});
        res.end(JSON.stringify(results.rows));
      }
    )
  })
}

//
// Diese Javascript-Funktion startet den Server
//
function startServer () {
  var app =  express();
  app.get ("/emp/*", processEmp);

  var server = app.listen(9000, function () {
    var host = server.address().address
    var port = server.address().port
    console.log('Table EMP REST Service listening at http://%s:%s', host, port);
  });
}

//
// Programmstart. Oracle Connection Pool und bei Erfolg den Webserver starten
//
oracledb.createPool(
  {
    user          : "scott",
    password      : "*****",
    connectString : "dbserver.mycompany.com:1521/orcl",
    poolMin       : 10,
    poolMax       : 20
  },

  function(err, ppool){
    pool = ppool;
    startServer();
  }
);
Ein solcher "Mini-Dienst" lässt sich sehr elegant mit der Visualisierungstechnologie D3js verbinden; ein sehr einfaches Beispiel sieht dann so aus:

Beliebte Postings