Skip to content

Commit 0cbaf15

Browse files
committed
Refactor session callback documentation
1 parent 90687f9 commit 0cbaf15

File tree

4 files changed

+143
-133
lines changed

4 files changed

+143
-133
lines changed

doc/api.md

Lines changed: 127 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -434,9 +434,8 @@ For installation information, see the [Node-oracledb Installation Instructions][
434434
- 15.3.6 [Connection Pool Pinging](#connpoolpinging)
435435
- 15.3.7 [Connection Tagging and Session State](#connpooltagging)
436436
- 15.3.7.1 [Node.js Session Callback](#sessionfixupnode)
437-
- 15.3.7.2 [Connection Tagging](#sessionfixuptagging)
438-
- 15.3.7.3 [Node.js Session Tagging Callback](#sessiontaggingnode)
439-
- 15.3.7.4 [PL/SQL Session Tagging Callback](#sessiontaggingplsql)
437+
- 15.3.7.2 [Node.js Session Tagging Callback](#sessiontaggingnode)
438+
- 15.3.7.3 [PL/SQL Session Tagging Callback](#sessiontaggingplsql)
440439
- 15.3.8 [Heterogeneous Connection Pools and Pool Proxy Authentication](#connpoolproxy)
441440
- 15.4 [External Authentication](#extauth)
442441
- 15.5 [Database Resident Connection Pooling (DRCP)](#drcp)
@@ -9546,154 +9545,148 @@ It will not be called in other cases. Using a callback saves the cost
95469545
of setting session state if a previous user of a connection has
95479546
already set it. The caller of `pool.getConnection()` can always
95489547
assume the correct state is set. The `sessionCallback` can also be a
9549-
PL/SQL procedure, described in [PL/SQL Session Tagging
9550-
Callback](#sessiontaggingplsql).
9548+
PL/SQL procedure.
95519549

9552-
There are three common scenarios for `sessionCallback`:
9553-
9554-
- When all connections in the pool should have the same state: use a
9555-
[Node.js callback without tagging](#sessionfixupnode).
9556-
9557-
- When connections in the pool require different state for different
9558-
users: use a [Node.js callback with tagging](#sessiontaggingnode).
9550+
Connection tagging and `sessionCallback` are new features in
9551+
node-oracledb 3.1.
95599552

9560-
- When using [DRCP](#drcp): use a [PL/SQL callback and
9561-
tagging](#sessiontaggingplsql).
9553+
There are three common scenarios for `sessionCallback`:
95629554

9563-
###### <a name="sessionfixupnode"></a> 15.3.7.1 Node.js Session Callback
9555+
- When all connections in the pool should have the same state use a simple
9556+
[Node.js Session Callback](#sessionfixupnode) without tagging.
9557+
9558+
- When connections in the pool require different state for different users use
9559+
a [Node.js Session Tagging Callback](#sessiontaggingnode).
9560+
9561+
- When using [DRCP](#drcp) then use a [PL/SQL Session Tagging
9562+
Callback](#sessiontaggingplsql).
9563+
9564+
###### <a name="sessionfixuptagging"></a> Connection Tagging
9565+
9566+
Pooled connections can be tagged to record their session state by setting the
9567+
property [`connection.tag`](#propconntag) to a user chosen string that
9568+
represents the state you have set in the connection. A
9569+
`pool.getConnection({tag: 'mytag'})` call can request a connection that has the
9570+
specified tag. If no available connections with that tag exist in the pool, an
9571+
untagged connection or a newly created connection will be returned. If the
9572+
optional `getConnection()` attribute `matchAnyTag` is *true*, then a connection
9573+
that has a different tag may be returned.
9574+
9575+
The [`sessionCallback`](#createpoolpoolattrssessioncallback) function is
9576+
invoked before `pool.getConnection()` returns if the requested tag is not
9577+
identical to the actual tag of the pooled connection. The callback can compare
9578+
the requested tag with the current actual tag in `connection.tag`. Any desired
9579+
state change can be made to the connection and `connection.tag` can be updated
9580+
to record the change. The best practice recommendation is to set the tag in
9581+
the callback function but, if required, a tag can be set anytime prior to
9582+
closing the connection. To clear a connection's tag set `connection.tag` to an
9583+
empty string.
9584+
9585+
You would use tagging where you want `pool.getConnection()` to return a
9586+
connection which has one of several different states. If all connections
9587+
should have the same state then you can simply set `sessionCallback` and not
9588+
use tagging. Also, it may not be worthwhile using a large number of different
9589+
tags, or using tagging where connections are being [dropped](#connectionclose)
9590+
and recreated frequently since the chance of `pool.getConnection()` returning
9591+
an already initialized connection with the requested tag could be low, so most
9592+
`pool.getConnection()` calls would return a connection needing its session
9593+
reset, and tag management will just add overhead.
9594+
9595+
When node-oracledb is using Oracle Client libraries 12.2 or later, then
9596+
node-oracledb uses 'multi-property tags' and the tag string must be of the form
9597+
of one or more "name=value" pairs separated by a semi-colon, for example
9598+
`"loc=uk;lang=cy"`. The Oracle [session pool][6] used by node-oracledb has
9599+
various heuristics to determine which connection is returned to the
9600+
application. Refer to the [multi-property tags documentation][125]. The
9601+
callback function can parse the requested multi-property tag and compare it
9602+
with the connection's actual properties in [`connection.tag`](#propconntag) to
9603+
determine what exact state to set and what value to update `connection.tag` to.
9604+
9605+
##### <a name="sessionfixupnode"></a> 15.3.7.1 Node.js Session Callback
9606+
9607+
When all connections in the pool should have the same state, a simple callback
9608+
can be used.
95649609

95659610
This example sets two NLS settings in each pooled connection. They
95669611
are only set the very first time connections are established to the
95679612
database. The `requestedTag` parameter is ignored because it is only
95689613
valid when tagging is being used:
95699614

95709615
```javascript
9571-
function initSession(connection, requestedTag, cb) {
9616+
function initSession(connection, requestedTag, callbackFn) {
95729617
connection.execute(
95739618
`alter session set nls_date_format = 'YYYY-MM-DD' nls_language = AMERICAN`,
9574-
cb);
9619+
callbackFn);
95759620
}
95769621

95779622
try {
95789623
const pool = await oracledb.createPool({
9579-
user: 'hr',
9580-
password: mypw, // mypw contains the hr schema password
9581-
connectString: 'localhost/XEPDB1',
9582-
sessionCallback: initSession
9583-
});
9624+
user: 'hr',
9625+
password: mypw, // mypw contains the hr schema password
9626+
connectString: 'localhost/XEPDB1',
9627+
sessionCallback: initSession
9628+
});
95849629
. . .
95859630
}
95869631
```
95879632

9588-
If you need to execute multiple SQL statements in the callback, use an
9589-
anonymous PL/SQL block to save [round-trips](#roundtrips) of repeated
9590-
`execute()` calls:
9633+
Note that a single ALTER SESSION statement is used to set multiple properties,
9634+
avoiding [round-trips](#roundtrips) of repeated `execute()` calls. If you need
9635+
to execute multiple SQL statements, then use an anonymous PL/SQL block for the
9636+
same reason:
95919637

95929638
```javascript
9593-
connection.execute(
9594-
`begin
9595-
execute immediate
9596-
'alter session set nls_date_format = ''YYYY-MM-DD'' nls_language = AMERICAN';
9597-
-- other SQL statements could be put here
9598-
end;`,
9599-
cb);
9639+
function initSession(connection, requestedTag, callbackFn) {
9640+
connection.clientId = "Chris";
9641+
connection.execute(
9642+
`begin
9643+
execute immediate 'alter session set nls_date_format = ''YYYY-MM-DD'' nls_language = AMERICAN';
9644+
insert into user_log (id, ts) values (sys_context('userenv', 'client_identifier'), systimestamp);
9645+
commit;
9646+
end;`,
9647+
callbackFn);
9648+
}
96009649
```
96019650

96029651
See [`sessionfixup.js`][126] for a runnable example.
96039652

9604-
Connection tagging and `sessionCallback` are new features in
9605-
node-oracledb 3.1.
9653+
##### <a name="sessiontaggingnode"></a> 15.3.7.2 Node.js Session Tagging Callback
96069654

9607-
###### <a name="sessionfixuptagging"></a> 15.3.7.2 Connection Tagging
9608-
9609-
Pooled connections can be tagged to record their session state by
9610-
setting the property [`connection.tag`](#propconntag) to a string. A
9611-
`pool.getConnection({tag: 'mytag'})` call can request a connection
9612-
that has the specified tag. If no available connections with that tag
9613-
exist in the pool, an untagged connection or a connection with a new
9614-
session will be returned. If the optional `getConnection()` attribute
9615-
`matchAnyTag` is *true*, then a connection that has a different tag
9616-
may be returned.
9617-
9618-
The [`sessionCallback`](#createpoolpoolattrssessioncallback) function
9619-
is invoked before `pool.getConnection()` returns if the requested tag
9620-
is not identical to the actual tag of the pooled connection. The
9621-
callback can compare the requested tag with the current actual tag in
9622-
`connection.tag`. Any desired state change can be made to the
9623-
connection and `connection.tag` can be updated to record the change.
9624-
The best practice recommendation is to set the tag in the callback
9625-
function but, if required, a tag can be set anytime prior to closing
9626-
the connection. To clear a connection's tag set `connection.tag` to
9627-
an empty string.
9628-
9629-
You would use tagging where you want `pool.getConnection()` to return
9630-
a connection which has one of several different states. If all
9631-
connections should have the same state then you can simply set
9632-
`sessionCallback`, as shown [earlier](#sessionfixupnode), and not use
9633-
tagging. Also, it may not be worthwhile using huge numbers of
9634-
different tags or using tagging where connections are being
9635-
[dropped](#connectionclose) or recreated frequently since the chance
9636-
of `pool.getConnection()` returning an already initialized connection
9637-
with the requested tag could be low, so most `pool.getConnection()`
9638-
calls would return a connection needing its session reset, and tag
9639-
management will just add overhead.
9655+
When connections in the pool require different state for different users and
9656+
you are not using DRCP, then use a JavaScript callback with tagging.
96409657

9641-
When node-oracledb is using Oracle Client libraries 12.2 or later,
9642-
then node-oracledb uses 'multi-property tags' and the tag string must
9643-
be of the form of one or more "name=value" pairs separated by a
9644-
semi-colon, for example `"loc=uk;lang=cy"`. The Oracle [session
9645-
pool][6] used by node-oracledb has various heuristics to determine
9646-
which connection is returned to the application. Refer to the
9647-
[multi-property tags documentation][125]. The callback function can
9648-
parse the requested multi-property tag and compare it with the
9649-
connection's actual properties in [`connection.tag`](#propconntag) to
9650-
determine what exact state to set and what value to update
9651-
`connection.tag` to.
9652-
9653-
###### <a name="sessiontaggingnode"></a> 15.3.7.3 Node.js Session Tagging Callback
9654-
9655-
This example Node.js callback function ensures the connection contains
9656-
valid settings for an application-specific "location=USA" property and
9657-
ignores any other properties in the tag that represent session state
9658-
set by other parts of the application (not shown) that are using the
9659-
same pool:
9658+
This example Node.js callback function ensures the connection contains valid
9659+
settings for an application-specific "USER_TZ=X" property where X is a valid
9660+
Oracle timezone:
96609661

96619662
```javascript
9662-
const sessionTag = "location=USA";
9663-
9664-
function initSession(connection, requestedTag, cb) {
9665-
const seen = connection.tag ? connection.tag.split(";").includes(requestedTag) : false;
9666-
if (seen) {
9667-
cb()
9668-
} else {
9669-
connection.execute(
9670-
`ALTER SESSION SET NLS_DATE_FORMAT = 'MM/DD/YY' NLS_LANGUAGE = AMERICAN`,
9671-
(err) => {
9672-
// Update the tag the record the connection's new state
9673-
const k = requestedTag.substr(0, requestedTag.indexOf('=')+1);
9674-
if (connection.tag.indexOf(k) >= 0) {
9675-
// Update value of an existing, matching property in the tag
9676-
const re = new RegExp(k + "[^;]*");
9677-
connection.tag = connection.tag.replace(re, requestedTag);
9678-
} else {
9679-
// the requested property was not previously set in the tag
9680-
connection.tag = requestedTag + ';' + connection.tag;
9681-
}
9682-
cb();
9683-
});
9663+
function initSession(connection, requestedTag, callbackFn) {
9664+
const tagParts = requestedTag.split('=');
9665+
if (tagParts[0] != 'USER_TZ') {
9666+
callbackFn(new Error('Error: Only property USER_TZ is supported'));
9667+
return;
96849668
}
9669+
9670+
connection.execute(
9671+
`ALTER SESSION SET TIME_ZONE = '${tagParts[1]}'`,
9672+
(err) => {
9673+
// Record the connection's new state and return
9674+
connection.tag = requestedTag;
9675+
callbackFn(err);
9676+
}
9677+
);
96859678
}
96869679

96879680
try {
96889681
await oracledb.createPool({
9689-
user: 'hr',
9690-
password: mypw, // mypw contains the hr schema password
9691-
connectString: 'localhost/XEPDB1',
9692-
sessionCallback: initSession
9693-
});
9682+
user: 'hr',
9683+
password: mypw, // mypw contains the hr schema password
9684+
connectString: 'localhost/XEPDB1',
9685+
sessionCallback: initSession
9686+
});
96949687

9695-
// Request a connection with a given tag from the pool cache, but accept any tag being returned.
9696-
const connection = await oracledb.getConnection({poolAlias: 'default', tag: sessionTag, matchAnyTag: true});
9688+
// Get a connection with a given tag (and corresponding session state) from the pool
9689+
const connection = await oracledb.getConnection({poolAlias: 'default', tag: "USER_TZ=UTC" });
96979690

96989691
. . . // Use the connection
96999692

@@ -9703,9 +9696,26 @@ try {
97039696
. . .
97049697
```
97059698

9706-
For runnable examples, see [`sessiontagging1.js`][127] and [`sessiontagging2.js`][128].
9699+
The `initSession()` session callback function is only invoked by
9700+
`getConnection()` if the node-oracledb connection pool cannot find a connection
9701+
with the requested tag. The session callback function adjusts the connection
9702+
state and records the matching tag.
9703+
9704+
Other parts of the application may request connections with different tags.
9705+
Eventually the pool would contain connections with various different states
9706+
(and equivalent tags). Each `getConnection()` call will attempt to return a
9707+
connection which already has the requested tag. If a matching free connection
9708+
cannot be found, the pool may grow or the session state from another connection
9709+
is cleared. Then `initSession()` is called so that the desired connection
9710+
state can be set.
9711+
9712+
For runnable examples, see [`sessiontagging1.js`][127] and
9713+
[`sessiontagging2.js`][128].
9714+
9715+
##### <a name="sessiontaggingplsql"></a> 15.3.7.3 PL/SQL Session Tagging Callback
97079716

9708-
###### <a name="sessiontaggingplsql"></a> 15.3.7.4 PL/SQL Session Tagging Callback
9717+
When using [DRCP](#drcp), tagging is most efficient when using a PL/SQL
9718+
callback.
97099719

97109720
When node-oracledb is using Oracle Client libraries 12.2 or later,
97119721
`sessionCallback` can be a string containing the name of a PL/SQL

examples/sessionfixup.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,15 +58,15 @@ if (process.platform === 'win32') { // Windows
5858
}
5959

6060
// initSession() will be invoked internally when each brand new pooled
61-
// connection is first used. Its callback function 'cb' should be
61+
// connection is first used. Its callback function 'callbackFn' should be
6262
// invoked only when all desired session state has been set.
6363
// In this example, the requestedTag and actualTag parameters are
6464
// ignored. They would be valid if connection tagging was being used.
6565
// If you have multiple SQL statements to execute, put them in a
6666
// single, anonymous PL/SQL block for efficiency.
67-
function initSession(connection, requestedTag, cb) {
67+
function initSession(connection, requestedTag, callbackFn) {
6868
console.log('In initSession');
69-
connection.execute(`ALTER SESSION SET TIME_ZONE = 'UTC'`, cb);
69+
connection.execute(`ALTER SESSION SET TIME_ZONE = 'UTC'`, callbackFn);
7070
}
7171

7272
async function init() {

examples/sessiontagging1.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,18 +63,18 @@ if (process.platform === 'win32') { // Windows
6363
// initSession() will be invoked internally when each brand new pooled
6464
// connection is first used, or when a getConnection() call requests a
6565
// connection tag and a connection without an identical tag is
66-
// returned. Its callback function 'cb' should be invoked only when
67-
// all desired session state has been set.
66+
// returned. Its callback function 'callbackFn' should be invoked only
67+
// when all desired session state has been set.
6868
// This implementation assumes that every pool.getConnection() will
6969
// request a tag having the format USER_TZ=X, where X is a valid
7070
// Oracle timezone. See sessiontagging2.js for a more complete
7171
// implementation.
72-
function initSession(connection, requestedTag, cb) {
72+
function initSession(connection, requestedTag, callbackFn) {
7373
console.log(`In initSession. requested tag: ${requestedTag}, actual tag: ${connection.tag}`);
7474

7575
const tagParts = requestedTag.split('=');
7676
if (tagParts[0] != 'USER_TZ') {
77-
cb(new Error('Error: Only property USER_TZ is supported'));
77+
callbackFn(new Error('Error: Only property USER_TZ is supported'));
7878
return;
7979
}
8080

@@ -85,7 +85,7 @@ function initSession(connection, requestedTag, cb) {
8585
`ALTER SESSION SET TIME_ZONE = '${tagParts[1]}'`,
8686
(err) => {
8787
connection.tag = requestedTag; // Record the connection's new state
88-
cb(err);
88+
callbackFn(err);
8989
}
9090
);
9191
}

0 commit comments

Comments
 (0)