Skip to content

Commit ed55a78

Browse files
committed
Update Lob streaming best practice doc
1 parent e90d75a commit ed55a78

24 files changed

+155
-196
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,12 @@
3131

3232
- Fixed some static code analysis warnings.
3333

34+
- Updated Lob streaming documentation and examples. Applications should use the
35+
`end` event (for readable streams) and `finish` event (for writeable streams)
36+
instead of the `close` event. The node-oracledb's `lob.close()` method is now
37+
deprecated in favor of the more functional Node.js 8 Stream `destroy()`
38+
method.
39+
3440
## node-oracledb v4.1.0 (26 Nov 2019)
3541

3642
- Added end-to-end tracing attributes

doc/api.md

Lines changed: 86 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,8 @@ For installation information, see the [Node-oracledb Installation Instructions][
259259
- 7.1.4 [`type`](#proplobtype)
260260
- 7.2 [Lob Methods](#lobmethods)
261261
- 7.2.1 [`close()`](#lobclose)
262-
- 7.2.2 [`getData()`](#lobgetdata)
262+
- 7.2.2 [`destroy()`](#lobdestroy)
263+
- 7.2.3 [`getData()`](#lobgetdata)
263264
8. [Pool Class](#poolclass)
264265
- 8.1 [Pool Properties](#poolproperties)
265266
- 8.1.1 [`connectionsInUse`](#proppoolconnectionsinuse)
@@ -486,6 +487,7 @@ For installation information, see the [Node-oracledb Installation Instructions][
486487
- 33.4 [Migrating from node-oracledb 3.0 to node-oracledb 3.1](#migratev30v31)
487488
- 33.5 [Migrating from node-oracledb 3.1 to node-oracledb 4.0](#migratev31v40)
488489
- 33.6 [Migrating from node-oracledb 4.0 to node-oracledb 4.1](#migratev40v41)
490+
- 33.7 [Migrating from node-oracledb 4.1 to node-oracledb 4.2](#migratev41v42)
489491
34. [Useful Resources for Node-oracledb](#otherresources)
490492

491493
## <a name="apimanual"></a> NODE-ORACLEDB API MANUAL
@@ -2913,7 +2915,7 @@ is initially empty. Data can be streamed to the LOB, which can then
29132915
be passed into PL/SQL blocks, or inserted into the database.
29142916

29152917
When no longer required, Lobs created with `createLob()` should be
2916-
closed with [`lob.close()`](#lobclose) because Oracle Database
2918+
closed with [`lob.destroy()`](#lobdestroy) because Oracle Database
29172919
resources are held open if temporary LOBs are not closed.
29182920

29192921
Open temporary LOB usage can be monitored using the view
@@ -4662,7 +4664,7 @@ Number pieceSize
46624664
```
46634665

46644666
The number of bytes (for BLOBs) or characters (for CLOBs) to read for
4665-
each Stream 'data' event of a queried LOB.
4667+
each Stream `data` event of a queried LOB.
46664668

46674669
The default value is [`chunkSize`](#proplobchunksize).
46684670

@@ -4691,6 +4693,9 @@ a LOB is returned by a query.
46914693

46924694
#### <a name="lobclose"></a> 7.2.1 `lob.close()`
46934695

4696+
**Note: this method is deprecated and [`lob.destroy()`](#lobdestroy) should be
4697+
used instead.**
4698+
46944699
##### Prototype
46954700

46964701
Callback:
@@ -4706,19 +4711,18 @@ promise = close();
47064711

47074712
Explicitly closes a Lob.
47084713

4709-
Lobs created with [`createLob()`](#connectioncreatelob) should be
4710-
explicitly closed with [`lob.close()`](#lobclose) when no longer
4711-
needed. This frees resources in node-oracledb and in Oracle Database.
4714+
Lobs created with [`createLob()`](#connectioncreatelob) should be explicitly
4715+
closed when no longer needed. This frees resources in node-oracledb and in
4716+
Oracle Database.
47124717

4713-
Persistent or temporary Lobs returned from the database may also be
4714-
closed with `lob.close()` as long as streaming is not currently
4715-
happening. Note these Lobs are automatically closed when streamed to
4716-
completion or used as the source for an IN OUT bind. If you try to
4717-
close a Lob being used for streaming you will get the error *NJS-023:
4718+
Persistent or temporary Lobs returned from the database may also be closed as
4719+
long as streaming is not currently happening. Note these Lobs are automatically
4720+
closed when streamed to completion or used as the source for an IN OUT bind. If
4721+
you try to close a Lob being used for streaming you will get the error *NJS-023:
47184722
concurrent operations on a Lob are not allowed*.
47194723

4720-
The `lob.close()` method emits the [Node.js Stream][16] 'close' event
4721-
unless the Lob has already been explicitly or automatically closed.
4724+
The `lob.close()` method emits the [Node.js Stream][16] `close` event unless the
4725+
Lob has already been explicitly or automatically closed.
47224726

47234727
The connection must be open when calling `lob.close()` on a temporary
47244728
LOB, such as those created by `createLob()`.
@@ -4740,7 +4744,43 @@ See [Closing Lobs](#closinglobs) for more discussion.
47404744
*Error error* | If `close()` succeeds, `error` is NULL. If an error occurs, then `error` contains the [error message](#errorobj).
47414745

47424746

4743-
#### <a name="lobgetdata"></a> 7.2.2 `lob.getData()`
4747+
#### <a name="lobdestroy"></a> 7.2.2 `lob.destroy()`
4748+
4749+
##### Prototype
4750+
4751+
```
4752+
destroy([Error error]);
4753+
```
4754+
4755+
##### Description
4756+
4757+
This synchronous method explicitly destroys a Lob.
4758+
4759+
Lobs created with [`createLob()`](#connectioncreatelob) should be
4760+
explicitly closed with `lob.destroy()` when no longer
4761+
needed. This frees resources in node-oracledb and in Oracle Database.
4762+
4763+
Persistent or temporary Lobs returned from the database may also be
4764+
closed with `lob.destroy()`. Note these Lobs are automatically closed when streamed to
4765+
completion or used as the source for an IN OUT bind.
4766+
4767+
The `lob.destroy()` method emits the [Node.js Stream][16] `close` event.
4768+
4769+
Once a Lob is destroyed, it cannot be used.
4770+
4771+
See [Closing Lobs](#closinglobs) for more discussion.
4772+
4773+
##### Parameters
4774+
4775+
- ```
4776+
Error error
4777+
```
4778+
4779+
Parameter | Description
4780+
----------------------------|-------------
4781+
*Error error* | This optional parameter is used for the error emitted in an `error` event.
4782+
4783+
#### <a name="lobgetdata"></a> 7.2.3 `lob.getData()`
47444784

47454785
##### Prototype
47464786

@@ -10509,12 +10549,12 @@ get data.
1050910549
The `read(size)` unit is in characters for CLOBs and in bytes for
1051010550
BLOBs.
1051110551

10512-
When reading a LOB from the database, resources are automatically
10513-
released at completion of the readable stream or if there is a LOB
10514-
error. The `lob.close()` method can also be used to close persistent
10515-
LOBs that have not been streamed to completion.
10552+
When reading a LOB from the database, resources are automatically released at
10553+
completion of the readable stream or if there is a LOB error. The
10554+
[`lob.destroy()`](#lobdestroy) method can also be used to close persistent LOBs
10555+
that have not been streamed to completion.
1051610556

10517-
A Readable Lob object starts out in paused mode. If a 'data' event
10557+
A Readable Lob object starts out in paused mode. If a `data` event
1051810558
handler is added, or the Lob is piped to a Writeable stream, then the
1051910559
Lob switches to flowing mode.
1052010560

@@ -10525,7 +10565,7 @@ emitting `data` events.
1052510565

1052610566
Similarly, a Readable Lob operating in the paused mode can be switched
1052710567
to flowing mode by calling `resume()`. It will then start emitting
10528-
'data' events again.
10568+
`data` events again.
1052910569

1053010570
#### Writeable Lobs
1053110571

@@ -10538,11 +10578,9 @@ resources. If the Lob is being piped into, then the `write()` and
1053810578
Writeable Lobs also have events, see the [Node.js Stream][16]
1053910579
documentation.
1054010580

10541-
At the conclusion of streaming into a Writeable Lob, the `close` event
10542-
will occur. It is recommended to put logic such as committing and
10543-
releasing connections in this event (or after it occurs). See
10544-
[lobinsert2.js][51]. It is also recommended that persistent LOBs not
10545-
use the `finish` event handler for cleanup.
10581+
At the conclusion of streaming into a Writeable Lob, the `finish` event will
10582+
occur. It is recommended to put logic such as committing and releasing
10583+
connections in this event (or after it occurs). See [lobinsert2.js][51].
1054610584

1054710585
### <a name="lobinsertdiscussion"></a> 17.4 Using RETURNING INTO to Insert into LOBs
1054810586

@@ -10566,7 +10604,7 @@ if (result.rowsAffected != 1 || result.outBinds.lobbv.length != 1) {
1056610604

1056710605
const doInsert = new Promise((resolve, reject) => {
1056810606
const lob = result.outBinds.lobbv[0];
10569-
lob.on('close', async () => {
10607+
lob.on('finish', async () => {
1057010608
await connection.commit(); // all data is loaded so we can commit it
1057110609
});
1057210610
lob.on('error', async (err) => {
@@ -10587,7 +10625,7 @@ await doInsert;
1058710625

1058810626
This example streams from a file into the table. When the data has
1058910627
been completely streamed, the Lob is automatically closed and the
10590-
'close' event triggered. At this point the data can be committed.
10628+
`close` event triggered. At this point the data can be committed.
1059110629

1059210630
See [lobinsert2.js][51] for the full example.
1059310631

@@ -10610,7 +10648,7 @@ the stream, persistent LOBs are automatically closed.
1061010648
Lobs returned from the database that are not streamed can be passed
1061110649
back to the database as IN binds for PL/SQL blocks, for `INSERT`, or
1061210650
for `UPDATE` statements. The Lobs should then be closed with
10613-
[`lob.close()`](#lobclose). If they are passed as IN OUT binds, they
10651+
[`lob.destroy()`](#lobdestroy). If they are passed as IN OUT binds, they
1061410652
will be automatically closed and the execution
1061510653
[`outBinds`](#execoutbinds) property will contain the updated Lob.
1061610654

@@ -10674,7 +10712,7 @@ if (lob.type === oracledb.CLOB) {
1067410712
}
1067510713

1067610714
lob.on('error', function(err) { cb(err); });
10677-
lob.on('close', function() { cb(null); }); // all done. The Lob is automatically closed.
10715+
lob.on('end', function() { cb(null); }); // all done. The Lob is automatically closed.
1067810716

1067910717
const outStream = fs.createWriteStream('myoutput.txt');
1068010718
outStream.on('error', function(err) { cb(err); });
@@ -10699,7 +10737,7 @@ let str = "";
1069910737

1070010738
lob.setEncoding('utf8'); // set the encoding so we get a 'string' not a 'buffer'
1070110739
lob.on('error', function(err) { cb(err); });
10702-
lob.on('close', function() { cb(null); }); // all done. The Lob is automatically closed.
10740+
lob.on('end', function() { cb(null); }); // all done. The Lob is automatically closed.
1070310741
lob.on('data', function(chunk) {
1070410742
str += chunk; // or use Buffer.concat() for BLOBS
1070510743
});
@@ -10710,7 +10748,7 @@ lob.on('end', function() {
1071010748
```
1071110749

1071210750
Node-oracledb's [`lob.pieceSize`](#proplobpiecesize) can be used to
10713-
control the number of bytes retrieved for each readable 'data' event.
10751+
control the number of bytes retrieved for each readable `data` event.
1071410752
This sets the number of bytes (for BLOBs) or characters (for CLOBs).
1071510753
The default is [`lob.chunkSize`](#proplobchunksize). The
1071610754
recommendation is for it to be a multiple of `chunkSize`.
@@ -10729,7 +10767,7 @@ statement IN binds, however the `RETURNING INTO` method shown above
1072910767
will be more efficient.
1073010768

1073110769
Lobs from `createLob()` will use space in the temporary tablespace
10732-
until [`lob.close()`](#lobclose) is called. Database Administrators
10770+
until [`lob.destroy()`](#lobdestroy) is called. Database Administrators
1073310771
can track this usage by querying [`V$TEMPORARY_LOBS`][13].
1073410772

1073510773
#### Passing a Lob Into PL/SQL
@@ -10774,10 +10812,10 @@ const result = await connection.execute(
1077410812
```
1077510813

1077610814
When the temporary LOB is no longer needed, it must be closed with
10777-
[`lob.close()`](#lobclose):
10815+
[`lob.destroy()`](#lobdestroy):
1077810816

1077910817
```javascript
10780-
await templob.close();
10818+
await templob.destroy();
1078110819
```
1078210820

1078310821
### <a name="closinglobs"></a> 17.7 Closing Lobs
@@ -10787,25 +10825,16 @@ tablespace storage used by a temporary LOB is released. Once a Lob is
1078710825
closed, it can no longer be bound or used for streaming.
1078810826

1078910827
Lobs created with [`createLob()`](#connectioncreatelob) should be
10790-
explicitly closed with [`lob.close()`](#lobclose).
10828+
explicitly closed with [`lob.destroy()`](#lobdestroy).
1079110829

1079210830
Persistent or temporary Lobs returned from the database should be
10793-
closed with `lob.close()` unless they have been automatically closed.
10831+
closed with `lob.destroy()` unless they have been automatically closed.
1079410832
Automatic closing of returned Lobs occurs when:
1079510833

1079610834
- streaming has completed
1079710835
- a stream error occurs
1079810836
- the Lob was used as the source for an IN OUT bind
1079910837

10800-
If you try to close a Lob being used for streaming you will get the
10801-
error *NJS-023: concurrent operations on a Lob are not allowed*.
10802-
10803-
The connection must be open when calling `lob.close()` on a temporary
10804-
LOB.
10805-
10806-
The `lob.close()` method emits the [Node.js Stream][16] 'close' event
10807-
unless the Lob has already been closed explicitly or automatically.
10808-
1080910838
## <a name="jsondatatype"></a> 18. Oracle Database JSON Data type
1081010839

1081110840
Oracle Database 12.1.0.2 introduced native support for JSON data. You
@@ -14449,6 +14478,18 @@ When upgrading from node-oracledb version 4.0 to version 4.1:
1444914478
- Note that the default for [`oracledb.events`](#propdbevents) has reverted to
1445014479
*false*. If you relied on it being *true*, then explicitly set it.
1445114480

14481+
### <a name="migratev41v42"></a> 33.7 Migrating from node-oracledb 4.1 to node-oracledb 4.2
14482+
14483+
- Review the [CHANGELOG][83] and take advantage of new features.
14484+
14485+
- Review the updated Lob stream documentation. The best practice is to use the
14486+
`end` event (for readable streams) and `finish` event (for writeable streams)
14487+
instead of depending on the `close` event. Applications should migrate to the
14488+
Node.js 8 [`destroy()`](#lobdestroy) method instead of the deprecated
14489+
node-oracledb [`close()`](#lobclose) method. Note that unlike `close()`, the
14490+
`destroy()` method does not take a callback parameter. If `destroy()` is
14491+
given an error argument, an `error` event is emitted with this error.
14492+
1445214493
## <a name="otherresources"></a> 34. Useful Resources for Node-oracledb
1445314494

1445414495
Node-oracledb can be installed on the pre-built [*Database App Development

examples/lobbinds.js

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -172,10 +172,6 @@ async function query_plsql_inout(connection) {
172172
});
173173
clob2.on('end', () => {
174174
// console.log("clob2.on 'end' event");
175-
});
176-
clob2.on('close', () => {
177-
// console.log("clob2.on 'close' event");
178-
179175
console.log (" Completed");
180176
if (!errorHandled) {
181177
resolve();

examples/lobinsert2.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. */
1+
/* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. */
22

33
/******************************************************************************
44
*
@@ -65,8 +65,8 @@ async function run() {
6565

6666
let errorHandled = false;
6767

68-
lob.on('close', () => {
69-
// console.log("lob.on 'close' event");
68+
lob.on('finish', () => {
69+
// console.log("lob.on 'finish' event");
7070
connection.commit((err) => {
7171
if (err) {
7272
if (!errorHandled) {

examples/lobstream1.js

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,6 @@ async function doStream(lob, outFileName) {
5757
});
5858
lob.on('end', () => {
5959
// console.log("lob.on 'end' event");
60-
});
61-
lob.on('close', () => {
62-
// console.log("lob.on 'close' event");
6360
if (!errorHandled) {
6461
resolve();
6562
}

examples/lobstream2.js

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,6 @@ async function run() {
8080
clob.on('end', () => {
8181
// console.log("clob.on 'end' event");
8282
console.log(myclob);
83-
});
84-
clob.on('close', () => {
85-
// console.log("clob.on 'close' event");
8683
if (!errorHandled) {
8784
resolve();
8885
}

lib/lob.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,18 @@ class Lob {
6969
this.getData = nodbUtil.promisify(oracledb, getData);
7070
}
7171

72+
// called by stream.destroy() and ensures that the LOB is closed if it has
73+
// not already been closed (never called directly)
74+
_destroy(err, cb) {
75+
this._close(function(closeErr) {
76+
if (closeErr) {
77+
cb(closeErr);
78+
} else {
79+
cb(err);
80+
}
81+
});
82+
}
83+
7284
// implementation of streaming read; if lob is set to auto-close, the lob is
7385
// automatically closed within the C++ code when an error occurs or when
7486
// there are no more bytes to transfer; all that needs to be done in the JS

0 commit comments

Comments
 (0)