UNPKG

26.8 kBMarkdownView Raw
1hdb - Pure JavaScript SAP HANA Database Client
2==============================================
3
4[![Version](https://img.shields.io/npm/v/hdb.svg?style=flat-square)](https://npmjs.org/package/hdb)
5[![Build](https://img.shields.io/travis/SAP/node-hdb.svg?style=flat-square)](http://travis-ci.org/SAP/node-hdb)
6[![Coverage](https://img.shields.io/coveralls/SAP/node-hdb/master.svg?style=flat-square)](https://coveralls.io/r/SAP/node-hdb?branch=master)
7[![Dependencies](https://img.shields.io/david/SAP/node-hdb.svg?style=flat-square)](https://david-dm.org/SAP/node-hdb#info=dependencies&view=list)
8[![DevDependencies](https://img.shields.io/david/dev/SAP/node-hdb.svg?style=flat-square)](https://david-dm.org/SAP/node-hdb?type=dev&view=list)
9[![License](https://img.shields.io/npm/l/hdb.svg?style=flat-square)](http://www.apache.org/licenses/LICENSE-2.0.html)
10[![Downloads](https://img.shields.io/npm/dm/hdb.svg?style=flat-square)](http://npm-stat.com/charts.html?package=hdb)
11[![REUSE status](https://api.reuse.software/badge/github.com/SAP/node-hdb)](https://api.reuse.software/info/github.com/SAP/node-hdb)
12
13Table of contents
14-------------
15
16* [Install](#install)
17* [SAP Support for hdb and @sap/hana-client](#sap-support-for-hdb-and-saphana-client)
18* [Getting started](#getting-started)
19* [Establish a database connection](#establish-a-database-connection)
20* [Direct Statement Execution](#direct-statement-execution)
21* [Prepared Statement Execution](#prepared-statement-execution)
22* [Bulk Insert](#bulk-insert)
23* [Streaming results](#streaming-results)
24* [Transaction handling](#transaction-handling)
25* [Streaming Large Objects](#streaming-large-objects)
26* [CESU-8 encoding support](#cesu-8-encoding-support)
27* [TCP Keepalive](#tcp-keepalive)
28* [Running tests](#running-tests)
29* [Running examples](#running-examples)
30
31Install
32-------
33
34Install from npm:
35
36```bash
37npm install hdb
38```
39
40or clone from the [GitHub repository](https://github.com/SAP/node-hdb) to run tests and examples locally:
41
42```bash
43git clone https://github.com/SAP/node-hdb.git
44cd node-hdb
45npm install
46```
47SAP Support for hdb and @sap/hana-client
48------------
49
50__The hdb and [@sap/hana-client](https://www.npmjs.com/package/@sap/hana-client) Node.js SAP HANA client drivers are supported by SAP for connecting to [SAP HANA Cloud](https://www.sap.com/products/hana/cloud.html) and [SAP HANA Platform](https://www.sap.com/products/hana.html) servers. When starting a new project, it is encouraged to use the fully featured @sap/hana-client driver ([documentation](https://help.sap.com/viewer/f1b440ded6144a54ada97ff95dac7adf/latest/en-US/a5c332936d9f47d8b820a4ecc427352c.html)).__
51
52```shell
53npm install @sap/hana-client
54```
55
56Below is a major feature comparison chart between the two drivers:
57
58| Feature | @sap/hana-client |hdb|
59|-------------------------------------------------------|:----------------:|:----------------:|
60| Connectivity to SAP HANA Cloud |:heavy_check_mark:|:heavy_check_mark:|
61| Connectivity to SAP HANA as a Service |:heavy_check_mark:|:heavy_check_mark:|
62| Connectivity to SAP HANA Platform |:heavy_check_mark:|:heavy_check_mark:|
63| Transport Layer Security (TLS) |:heavy_check_mark:|:heavy_check_mark:|
64| Active-Active Read Enabled |:heavy_check_mark:|:x:|
65| Client-Side Data Encryption |:heavy_check_mark:|:x:|
66| Statement Distribution |:heavy_check_mark:|:x:|
67| Kerberos Authentication |:heavy_check_mark:|:x:|
68| Secure User Store Integration (hdbuserstore) |:heavy_check_mark:|:x:|
69| Connections through HTTP proxy |:heavy_check_mark:|:x:|
70| Connections through SOCKS proxy (SAP Cloud Connector) |:heavy_check_mark:|:x:|
71| Tracing via hdbsqldbc_cons |:heavy_check_mark:|:x:|
72| Tracing via environment variable to a file |:heavy_check_mark:|:heavy_check_mark:|
73| Pure JavaScript package |:x: |:heavy_check_mark:|
74| Node.js major version support |8+|All Supported Versions|
75| License (without alternate SAP license agreement) |[SAP Developer Agreement](https://tools.hana.ondemand.com/developer-license.txt)|[Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0.html)|
76| SAP Support (with SAP Support agreement) |Component [HAN-DB-CLI](https://launchpad.support.sap.com/#incident/create)|Component [HAN-DB-CLI](https://launchpad.support.sap.com/#incident/create)|
77| Community Support |[answers.sap.com](https://answers.sap.com/tags/73554900100700000996) HANA tag|[node-hdb/issues](https://github.com/SAP/node-hdb/issues)
78
79The hdb driver may also have different APIs or lack support for SAP HANA server features where the @sap/hana-client is fully supported. APIs that are the same in both drivers may have different behaviour.
80
81Getting started
82------------
83
84If you do not have access to an SAP HANA server, go to the [SAP HANA Developer Center](https://developers.sap.com/topics/hana.html) and choose one of the options to use SAP HANA Express or deploy a new SAP HANA Cloud server.
85
86This is a very simple example showing how to use this module:
87
88```js
89var hdb = require('hdb');
90var client = hdb.createClient({
91 host : 'hostname',
92 port : 30015,
93 user : 'user',
94 password : 'secret'
95});
96client.on('error', function (err) {
97 console.error('Network connection error', err);
98});
99client.connect(function (err) {
100 if (err) {
101 return console.error('Connect error', err);
102 }
103 client.exec('select * from DUMMY', function (err, rows) {
104 client.end();
105 if (err) {
106 return console.error('Execute error:', err);
107 }
108 console.log('Results:', rows);
109 });
110});
111```
112
113Establish a database connection
114-------------------------------
115
116The first step to establish a database connection is to create a client object. It is recommended to pass all required `connect` options like `host`, `port`, `user` and `password` to the `createClient` function. They will be used as defaults for any following connect calls on the created client instance. In case of network connection errors like a connection timeout or a database restart, you should register an error event handler in order to be able to handle these kinds of problems. If there are no error event handlers, errors will not be emitted.
117
118```js
119var hdb = require('hdb');
120var client = hdb.createClient({
121 host : 'hostname',
122 port : 30015,
123 user : 'user',
124 password : 'secret'
125});
126client.on('error', function (err) {
127 console.error('Network connection error', err);
128});
129console.log(client.readyState); // new
130```
131
132When a client instance is created it does not immediately open a network connection to the database host. Initially, the client is in a 'new' state. When you call `connect` for the first time, two things are done internally:
133
1341. A network connection is established and the communication is initialized (Protocol - and Product Version exchange). Now the connection is ready for exchanging messages but no user session is established as the client is in a `disconnected` state. This step is skipped if the client is already in a `disconnected` state.
135
1362. The authentication process is initiated. After a successful user authentication a database session is established and the client is in a `connected` state. If authentication fails the client remains in a `'disconnect'` state.
137
138```js
139client.connect(function (err) {
140 if (err) {
141 return console.error('Error:', err);
142 }
143 console.log(client.readyState); // connected
144});
145```
146If user and password are specified they will override the defaults of the client. It is possible to disconnect and reconnect with a different user on the same client instance and the same network connection.
147
148The client also supports SAP HANA systems installed in multiple-container (MDC) mode. In this case a single SAP HANA system may contain several isolated tenant databases.
149A database is identified by its name. One of the databases in an MDC setup is the system database which is used for central system administration.
150One can connect to a specific tenant database directly via its host and SQL port (as shown in the example above) or via the system database which may lookup the exact host and port of a particular database by a given name.
151
152```js
153var hdb = require('hdb');
154var client = hdb.createClient({
155 host : 'hostname', // system database host
156 port : 30013, // system database port
157 databaseName : 'DB1', // name of a particular tenant database
158 user : 'user', // user for the tenant database
159 password : 'secret' // password for the user specified
160});
161```
162
163The client also accepts an instance number instead of the port of the system database:
164
165```js
166var hdb = require('hdb');
167var client = hdb.createClient({
168 host : 'hostname', // system database host
169 instanceNumber : '00', // instance number of the HANA system
170 databaseName : 'DB1', // name of a particular tenant database
171 user : 'user', // user for the tenant database
172 password : 'secret' // password for the user specified
173});
174```
175
176Multiple hosts can be provided to the client as well:
177
178```js
179var hdb = require('hdb');
180var client = hdb.createClient({
181 hosts : [ { host: 'host1', port: 30015 }, { host: 'host2', port: 30015 } ],
182 user : 'user',
183 password : 'secret'
184});
185```
186
187This is suitable for multiple-host SAP HANA systems which are distributed over several hosts. The client establishes a connection to the first available host from the list.
188
189### Authentication mechanisms
190Details about the different authentication methods can be found in the [SAP HANA Security Guide](https://help.sap.com/viewer/6b94445c94ae495c83a19646e7c3fd56/latest/en-US/440f6efe693d4b82ade2d8b182eb1efb.html).
191
192#### User / Password
193Users authenticate themselves with their database `user` and `password`.
194
195#### SAML assertion
196SAML bearer assertions as well as unsolicited SAML responses that include an
197unencrypted SAML assertion can be used to authenticate users. SAML assertions and responses must be signed using XML signatures. XML Digital signatures can be created with [xml-crypto](https://www.npmjs.org/package/xml-crypto) or [xml-dsig](https://www.npmjs.org/package/xml-dsig).
198
199Instead of `user` and `password` you have to provide a SAML `assertion`:
200
201```js
202client.connect({
203 assertion: '<Assertion xmlns="urn:oasis:names:tc:SAML:2.0:assertion" ...>...</Assertion>'
204},function (err) {
205 if (err) {
206 return console.error('Error:', err);
207 }
208 console.log('User:', client.get('user'));
209 console.log('SessionCookie:', client.get('SessionCookie'));
210});
211```
212
213After a successful SAML authentication, the server returns the database `user` and a `SessionCookie` which can be used for reconnecting.
214
215### Encrypted network communication
216To establish an encrypted database connection just pass either `key`, `cert` and `ca` or a `pfx` to createClient.
217
218```js
219var client = hdb.createClient({
220 host : 'hostname',
221 port : 30015,
222 key : fs.readFileSync('client-key.pem'),
223 cert : fs.readFileSync('client-cert.pem'),
224 ca : [fs.readFileSync('trusted-cert.pem')],
225 ...
226});
227```
228
229Use the `useTLS` option if you would like to connect to SAP HANA using Node.js's trusted certificates.
230
231```js
232var client = hdb.createClient({
233 host : 'hostname',
234 port : 30015,
235 useTLS: true,
236 ...
237});
238```
239
240**Note** for MDC use cases: The system database and the target tenant database may be configured to work with different certificates.
241If so, make sure to include all the necessary TLS-related properties for both the databases in the client's options.
242
243In case you need custom logic to validate the server's hostname against the certificate, you can assign a callback function to the `checkServerIdentity` property, alongside the other connection options. The callback is
244supplied to the `tls.connect` funciton of the [TLS](https://nodejs.org/api/tls.html#connect) API and should conform to the signature described there.
245
246Direct Statement Execution
247--------------------------
248
249Direct statement execution is the simplest way to execute SQL statements.
250The only input parameter is the SQL command to be executed.
251Generally, statement execution results are returned using callbacks.
252The type of returned result depends on the kind of statement.
253
254### DDL Statement
255
256In the case of a DDL statement nothing is returned:
257
258```js
259client.exec('create table TEST.NUMBERS (a int, b varchar(16))', function (err) {
260 if (err) {
261 return console.error('Error:', err);
262 }
263 console.log('Table TEST.NUMBERS has been created');
264});
265```
266
267### DML Statement
268
269In the case of a DML Statement the number of `affectedRows` is returned:
270
271```js
272client.exec('insert into TEST.NUMBERS values (1, \'one\')', function (err, affectedRows) {
273 if (err) {
274 return console.error('Error:', err);
275 }
276 console.log('Number of affected rows:', affectedRows);
277});
278```
279
280### Query
281
282The `exec` function is a convenient way to completely retrieve the result of a query. In this case all selected `rows` are fetched and returned in the callback. The `resultSet` is automatically closed and all `Lobs` are completely read and returned as buffer objects. If streaming of the results is required you will have to use the `execute` function. This is described in section [Streaming results](#streaming-results):
283
284```js
285client.exec('select A, B from TEST.NUMBERS order by A', function(err, rows) {
286 if (err) {
287 return console.error('Error:', err);
288 }
289 console.log('Rows:', rows);
290});
291```
292
293Different Representations of Query Results
294-----------------------------------
295The default representation of a single row is an object where the property names are the columnDisplayNames of the resultSetMetadata:
296
297```js
298var command = 'select top 1 * from t1';
299client.exec(command, function(err, rows) {
300 /* rows will be an array like this:
301 [{
302 ID: 1,
303 A: 't1.1.a',
304 B: 't1.1.b'
305 }]
306 */
307});
308```
309
310If your SQL statement is a join with overlapping column names, you may want to get separate objects for each table per row. This is possible if you set option `nestTables` to TRUE:
311
312```js
313var command = 'select top 1 * from t1 join t2 on t1.id = t2.id';
314var options = {
315 nestTables: true
316};
317client.exec(command, options, function(err, rows) {
318 /* rows will be an array like this now:
319 [{
320 T1: {
321 ID: 1,
322 A: 't1.1.a',
323 B: 't1.1.b',
324 },
325 T2: {
326 ID: 1
327 A: 't2.1.a',
328 B: 't2.1.b',
329 },
330 }]
331 */
332});
333```
334
335It is also possible to return all rows as an array where the order of the column values is exactly the same as in the resultSetMetadata. In this case you have to set the option `rowsAsArray` to TRUE:
336
337```js
338var command = 'select top 1 * from t1 join t2 on t1.id = t2.id';
339var options = {
340 rowsAsArray: true
341};
342client.exec(command, options, function(err, rows) {
343 /* rows will be an array like this now:
344 [[
345 1,
346 't1.1.a',
347 't1.1.b',
348 1
349 't2.1.a',
350 't2.1.b'
351 ]]
352 */
353});
354```
355
356Prepared Statement Execution
357----------------------------
358
359### Prepare a Statement
360
361The client returns a `statement` object which can be executed multiple times:
362
363```js
364client.prepare('select * from DUMMY where DUMMY = ?', function (err, statement){
365 if (err) {
366 return console.error('Error:', err);
367 }
368 // do something with the statement
369 console.log('StatementId', statement.id);
370});
371```
372
373### Execute a Statement
374
375The execution of a prepared statement is similar to the direct statement execution on the client. The difference is that the first parameter of the `exec` function is an array with positional `parameters`. In case of named parameters it can also be an `parameters` object:
376
377```js
378statement.exec(['X'], function (err, rows) {
379 if (err) {
380 return console.error('Error:', err);
381 }
382 console.log('Rows:', rows);
383});
384```
385
386If you use the `execute` function instead of the `exec` function the `resultSet` is returned in the callback like in the direct query execution above.
387
388### Calling Stored Procedures
389
390If you have a stored procedure similar to the following example:
391
392```sql
393create procedure PROC_DUMMY (in a int, in b int, out c int, out d DUMMY, out e TABLES)
394 language sqlscript
395 reads sql data as
396 begin
397 c := :a + :b;
398 d = select * from DUMMY;
399 e = select * from TABLES;
400 end
401```
402You can call it via a prepared statement.
403The second argument is always an object with the scalar parameters.
404If there are no scalar parameters, an empty object ``{}`` is returned.
405The following arguments are the `resultSets`:
406
407```js
408client.prepare('call PROC_DUMMY (?, ?, ?, ?, ?)', function(err, statement){
409 if (err) {
410 return console.error('Prepare error:', err);
411 }
412 statement.exec({
413 A: 3,
414 B: 4
415 }, function(err, parameters, dummyRows, tableRows) {
416 if (err) {
417 return console.error('Exec error:', err);
418 }
419 console.log('Parameters:', parameters);
420 console.log('Dummies:', dummyRows);
421 console.log('Tables:', tableRows);
422 });
423});
424```
425**Note:** Default values for stored procedures are not supported.
426
427### Drop Statement
428
429To drop the statement simply call:
430
431```js
432statement.drop(function(err){
433 if (err) {
434 return console.error('Drop error:', err);
435 }
436 console.log('Statement dropped');
437});
438```
439The callback is optional in this case.
440
441### Using Datetime types
442
443If you want to use DATETIME types in a prepared statement,
444be aware that strings like `'14.04.2016 12:41:11.215'` are not
445processed by the SAP HANA Database but by the node-hdb module.
446Therefore, you must use the exact required format that would be returned
447by a selection made with this module.
448The formats are:
449```js
450TIME: '13:32:20'
451DATE: '2016-04-14'
452TIMESTAMP: '2016-04-14T13:32:20.737'
453SECONDDATE: '2016-04-14T13:32:20'
454```
455
456Another possibility is to use the functions
457`TO_DATE`, `TO_DATS`, `TO_TIME` and `TO_TIMESTAMP` in your
458SQL statement to convert your string to a valid DATETIME type.
459
460Bulk Insert
461---------------
462
463If you want to insert multiple rows with a single execution you just
464have to provide the all parameters as array, for example:
465
466```js
467client.prepare('insert into TEST.NUMBERS values (?, ?)', function(err, statement){
468 if (err) {
469 return console.error('Prepare error:', err);
470 }
471 statement.exec([[1, 'one'], ['2', 'two'], [3, 'three']], function(err, affectedRows) {
472 if (err) {
473 return console.error('Exec error:', err);
474 }
475 console.log('Array of affected rows:', affectedRows);
476 });
477});
478```
479For further details, see: [app9](https://github.com/SAP/node-hdb/blob/master/examples/app9.js).
480
481
482Streaming results
483---------------
484
485If you use the `execute` function of the client or statement instead of the `exec` function, a `resultSet` object is returned in the callback instead of an array of all rows. The `resultSet` object allows you to create an object based `row` stream or an array based stream of `rows` which can be piped to an writer object. Don't forget to close the `resultSet` if you use the `execute` function:
486
487```js
488client.execute('select A, B from TEST.NUMBERS order by A', function(err, rs) {
489 if (err) {
490 return console.error('Error:', err);
491 }
492 rs.setFetchSize(2048);
493 rs.createObjectStream()
494 .pipe(new MyWriteStream())
495 .on('finish', function (){
496 if (!rs.closed) {
497 rs.close();
498 }
499 });
500});
501```
502For further details, see [app4](https://github.com/SAP/node-hdb/blob/master/examples/app4.js).
503
504Transaction handling
505---------------
506
507The default behavior is that each statement is automatically committed. If you want to manually control `commit ` and `rollback` of a transaction, you can do this by calling `setAutoCommit(false)` on the client object:
508
509```js
510function execTransaction(cb) {
511 client.setAutoCommit(false);
512 async.series([
513 client.exec.bind(client, "insert into NUMBERS values (1, 'one')"),
514 client.exec.bind(client, "insert into NUMBERS values (2, 'two')")
515 ], function (err) {
516 if (err) {
517 client.rollback(function(err){
518 if (err) {
519 err.code = 'EROLLBACK';
520 return cb(err);
521 }
522 cb(null, false);
523 });
524 } else {
525 client.commit(function(commitError){
526 if (err) {
527 err.code = 'ECOMMIT';
528 return cb(err);
529 }
530 cb(null, true);
531 });
532 }
533 client.setAutoCommit(true);
534 });
535}
536
537execTransaction(function(err, ok){
538 if (err) {
539 return console.error('Commit or Rollback error', err);
540 }
541 if (ok) {
542 console.log('Commited');
543 } else {
544 console.log('Rolled back');
545 }
546})
547
548```
549
550For further details, see: [tx1](https://github.com/SAP/node-hdb/blob/master/examples/tx1.js).
551
552Streaming Large Objects
553-------------
554
555### Read Streams
556
557Reading large object as stream can be done if you use the `execute` method of client or statement. In this case for all LOB columns a [Lob](https://github.com/SAP/node-hdb/blob/master/lib/protocol/Lob.js) object is returned. You can call `createReadStream` or `read` in order create a readable stream or to read the LOB completely.
558
559### Write Streams
560
561Writing large objects is automatically done. You just have to pass a [`Readable`](http://nodejs.org/api/stream.html#stream_class_stream_readable_1) instance or a buffer object as parameter.
562
563For further details, see: [app7](https://github.com/SAP/node-hdb/blob/master/examples/app7.js).
564
565CESU-8 encoding support
566-------------
567
568The SAP HANA server connectivity protocol uses [CESU-8](https://en.wikipedia.org/wiki/CESU-8) encoding. Node.js does not suport CESU-8 natively and the driver by default converts all text to CESU-8 format in the javascript layer including SQL statements.
569
570Due to the fact that Node.js has built-in support for UTF-8, using UTF-8 in the HDB drivers can lead to performance gains especially for large text data.
571If you are sure that your data contains only [BMP](https://en.wikipedia.org/wiki/Plane_(Unicode)#Basic_Multilingual_Plane) characters, you can disable CESU-8 conversion by setting a flag in the client configuration.
572
573`createClient` accepts the parameter `useCesu8` to disable CESU-8 support. Here is how to provide the configuration:
574
575```js
576var hdb = require('hdb');
577var client = hdb.createClient({
578 host : 'hostname',
579 port : 30015,
580 user : 'user',
581 password : 'secret',
582 useCesu8 : false
583});
584
585```
586
587This setting is per client and cannot be changed later.
588
589__Note:__ Using CESU-8 brings performance penalties proportionate to the text size that has to be converted.
590
591TCP Keepalive
592-------------
593
594To configure TCP keepalive behaviour, include the tcpKeepAliveIdle connect option. The value provided for this option is the number of seconds before an idle connection will begin sending keepalive packets. By default, TCP keepalive will be turned on with a value of 200 seconds. If a value of 0 is specified, keepalive behaviour is determined by the operating system.
595The following example creates a client whose connections will begin sending keepalive packets after 300 seconds.
596
597```js
598var hdb = require('hdb');
599var client = hdb.createClient({
600 host : 'hostname',
601 port : 30015,
602 user : 'user',
603 password : 'secret',
604 tcpKeepAliveIdle : 300
605});
606
607```
608
609TCP keepalive can be explicity disabled by specifying tcpKeepAliveIdle=false as in the example below.
610
611```js
612var hdb = require('hdb');
613var client = hdb.createClient({
614 host : 'hostname',
615 port : 30015,
616 user : 'user',
617 password : 'secret',
618 tcpKeepAliveIdle : false
619});
620
621```
622
623Running tests
624-------------
625
626To run the unit tests for _hdb_ simply run:
627
628```bash
629make test-unit
630```
631
632To run the unit tests as well as acceptance tests for _hdb_ you have to run:
633
634```bash
635make test
636```
637
638For the acceptance tests a database connection has to be established. Therefore, you need to copy the configuration template [config.tpl.json](https://github.com/SAP/node-hdb/blob/master/test/db/config.tpl.json) in the ```test/db``` folder to ```config.json``` and change the connection data to yours. If the ```config.json``` file does not exist a local mock server is started.
639
640
641Running examples
642----------------
643
644For any examples you need a valid ```config.json``` in the ```test/db``` folder.
645
646
647- [app1](https://github.com/SAP/node-hdb/blob/master/examples/app1.js): Simple query.
648- [app2](https://github.com/SAP/node-hdb/blob/master/examples/app2.js): Fetch rows from `ResultSet`.
649- [app3](https://github.com/SAP/node-hdb/blob/master/examples/app3.js): Streaming rows `createObjectStream()`.
650- [app4](https://github.com/SAP/node-hdb/blob/master/examples/app4.js): Pipe row into JSON-Transform and to `stdout`.
651- [app5](https://github.com/SAP/node-hdb/blob/master/examples/app6.js): Stream from the filesystem into a db table.
652- [app6](https://github.com/SAP/node-hdb/blob/master/examples/app5.js): Stream from a db table into the filesystem.
653- [app7](https://github.com/SAP/node-hdb/blob/master/examples/app7.js): Insert a row with a large image into a db table (uses WriteLobRequest and Transaction internally).
654- [app8](https://github.com/SAP/node-hdb/blob/master/examples/app8.js): Automatic reconnect when network connection is lost.
655- [app9](https://github.com/SAP/node-hdb/blob/master/examples/app9.js): Insert multiple rows with large images into a db table as one batch.
656- [app10](https://github.com/SAP/node-hdb/blob/master/examples/app10.js): Usage example of query option `nestTables`.
657- [call1](https://github.com/SAP/node-hdb/blob/master/examples/call1.js): Call stored procedure.
658- [call2](https://github.com/SAP/node-hdb/blob/master/examples/call2.js): Call stored procedure with lob input and output parameter.
659- [call3](https://github.com/SAP/node-hdb/blob/master/examples/call3.js): Call stored procedure with table as input parameter.
660- [tx1](https://github.com/SAP/node-hdb/blob/master/examples/tx1.js): Transaction handling (shows how to use commit and rollback).
661- [csv](https://github.com/SAP/node-hdb/blob/master/examples/csv.js): Stream a db table into csv file.
662- [server](https://github.com/SAP/node-hdb/blob/master/examples/server.js): Stream rows into http response `http://localhost:1337/{schema}/{tablename}?top={top}`
663
664To run the first example:
665
666```bash
667node examples/app1
668```
669
670## Licensing
671
672Copyright 2013-2021 SAP SE or an SAP affiliate company and node-hdb contributors. Please see our [LICENSE](LICENSE) for copyright and license information. Detailed information including third-party components and their licensing/copyright information is available [via the REUSE tool](https://api.reuse.software/info/github.com/SAP/node-hdb).