SAP HANA Database Client for Node

repository·master·Indexed 43 days ago

https://github.com/sap/node-hdb

A pure JavaScript SAP HANA Database Client for Node.js (version 2.29.6) that allows developers to connect to SAP HANA Cloud, SAP HANA Platform, and other HANA instances. It supports executing SQL via exec() and prepare(), managing transactions with setAutoCommit(), streaming large datasets using resultSet, and authenticating via SAML or JWT tokens. The client includes support for TLS/SSL, SOCKS5/HTTP proxies, and bulk inserts.

Tokens
10K
Snippets
27
Records
43
Agent score
55%

What's inside hdb

  1. Install hdb via npm

    master

    To use the hdb driver in your project, install it from the npm registry:

    npm install hdb

    If you want to run tests or examples locally, you can clone the repository and install dependencies manually:

    git clone https://github.com/SAP/node-hdb.git
    cd node-hdb
    npm install
  2. Control Maximum Packet Size

    master

    By default, outgoing packets are restricted to 128KB. To handle larger SQL statements or LOBs, configure packetSize and packetSizeLimit in createClient.

    • packetSize: The size of individual packets (default: 131072 / 128KB). Range: 65536 to 1073741823.
    • packetSizeLimit: The maximum total size for an outgoing packet (default: same as packetSize). Range: packetSize to 1073741823.

    Example: Allowing up to 1MB total size while keeping LOB chunks at 128KB:

    var client = hdb.createClient({
      host : 'hostname',
      port : 30015,
      packetSize : Math.pow(2, 17), // 128KB
      packetSizeLimit : Math.pow(2, 20) // 1MB
    });
    var client = hdb.createClient({
      host : 'hostname',
      port : 30015,
      packetSize : Math.pow(2, 17),
      packetSizeLimit : Math.pow(2, 20)
    });
  3. Manage multiple physical connections with PhysicalConnectionSet

    master

    A PhysicalConnectionSet is used to group multiple physical connections associated with a single logical connection. This is particularly relevant in scenarios involving connection redirection or multiple volumes.

    Key Concepts

    • Anchor Connection: One connection in the set is designated as the 'anchor'. This is typically the initial connection made before any redirection occurs. Use addAnchorConnection(pconn) to set this.
    • Secondary Connections: Additional connections added via addConnection(pconn).

    Common Operations

    • getAnchorConnection(): Retrieves the designated anchor connection.
    • getConnection(clientConnectionId): Retrieves a specific connection by its ID.
    • closeAll(): Closes all connections in the set and clears the set.
  4. Understand PhysicalConnection lifecycle and errors

    master

    The PhysicalConnection class manages the low-level TCP socket and the HDB protocol handshake.

    Connection States

    • Use isConnected() to check if the socket is open and the protocolVersion has been successfully negotiated.

    Error Codes

    During the connection lifecycle, the following error codes may be emitted via callbacks or event listeners:

    • EHDBINIT: Invalid initialization reply received from the server.
    • EHDBTIMEOUT: The initialization handshake timed out.
    • EHDBCLOSE: The connection was closed by the server (sent via the onEnd callback).

    Cleanup

    • close(): Destroys the underlying socket.
    • destroy(err): Destroys the socket and can pass an error object.
    • closeAllListeners(eventName): Removes all listeners from the socket, or a specific event if eventName is provided.
  5. Perform Bulk Inserts

    master

    To insert multiple rows in a single execution, pass an array of parameter arrays to a prepared statement's exec method.

    client.prepare('insert into TEST.NUMBERS values (?, ?)', function(err, statement){
      if (err) return console.error('Error:', err);
      
      // Each inner array represents one row
      const data = [[1, 'one'], ['2', 'two'], [3, 'three']];
      
      statement.exec(data, function(err, affectedRows) {
        if (err) return console.error('Error:', err);
        console.log('Rows affected:', affectedRows);
      });
    });
    client.prepare('insert into TEST.NUMBERS values (?, ?)', function(err, statement){
      if (err) {
        return console.error('Prepare error:', err);
      }
      statement.exec([[1, 'one'], ['2', 'two'], [3, 'three']], function(err, affectedRows) {
        if (err) {
          return console.error('Exec error:', err);
        }
        console.log('Array of affected rows:', affectedRows);
      });
    });
  6. Configure encrypted network communication (TLS)

    master

    To enable TLS/SSL, pass key, cert, and ca (or a pfx) to createClient. Alternatively, use the useTLS: true option to connect using Node.js's built-in trusted certificates.

    If you need to validate the server's hostname against the certificate, use the checkServerIdentity property, which follows the standard Node.js tls.connect callback signature.

    var client = hdb.createClient({
      host : 'hostname',
      port : 30015,
      key  : fs.readFileSync('client-key.pem'),
      cert : fs.readFileSync('client-cert.pem'),
      ca   : [fs.readFileSync('trusted-cert.pem')],
      useTLS: true
    });
  7. Manage Transactions with `setAutoCommit()`

    master

    By default, every statement is automatically committed. To manage transactions manually, call client.setAutoCommit(false).

    Use client.commit(callback) to finalize changes or client.rollback(callback) to undo them. After your transaction logic, remember to call client.setAutoCommit(true) to return to default behavior.

    client.setAutoCommit(false);
    
    client.exec('insert into NUMBERS values (1, "one")', function(err) {
      if (err) {
        return client.rollback(function() { /* handle rollback */ });
      }
      
      client.commit(function(commitErr) {
        client.setAutoCommit(true);
        if (commitErr) return console.error('Commit error');
        console.log('Transaction committed');
      });
    });
  8. Authenticate using SAML or JWT tokens

    master

    Instead of using user and password, you can provide authentication tokens during the connect() call.

    SAML Authentication

    Provide a signed SAML assertion in the connect options. Upon success, the server returns the database user and a sessionCookie which can be used for reconnecting.

    JWT Authentication

    Provide a JWT token in the connect options. Upon success, the server returns the database user and a sessionCookie which can be used for reconnecting.

    // SAML
    client.connect({
      assertion: '<Assertion xmlns="urn:oasis:names:tc:SAML:2.0:assertion" ...>...</Assertion>'
    }, function (err) {
      if (err) return console.error('Error:', err);
      console.log('User:', client.get('user'));
    });
    
    // JWT
    client.connect({
      token: 'eyJhbGciOiJSUzI1NiJ9....'
    }, function (err) {
      if (err) return console.error('Error:', err);
      console.log('User:', client.get('user'));
    });
  9. Use Prepared Statements for efficiency and security

    master

    Use client.prepare(sql, callback) to create a statement object. This object can be executed multiple times with different parameters.

    Execution

    • Use statement.exec(parameters, callback) where parameters is an array of positional values or an object of named parameters.
    • Use statement.execute(parameters, callback) if you want to receive a resultSet (for streaming) instead of the full result array.

    Stored Procedures

    To call a stored procedure, pass the scalar parameters as an object in the first argument of exec. Subsequent arguments in the callback will contain the result sets (e.g., dummyRows, tableRows).

    Cleanup

    Call statement.drop(callback) to remove the statement from the server.

    client.prepare('select * from DUMMY where DUMMY = ?', function (err, statement){
      if (err) return console.error('Error:', err);
      
      statement.exec(['X'], function (err, rows) {
        if (err) return console.error('Error:', err);
        console.log('Rows:', rows);
      });
    });
  10. Stream results using `resultSet`

    master

    If you need to process large datasets without loading everything into memory, use the execute() method (instead of exec()). This returns a resultSet object.

    You can create an object stream or an array stream from the resultSet and pipe it to a writable stream.

    Note: You must call rs.close() when finished to prevent resource leaks.

    client.execute('select A, B from TEST.NUMBERS order by A', function(err, rs) {
      if (err) return console.error('Error:', err);
      
      rs.setFetchSize(2048);
      rs.createObjectStream()
        .pipe(new MyWriteStream())
        .on('finish', function (){
          if (!rs.closed) {
           rs.close();
          }
        });
    });
  11. Establish a database connection with hdb.createClient()

    master

    To connect to an SAP HANA database, use hdb.createClient(options). The client instance is initially in a 'new' state and does not open a network connection until connect() is called.

    It is highly recommended to register an 'error' event handler on the client to handle network connection errors or database restarts.

    Connection Options

    • host: The hostname of the database.
    • port: The SQL port.
    • user: Database user.
    • password: Database password.
    • databaseName: For MDC (Multitenant Database Container) setups, specify the tenant database name.
    • instanceNumber: Alternative to port for specifying the HANA system instance number.
    • hosts: An array of { host, port } objects for distributed/multiple-host systems. The client connects to the first available host.
    • SESSIONVARIABLE:KEY: Options prefixed with this allow setting session-specific client information at connection time.
    var hdb    = require('hdb');
    var client = hdb.createClient({
      host     : 'hostname',
      port     : 30015,
      user     : 'user',
      password : 'secret'
    });
    
    client.on('error', function (err) {
      console.error('Network connection error', err);
    });
    
    client.connect(function (err) {
      if (err) {
      	return console.error('Connect error', err);
      }
      console.log('Connected!');
    });
  12. Set Session-Specific Client Information

    master

    You can set session variables (key-value pairs) that the HANA server can use. These are case-sensitive.

    There are two ways to set them:

    1. At connection time: Use the SESSIONVARIABLE:KEY prefix in the createClient options.
    2. During a session: Use the client.setClientInfo(key, value) method. Variables set via setClientInfo are sent to the server during the next execute, prepare, or fetch operation.
    var client = hdb.createClient({
      host             : 'hostname',
      port             : 30015,
      user             : 'user',
      password         : 'secret',
      "SESSIONVARIABLE:EXAMPLEKEY1" : "EXAMPLEVALUE1"
    });
    
    // Set additional info later
    client.setClientInfo("EXAMPLEKEY2", "EXAMPLEVALUE2");