oracledb 2.1.0 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +174 -54
- package/LICENSE.md +52 -18
- package/README.md +35 -68
- package/binding.gyp +5 -4
- package/lib/connection.js +164 -14
- package/lib/oracledb.js +160 -11
- package/lib/pool.js +33 -22
- package/lib/querystream.js +3 -2
- package/lib/rel.txt +1 -1
- package/odpi/LICENSE.md +1 -1
- package/odpi/README.md +25 -84
- package/odpi/embed/README.md +1 -1
- package/odpi/include/dpi.h +51 -7
- package/odpi/src/dpiConn.c +78 -9
- package/odpi/src/dpiContext.c +24 -10
- package/odpi/src/dpiEnv.c +5 -1
- package/odpi/src/dpiError.c +4 -0
- package/odpi/src/dpiErrorMessages.h +6 -4
- package/odpi/src/dpiImpl.h +125 -68
- package/odpi/src/dpiMsgProps.c +33 -0
- package/odpi/src/dpiObject.c +17 -10
- package/odpi/src/dpiObjectType.c +1 -1
- package/odpi/src/dpiOci.c +55 -40
- package/odpi/src/dpiOracleType.c +2 -2
- package/odpi/src/dpiPool.c +88 -18
- package/odpi/src/dpiStmt.c +57 -36
- package/odpi/src/dpiSubscr.c +117 -9
- package/odpi/src/dpiUtils.c +20 -9
- package/odpi/src/dpiVar.c +504 -430
- package/package/MAKEPKG.BAT +64 -1
- package/package/README.md +9 -5
- package/package/createpackage.js +2 -2
- package/package/extractpackage.js +2 -1
- package/package/oracledbinstall.js +19 -19
- package/package/package.json +4 -4
- package/package.json +4 -4
- package/src/njsCommon.cpp +94 -10
- package/src/njsCommon.h +73 -21
- package/src/njsConnection.cpp +1425 -458
- package/src/njsConnection.h +68 -19
- package/src/njsIntLob.cpp +5 -1
- package/src/njsIntLob.h +1 -1
- package/src/njsMessages.cpp +9 -2
- package/src/njsMessages.h +9 -2
- package/src/njsOracle.cpp +213 -23
- package/src/njsOracle.h +18 -2
- package/src/njsPool.cpp +32 -14
- package/src/njsPool.h +4 -4
- package/src/njsResultSet.cpp +4 -3
- package/src/njsResultSet.h +1 -1
- package/src/njsSubscription.cpp +388 -0
- package/src/njsSubscription.h +111 -0
package/src/njsOracle.h
CHANGED
|
@@ -70,7 +70,7 @@ using namespace v8;
|
|
|
70
70
|
// The suffix should be something like "-dev" or "-beta.1".
|
|
71
71
|
// For production, leave NJS_NODE_ORACLEDB_SUFFIX undefined (not "")
|
|
72
72
|
#define NJS_NODE_ORACLEDB_MAJOR 2
|
|
73
|
-
#define NJS_NODE_ORACLEDB_MINOR
|
|
73
|
+
#define NJS_NODE_ORACLEDB_MINOR 3
|
|
74
74
|
#define NJS_NODE_ORACLEDB_PATCH 0
|
|
75
75
|
#define NJS_NODE_ORACLEDB_SUFFIX
|
|
76
76
|
|
|
@@ -104,11 +104,12 @@ using namespace v8;
|
|
|
104
104
|
// njsOracledb
|
|
105
105
|
// Class exposed to JS for the main module.
|
|
106
106
|
//-----------------------------------------------------------------------------
|
|
107
|
+
class njsSubscription;
|
|
107
108
|
class njsOracledb: public njsCommon
|
|
108
109
|
{
|
|
109
110
|
public:
|
|
110
111
|
|
|
111
|
-
static void Init(
|
|
112
|
+
static void Init(Local<Object> target);
|
|
112
113
|
|
|
113
114
|
bool getAutoCommit() const { return autoCommit; }
|
|
114
115
|
unsigned int getOutFormat() const { return outFormat; }
|
|
@@ -127,9 +128,15 @@ public:
|
|
|
127
128
|
void SetFetchAsBufferTypesOnBaton(njsBaton *baton) const;
|
|
128
129
|
static dpiContext *GetDPIContext() { return globalDPIContext; }
|
|
129
130
|
static void ThrowDPIError(void);
|
|
131
|
+
static njsSubscription *GetSubscription(std::string &name);
|
|
132
|
+
static void SetSubscription(std::string &name, Local<Value> subscription);
|
|
133
|
+
static void ClearSubscription(std::string &name);
|
|
130
134
|
|
|
131
135
|
private:
|
|
132
136
|
|
|
137
|
+
static bool InitCommonCreateParams(njsBaton *baton,
|
|
138
|
+
dpiCommonCreateParams *params);
|
|
139
|
+
|
|
133
140
|
static NAN_METHOD(New);
|
|
134
141
|
|
|
135
142
|
// Get Connection Methods
|
|
@@ -156,13 +163,16 @@ private:
|
|
|
156
163
|
static NAN_GETTER(GetVersionString);
|
|
157
164
|
static NAN_GETTER(GetVersionSuffix);
|
|
158
165
|
static NAN_GETTER(GetConnectionClass);
|
|
166
|
+
static NAN_GETTER(GetEdition);
|
|
159
167
|
static NAN_GETTER(GetExternalAuth);
|
|
160
168
|
static NAN_GETTER(GetFetchArraySize);
|
|
161
169
|
static NAN_GETTER(GetFetchAsString);
|
|
162
170
|
static NAN_GETTER(GetFetchAsBuffer);
|
|
163
171
|
static NAN_GETTER(GetLobPrefetchSize);
|
|
164
172
|
static NAN_GETTER(GetOracleClientVersion);
|
|
173
|
+
static NAN_GETTER(GetOracleClientVersionString);
|
|
165
174
|
static NAN_GETTER(GetPoolPingInterval);
|
|
175
|
+
static NAN_GETTER(GetEvents);
|
|
166
176
|
|
|
167
177
|
// Define Setter Accessors to Properties
|
|
168
178
|
static NAN_SETTER(SetPoolMin);
|
|
@@ -178,13 +188,16 @@ private:
|
|
|
178
188
|
static NAN_SETTER(SetVersionString);
|
|
179
189
|
static NAN_SETTER(SetVersionSuffix);
|
|
180
190
|
static NAN_SETTER(SetConnectionClass);
|
|
191
|
+
static NAN_SETTER(SetEdition);
|
|
181
192
|
static NAN_SETTER(SetExternalAuth);
|
|
182
193
|
static NAN_SETTER(SetFetchArraySize);
|
|
183
194
|
static NAN_SETTER(SetFetchAsString);
|
|
184
195
|
static NAN_SETTER(SetFetchAsBuffer);
|
|
185
196
|
static NAN_SETTER(SetLobPrefetchSize);
|
|
186
197
|
static NAN_SETTER(SetOracleClientVersion);
|
|
198
|
+
static NAN_SETTER(SetOracleClientVersionString);
|
|
187
199
|
static NAN_SETTER(SetPoolPingInterval);
|
|
200
|
+
static NAN_SETTER(SetEvents);
|
|
188
201
|
|
|
189
202
|
njsOracledb();
|
|
190
203
|
~njsOracledb() {
|
|
@@ -194,6 +207,7 @@ private:
|
|
|
194
207
|
uint32_t outFormat;
|
|
195
208
|
bool autoCommit;
|
|
196
209
|
bool extendedMetaData;
|
|
210
|
+
bool events;
|
|
197
211
|
uint32_t maxRows;
|
|
198
212
|
|
|
199
213
|
uint32_t stmtCacheSize;
|
|
@@ -205,6 +219,7 @@ private:
|
|
|
205
219
|
uint32_t poolTimeout;
|
|
206
220
|
|
|
207
221
|
std::string connClass;
|
|
222
|
+
std::string edition;
|
|
208
223
|
bool externalAuth;
|
|
209
224
|
Nan::Persistent<Array> jsFetchAsStringTypes;
|
|
210
225
|
Nan::Persistent<Array> jsFetchAsBufferTypes;
|
|
@@ -213,6 +228,7 @@ private:
|
|
|
213
228
|
int32_t poolPingInterval;
|
|
214
229
|
|
|
215
230
|
static Nan::Persistent<FunctionTemplate> oracledbTemplate_s;
|
|
231
|
+
static Nan::Persistent<Object> subscriptions;
|
|
216
232
|
static dpiContext *globalDPIContext;
|
|
217
233
|
|
|
218
234
|
};
|
package/src/njsPool.cpp
CHANGED
|
@@ -69,7 +69,7 @@ Nan::Persistent<FunctionTemplate> njsPool::poolTemplate_s;
|
|
|
69
69
|
// Initialization function of Pool class. Maps functions and properties
|
|
70
70
|
// from JS to C++.
|
|
71
71
|
//-----------------------------------------------------------------------------
|
|
72
|
-
void njsPool::Init(
|
|
72
|
+
void njsPool::Init(Local<Object> target)
|
|
73
73
|
{
|
|
74
74
|
Nan::HandleScope scope;
|
|
75
75
|
|
|
@@ -77,7 +77,7 @@ void njsPool::Init(Handle<Object> target)
|
|
|
77
77
|
temp->InstanceTemplate()->SetInternalFieldCount(1);
|
|
78
78
|
temp->SetClassName(Nan::New<v8::String>("Pool").ToLocalChecked());
|
|
79
79
|
|
|
80
|
-
Nan::SetPrototypeMethod(temp, "
|
|
80
|
+
Nan::SetPrototypeMethod(temp, "close", Close);
|
|
81
81
|
Nan::SetPrototypeMethod(temp, "getConnection", GetConnection);
|
|
82
82
|
|
|
83
83
|
Nan::SetAccessor(temp->InstanceTemplate(),
|
|
@@ -360,14 +360,24 @@ NAN_METHOD(njsPool::GetConnection)
|
|
|
360
360
|
{
|
|
361
361
|
njsBaton *baton;
|
|
362
362
|
njsPool *pool;
|
|
363
|
+
Local<Object> connProps;
|
|
363
364
|
|
|
364
|
-
pool = (njsPool*) ValidateArgs(info,
|
|
365
|
+
pool = (njsPool*) ValidateArgs(info, 2, 2);
|
|
365
366
|
if (!pool)
|
|
366
367
|
return;
|
|
368
|
+
|
|
369
|
+
/* Get optional connection properties: argument may have empty json */
|
|
370
|
+
if (!pool->GetObjectArg(info, 0, connProps))
|
|
371
|
+
return;
|
|
372
|
+
|
|
367
373
|
baton = pool->CreateBaton(info);
|
|
368
374
|
if (!baton)
|
|
369
375
|
return;
|
|
370
376
|
if (baton->error.empty()) {
|
|
377
|
+
/* Connection Properties: If empty json, values will be empty */
|
|
378
|
+
baton->GetStringFromJSON(connProps, "user", 0, baton->user);
|
|
379
|
+
baton->GetStringFromJSON(connProps, "password", 0, baton->password);
|
|
380
|
+
|
|
371
381
|
baton->jsOracledb.Reset(pool->jsOracledb);
|
|
372
382
|
njsOracledb *oracledb = baton->GetOracledb();
|
|
373
383
|
baton->connClass = oracledb->getConnectionClass();
|
|
@@ -397,8 +407,16 @@ void njsPool::Async_GetConnection(njsBaton *baton)
|
|
|
397
407
|
params.connectionClass = baton->connClass.c_str();
|
|
398
408
|
params.connectionClassLength = baton->connClass.length();
|
|
399
409
|
}
|
|
400
|
-
if (dpiPool_acquireConnection(baton->dpiPoolHandle,
|
|
401
|
-
|
|
410
|
+
if (dpiPool_acquireConnection(baton->dpiPoolHandle,
|
|
411
|
+
baton->user.empty() ?
|
|
412
|
+
NULL : baton->user.c_str(),
|
|
413
|
+
baton->user.empty() ?
|
|
414
|
+
0 : baton->user.length(),
|
|
415
|
+
baton->password.empty () ?
|
|
416
|
+
NULL : baton->password.c_str(),
|
|
417
|
+
baton->password.empty () ?
|
|
418
|
+
0 : baton->password.length(),
|
|
419
|
+
¶ms, &baton->dpiConnHandle) < 0)
|
|
402
420
|
baton->GetDPIError();
|
|
403
421
|
}
|
|
404
422
|
|
|
@@ -416,15 +434,15 @@ void njsPool::Async_AfterGetConnection(njsBaton *baton, Local<Value> argv[])
|
|
|
416
434
|
|
|
417
435
|
|
|
418
436
|
//-----------------------------------------------------------------------------
|
|
419
|
-
// njsPool::
|
|
420
|
-
//
|
|
437
|
+
// njsPool::Close()
|
|
438
|
+
// Close the pool. The reference to the DPI handle is transferred to the
|
|
421
439
|
// baton so that it will cleared automatically upon success and so that the
|
|
422
440
|
// pool is marked as invalid immediately.
|
|
423
441
|
//
|
|
424
442
|
// PARAMETERS
|
|
425
443
|
// - JS callback which will receive (error)
|
|
426
444
|
//-----------------------------------------------------------------------------
|
|
427
|
-
NAN_METHOD(njsPool::
|
|
445
|
+
NAN_METHOD(njsPool::Close)
|
|
428
446
|
{
|
|
429
447
|
njsBaton *baton;
|
|
430
448
|
njsPool *pool;
|
|
@@ -437,17 +455,17 @@ NAN_METHOD(njsPool::Terminate)
|
|
|
437
455
|
return;
|
|
438
456
|
baton->dpiPoolHandle = pool->dpiPoolHandle;
|
|
439
457
|
pool->dpiPoolHandle = NULL;
|
|
440
|
-
baton->QueueWork("
|
|
458
|
+
baton->QueueWork("Close", Async_Close, NULL, 1);
|
|
441
459
|
}
|
|
442
460
|
|
|
443
461
|
|
|
444
462
|
//-----------------------------------------------------------------------------
|
|
445
|
-
// njsPool::
|
|
446
|
-
// Worker function for njsPool::
|
|
447
|
-
//
|
|
448
|
-
//
|
|
463
|
+
// njsPool::Async_Close()
|
|
464
|
+
// Worker function for njsPool::Close() method. If the attempt to
|
|
465
|
+
// close the pool fails, the reference to the DPI handle is transferred back
|
|
466
|
+
// from the baton to the pool.
|
|
449
467
|
//-----------------------------------------------------------------------------
|
|
450
|
-
void njsPool::
|
|
468
|
+
void njsPool::Async_Close(njsBaton *baton)
|
|
451
469
|
{
|
|
452
470
|
if (dpiPool_close(baton->dpiPoolHandle, DPI_MODE_POOL_CLOSE_DEFAULT) < 0) {
|
|
453
471
|
njsPool *pool = (njsPool*) baton->callingObj;
|
package/src/njsPool.h
CHANGED
|
@@ -67,7 +67,7 @@ using namespace node;
|
|
|
67
67
|
class njsPool: public njsCommon {
|
|
68
68
|
public:
|
|
69
69
|
|
|
70
|
-
static void Init(
|
|
70
|
+
static void Init(Local<Object> target);
|
|
71
71
|
static Local<Object> CreateFromBaton(njsBaton *baton);
|
|
72
72
|
bool IsValid() const { return (dpiPoolHandle) ? true : false; }
|
|
73
73
|
njsErrorType GetInvalidErrorType() const { return errInvalidPool; }
|
|
@@ -81,9 +81,9 @@ private:
|
|
|
81
81
|
static void Async_GetConnection(njsBaton *baton);
|
|
82
82
|
static void Async_AfterGetConnection(njsBaton *baton, Local<Value> argv[]);
|
|
83
83
|
|
|
84
|
-
//
|
|
85
|
-
static NAN_METHOD(
|
|
86
|
-
static void
|
|
84
|
+
// Close Methods
|
|
85
|
+
static NAN_METHOD(Close);
|
|
86
|
+
static void Async_Close(njsBaton *baton);
|
|
87
87
|
|
|
88
88
|
// Define Getter Accessors to properties
|
|
89
89
|
static NAN_GETTER(GetPoolMax);
|
package/src/njsResultSet.cpp
CHANGED
|
@@ -85,7 +85,7 @@ njsResultSet::~njsResultSet()
|
|
|
85
85
|
// Initialization function of ResultSet class. Maps functions and properties
|
|
86
86
|
// from JS to C++.
|
|
87
87
|
//-----------------------------------------------------------------------------
|
|
88
|
-
void njsResultSet::Init(
|
|
88
|
+
void njsResultSet::Init(Local<Object> target)
|
|
89
89
|
{
|
|
90
90
|
Nan::HandleScope scope;
|
|
91
91
|
Local<FunctionTemplate> temp = Nan::New<FunctionTemplate>(New);
|
|
@@ -304,7 +304,7 @@ bool njsResultSet::GetRowsHelper(njsBaton *baton, int *moreRows)
|
|
|
304
304
|
}
|
|
305
305
|
if (dpiConn_newVar(this->dpiConnHandle, var->varTypeNum,
|
|
306
306
|
var->nativeTypeNum, numRowsToFetch, var->maxSize, 1, 0, NULL,
|
|
307
|
-
&var->dpiVarHandle, &var->dpiVarData) < 0) {
|
|
307
|
+
&var->dpiVarHandle, &var->buffer.dpiVarData) < 0) {
|
|
308
308
|
baton->GetDPIError();
|
|
309
309
|
return false;
|
|
310
310
|
}
|
|
@@ -384,7 +384,8 @@ void njsResultSet::Async_AfterGetRows(njsBaton *baton, Local<Value> argv[])
|
|
|
384
384
|
else rowAsObj = Nan::New<Object>();
|
|
385
385
|
for (uint32_t col = 0; col < resultSet->numQueryVars; col++) {
|
|
386
386
|
var = &resultSet->queryVars[col];
|
|
387
|
-
if (!njsConnection::GetScalarValueFromVar(baton, var,
|
|
387
|
+
if (!njsConnection::GetScalarValueFromVar(baton, var, &var->buffer,
|
|
388
|
+
row, val))
|
|
388
389
|
return;
|
|
389
390
|
if (baton->outFormat == NJS_ROWS_ARRAY)
|
|
390
391
|
Nan::Set(rowAsArray, col, val);
|
package/src/njsResultSet.h
CHANGED
|
@@ -68,7 +68,7 @@ using namespace node;
|
|
|
68
68
|
class njsResultSet: public njsCommon {
|
|
69
69
|
public:
|
|
70
70
|
|
|
71
|
-
static void Init(
|
|
71
|
+
static void Init(Local<Object> target);
|
|
72
72
|
bool IsValid() const;
|
|
73
73
|
njsErrorType GetInvalidErrorType() const { return errInvalidResultSet; }
|
|
74
74
|
static Local<Object> CreateFromBaton(njsBaton *baton);
|
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
/* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
/******************************************************************************
|
|
4
|
+
*
|
|
5
|
+
* You may not use the identified files except in compliance with the Apache
|
|
6
|
+
* License, Version 2.0 (the "License.")
|
|
7
|
+
*
|
|
8
|
+
* You may obtain a copy of the License at
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0.
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
13
|
+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
*
|
|
15
|
+
* See the License for the specific language governing permissions and
|
|
16
|
+
* limitations under the License.
|
|
17
|
+
*
|
|
18
|
+
* This file uses NAN:
|
|
19
|
+
*
|
|
20
|
+
* Copyright (c) 2015 NAN contributors
|
|
21
|
+
*
|
|
22
|
+
* NAN contributors listed at https://github.com/rvagg/nan#contributors
|
|
23
|
+
*
|
|
24
|
+
* Permission is hereby granted, free of charge, to any person obtaining
|
|
25
|
+
* a copy of this software and associated documentation files (the
|
|
26
|
+
* "Software"), to deal in the Software without restriction, including
|
|
27
|
+
* without limitation the rights to use, copy, modify, merge, publish,
|
|
28
|
+
* distribute, sublicense, and/or sell copies of the Software, and to
|
|
29
|
+
* permit persons to whom the Software is furnished to do so, subject to
|
|
30
|
+
* the following conditions:
|
|
31
|
+
*
|
|
32
|
+
* The above copyright notice and this permission notice shall be
|
|
33
|
+
* included in all copies or substantial portions of the Software.
|
|
34
|
+
*
|
|
35
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
36
|
+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
37
|
+
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
38
|
+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
39
|
+
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
40
|
+
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
41
|
+
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
42
|
+
*
|
|
43
|
+
* NAME
|
|
44
|
+
* njsSubscription.cpp
|
|
45
|
+
*
|
|
46
|
+
* DESCRIPTION
|
|
47
|
+
* Subscription class implementation.
|
|
48
|
+
*
|
|
49
|
+
*****************************************************************************/
|
|
50
|
+
|
|
51
|
+
#include "njsSubscription.h"
|
|
52
|
+
#include "njsOracle.h"
|
|
53
|
+
|
|
54
|
+
using namespace std;
|
|
55
|
+
using namespace node;
|
|
56
|
+
using namespace v8;
|
|
57
|
+
|
|
58
|
+
// peristent ResultSet class handle
|
|
59
|
+
Nan::Persistent<FunctionTemplate> njsSubscription::subscriptionTemplate_s;
|
|
60
|
+
|
|
61
|
+
//-----------------------------------------------------------------------------
|
|
62
|
+
// njsSubscription::~njsSubscription()
|
|
63
|
+
// Destructor. If notifications have been started (noted by the presence of a
|
|
64
|
+
// subscription handle) then notifications will be stopped.
|
|
65
|
+
//-----------------------------------------------------------------------------
|
|
66
|
+
njsSubscription::~njsSubscription()
|
|
67
|
+
{
|
|
68
|
+
if (dpiSubscrHandle)
|
|
69
|
+
StopNotifications();
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
//-----------------------------------------------------------------------------
|
|
74
|
+
// njsSubscription::ProcessNotification()
|
|
75
|
+
// This method is called inside the event loop in the JavaScript main thread.
|
|
76
|
+
// It works together with the EventHandler() method and lets that function
|
|
77
|
+
// know when its work is complete by "waiting" for the barrier.
|
|
78
|
+
//-----------------------------------------------------------------------------
|
|
79
|
+
void njsSubscription::ProcessNotification(uv_async_t *handle)
|
|
80
|
+
{
|
|
81
|
+
njsSubscription *subscription = (njsSubscription*) handle->data;
|
|
82
|
+
Nan::HandleScope scope;
|
|
83
|
+
|
|
84
|
+
Local<Function> callback = Nan::New<Function>(subscription->jsCallback);
|
|
85
|
+
Local<Value> callbackArgs[1];
|
|
86
|
+
callbackArgs[0] = subscription->CreateMessage(subscription->message);
|
|
87
|
+
Nan::AsyncResource *asyncResource =
|
|
88
|
+
new Nan::AsyncResource("node-oracledb:SubscrCallback");
|
|
89
|
+
asyncResource->runInAsyncScope(Nan::GetCurrentContext()->Global(),
|
|
90
|
+
callback, 1, callbackArgs);
|
|
91
|
+
delete asyncResource;
|
|
92
|
+
if (!subscription->message->registered)
|
|
93
|
+
subscription->StopNotifications();
|
|
94
|
+
subscription->WaitOnBarrier();
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
//-----------------------------------------------------------------------------
|
|
99
|
+
// njsSubscription::WaitOnBarrier()
|
|
100
|
+
// Wait on barrier to ensure that only one message is being processed at a
|
|
101
|
+
// time.
|
|
102
|
+
//-----------------------------------------------------------------------------
|
|
103
|
+
void njsSubscription::WaitOnBarrier()
|
|
104
|
+
{
|
|
105
|
+
if (uv_barrier_wait(&barrier) > 0) {
|
|
106
|
+
uv_barrier_destroy(&barrier);
|
|
107
|
+
message = NULL;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
//-----------------------------------------------------------------------------
|
|
113
|
+
// njsSubscription::Init()
|
|
114
|
+
// Initialization function of Subscription class. Maps functions and
|
|
115
|
+
// properties from JS to C++.
|
|
116
|
+
//-----------------------------------------------------------------------------
|
|
117
|
+
void njsSubscription::Init(Local<Object> target)
|
|
118
|
+
{
|
|
119
|
+
Nan::HandleScope scope;
|
|
120
|
+
Local<FunctionTemplate> temp = Nan::New<FunctionTemplate>(New);
|
|
121
|
+
|
|
122
|
+
temp->InstanceTemplate()->SetInternalFieldCount(1);
|
|
123
|
+
temp->SetClassName(Nan::New<v8::String>("Subscription").ToLocalChecked());
|
|
124
|
+
|
|
125
|
+
subscriptionTemplate_s.Reset(temp);
|
|
126
|
+
Nan::Set(target, Nan::New<v8::String>("Subscription").ToLocalChecked(),
|
|
127
|
+
temp->GetFunction());
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
//-----------------------------------------------------------------------------
|
|
132
|
+
// njsSubscription::CreateMessage()
|
|
133
|
+
// Create message object that will be passed to the callback.
|
|
134
|
+
//-----------------------------------------------------------------------------
|
|
135
|
+
Local<Object> njsSubscription::CreateMessage(dpiSubscrMessage *message)
|
|
136
|
+
{
|
|
137
|
+
Nan::EscapableHandleScope scope;
|
|
138
|
+
Local<Object> messageObj = Nan::New<Object>();
|
|
139
|
+
Local<Value> temp;
|
|
140
|
+
|
|
141
|
+
// set type, database name, transaction id and registered flag
|
|
142
|
+
Nan::Set(messageObj, Nan::New<String>("type").ToLocalChecked(),
|
|
143
|
+
Nan::New<Integer>(message->eventType));
|
|
144
|
+
if (message->dbNameLength > 0) {
|
|
145
|
+
temp = Nan::New<String>(message->dbName,
|
|
146
|
+
message->dbNameLength).ToLocalChecked();
|
|
147
|
+
Nan::Set(messageObj, Nan::New<String>("dbName").ToLocalChecked(),
|
|
148
|
+
temp);
|
|
149
|
+
}
|
|
150
|
+
if (message->txIdLength > 0) {
|
|
151
|
+
temp = Nan::CopyBuffer((char*) message->txId,
|
|
152
|
+
message->txIdLength).ToLocalChecked();
|
|
153
|
+
Nan::Set(messageObj, Nan::New<String>("txId").ToLocalChecked(), temp);
|
|
154
|
+
}
|
|
155
|
+
Nan::Set(messageObj, Nan::New<String>("registered").ToLocalChecked(),
|
|
156
|
+
Nan::New<Boolean>(message->registered));
|
|
157
|
+
|
|
158
|
+
// set tables, if applicable
|
|
159
|
+
if (message->numTables > 0) {
|
|
160
|
+
Local<Array> arr = Nan::New<Array>(message->numTables);
|
|
161
|
+
Local<Object> element;
|
|
162
|
+
for (uint32_t i = 0; i < message->numTables; i++) {
|
|
163
|
+
element = CreateMessageTable(&message->tables[i]);
|
|
164
|
+
Nan::Set(arr, i, element);
|
|
165
|
+
}
|
|
166
|
+
Nan::Set(messageObj, Nan::New<String>("tables").ToLocalChecked(), arr);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// set queries, if applicable
|
|
170
|
+
if (message->numQueries > 0) {
|
|
171
|
+
Local<Array> arr = Nan::New<Array>(message->numQueries);
|
|
172
|
+
Local<Object> element;
|
|
173
|
+
for (uint32_t i = 0; i < message->numQueries; i++) {
|
|
174
|
+
element = CreateMessageQuery(&message->queries[i]);
|
|
175
|
+
Nan::Set(arr, i, element);
|
|
176
|
+
}
|
|
177
|
+
Nan::Set(messageObj, Nan::New<String>("queries").ToLocalChecked(),
|
|
178
|
+
arr);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// set queue name, if applicable
|
|
182
|
+
if (message->queueNameLength > 0) {
|
|
183
|
+
temp = Nan::New<String>(message->queueName,
|
|
184
|
+
message->queueNameLength).ToLocalChecked();
|
|
185
|
+
Nan::Set(messageObj, Nan::New<String>("queueName").ToLocalChecked(),
|
|
186
|
+
temp);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// set consumer name, if applicable
|
|
190
|
+
if (message->consumerNameLength > 0) {
|
|
191
|
+
temp = Nan::New<String>(message->consumerName,
|
|
192
|
+
message->consumerNameLength).ToLocalChecked();
|
|
193
|
+
Nan::Set(messageObj, Nan::New<String>("consumerName").ToLocalChecked(),
|
|
194
|
+
temp);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return scope.Escape(messageObj);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
//-----------------------------------------------------------------------------
|
|
202
|
+
// njsSubscription::CreateMessageQuery()
|
|
203
|
+
// Create message query object that will be passed to the callback.
|
|
204
|
+
//-----------------------------------------------------------------------------
|
|
205
|
+
Local<Object> njsSubscription::CreateMessageQuery(
|
|
206
|
+
dpiSubscrMessageQuery *query)
|
|
207
|
+
{
|
|
208
|
+
Nan::EscapableHandleScope scope;
|
|
209
|
+
Local<Object> queryObj = Nan::New<Object>();
|
|
210
|
+
|
|
211
|
+
// set tables, if applicable
|
|
212
|
+
if (query->numTables > 0) {
|
|
213
|
+
Local<Array> arr = Nan::New<Array>(query->numTables);
|
|
214
|
+
Local<Object> element;
|
|
215
|
+
for (uint32_t i = 0; i < query->numTables; i++) {
|
|
216
|
+
element = CreateMessageTable(&query->tables[i]);
|
|
217
|
+
Nan::Set(arr, i, element);
|
|
218
|
+
}
|
|
219
|
+
Nan::Set(queryObj, Nan::New<String>("tables").ToLocalChecked(), arr);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
return scope.Escape(queryObj);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
//-----------------------------------------------------------------------------
|
|
227
|
+
// njsSubscription::CreateMessageRow()
|
|
228
|
+
// Create message row object that will be passed to the callback.
|
|
229
|
+
//-----------------------------------------------------------------------------
|
|
230
|
+
Local<Object> njsSubscription::CreateMessageRow( dpiSubscrMessageRow *row)
|
|
231
|
+
{
|
|
232
|
+
Nan::EscapableHandleScope scope;
|
|
233
|
+
Local<Object> rowObj = Nan::New<Object>();
|
|
234
|
+
Local<Value> temp;
|
|
235
|
+
|
|
236
|
+
// set operation and rowid
|
|
237
|
+
Nan::Set(rowObj, Nan::New<String>("operation").ToLocalChecked(),
|
|
238
|
+
Nan::New<Integer>(row->operation));
|
|
239
|
+
temp = Nan::New<String>(row->rowid, row->rowidLength).ToLocalChecked();
|
|
240
|
+
Nan::Set(rowObj, Nan::New<String>("rowid").ToLocalChecked(), temp);
|
|
241
|
+
|
|
242
|
+
return scope.Escape(rowObj);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
//-----------------------------------------------------------------------------
|
|
247
|
+
// njsSubscription::CreateMessageTable()
|
|
248
|
+
// Create message table object that will be passed to the callback.
|
|
249
|
+
//-----------------------------------------------------------------------------
|
|
250
|
+
Local<Object> njsSubscription::CreateMessageTable(
|
|
251
|
+
dpiSubscrMessageTable *table)
|
|
252
|
+
{
|
|
253
|
+
Nan::EscapableHandleScope scope;
|
|
254
|
+
Local<Object> tableObj = Nan::New<Object>();
|
|
255
|
+
Local<Value> temp;
|
|
256
|
+
|
|
257
|
+
// set operation and name
|
|
258
|
+
Nan::Set(tableObj, Nan::New<String>("operation").ToLocalChecked(),
|
|
259
|
+
Nan::New<Integer>(table->operation));
|
|
260
|
+
temp = Nan::New<String>(table->name, table->nameLength).ToLocalChecked();
|
|
261
|
+
Nan::Set(tableObj, Nan::New<String>("name").ToLocalChecked(), temp);
|
|
262
|
+
|
|
263
|
+
// set rows, if applicable
|
|
264
|
+
if (table->numRows > 0) {
|
|
265
|
+
Local<Array> arr = Nan::New<Array>(table->numRows);
|
|
266
|
+
Local<Object> element;
|
|
267
|
+
for (uint32_t i = 0; i < table->numRows; i++) {
|
|
268
|
+
element = CreateMessageRow(&table->rows[i]);
|
|
269
|
+
Nan::Set(arr, i, element);
|
|
270
|
+
}
|
|
271
|
+
Nan::Set(tableObj, Nan::New<String>("rows").ToLocalChecked(), arr);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
return scope.Escape(tableObj);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
//-----------------------------------------------------------------------------
|
|
279
|
+
// njsSubscription::Create()
|
|
280
|
+
// Create a new subscription object.
|
|
281
|
+
//-----------------------------------------------------------------------------
|
|
282
|
+
Local<Object> njsSubscription::Create()
|
|
283
|
+
{
|
|
284
|
+
Nan::EscapableHandleScope scope;
|
|
285
|
+
Local<Function> func = Nan::GetFunction(Nan::New<FunctionTemplate>(
|
|
286
|
+
subscriptionTemplate_s)).ToLocalChecked();
|
|
287
|
+
Local<Object> obj = Nan::NewInstance(func).ToLocalChecked();
|
|
288
|
+
return scope.Escape(obj);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
//-----------------------------------------------------------------------------
|
|
293
|
+
// njsSubscription::StartNotifications()
|
|
294
|
+
// Start sending notifications to the supplied callback. An async handle is
|
|
295
|
+
// created to ensure the event loop doesn't terminate until the subscription is
|
|
296
|
+
// deregistered in some way (either directly via unsubscribe() or indirectly
|
|
297
|
+
// via the timeout attribute or the quality of service flag that tells a
|
|
298
|
+
// subscription to deregister after the first notification has been received).
|
|
299
|
+
//-----------------------------------------------------------------------------
|
|
300
|
+
void njsSubscription::StartNotifications(njsBaton *baton)
|
|
301
|
+
{
|
|
302
|
+
if (this->name.empty()) {
|
|
303
|
+
this->name = baton->name;
|
|
304
|
+
uv_mutex_init(&this->mutex);
|
|
305
|
+
uv_async_init(uv_default_loop(), &this->async, ProcessNotification);
|
|
306
|
+
this->async.data = this;
|
|
307
|
+
this->dpiSubscrHandle = baton->dpiSubscrHandle;
|
|
308
|
+
baton->dpiSubscrHandle = NULL;
|
|
309
|
+
baton->subscription = NULL;
|
|
310
|
+
Local<Value> subscriptionObj = Nan::New(baton->jsSubscription);
|
|
311
|
+
njsOracledb::SetSubscription(baton->name, subscriptionObj);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
//-----------------------------------------------------------------------------
|
|
317
|
+
// njsSubscription::StopNotifications()
|
|
318
|
+
// Stop sending notifications to the supplied callback. This happens when the
|
|
319
|
+
// subscription is deregistered, either directly via a call to unsubscribe()
|
|
320
|
+
// or indirectly via the timeout attribute or the quality of service flag that
|
|
321
|
+
// tells a subscription to deregister after the first notification has been
|
|
322
|
+
// received.
|
|
323
|
+
//-----------------------------------------------------------------------------
|
|
324
|
+
void njsSubscription::StopNotifications()
|
|
325
|
+
{
|
|
326
|
+
uv_close(reinterpret_cast<uv_handle_t*>(&async), OnStopNotifications);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
//-----------------------------------------------------------------------------
|
|
331
|
+
// njsSubscription::OnStopNotifications()
|
|
332
|
+
// This method is called when the subscription is deregistered. It is called
|
|
333
|
+
// in the main thread and is used to perform any clean up that is necessary.
|
|
334
|
+
//-----------------------------------------------------------------------------
|
|
335
|
+
void njsSubscription::OnStopNotifications(uv_handle_t *handle)
|
|
336
|
+
{
|
|
337
|
+
Nan::HandleScope scope;
|
|
338
|
+
njsSubscription *subscription = (njsSubscription*) handle->data;
|
|
339
|
+
if (subscription->dpiSubscrHandle) {
|
|
340
|
+
dpiSubscr_release(subscription->dpiSubscrHandle);
|
|
341
|
+
subscription->dpiSubscrHandle = NULL;
|
|
342
|
+
}
|
|
343
|
+
uv_mutex_destroy(&subscription->mutex);
|
|
344
|
+
subscription->jsCallback.Reset();
|
|
345
|
+
njsOracledb::ClearSubscription(subscription->name);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
//-----------------------------------------------------------------------------
|
|
350
|
+
// njsSubscription::EventHandler()
|
|
351
|
+
// This method is called by the ODPI-C subscription every time an event is
|
|
352
|
+
// received and is called from outside the event loop in a thread that
|
|
353
|
+
// Javascript does not know anything about. Since multiple calls to
|
|
354
|
+
// uv_async_send() result in only one call to the posted callback, at least
|
|
355
|
+
// until after the callback has completed, a barrier is used. This barrier
|
|
356
|
+
// ensures that uv_async_send() isn't called again until after the message has
|
|
357
|
+
// been successfully processed by the event loop. Note as well that the
|
|
358
|
+
// presence of the OPDI-C subscription handle indicates the subscription is
|
|
359
|
+
// actually ready to receive notifications. There is a short period of time
|
|
360
|
+
// when the subscription is registered but not yet ready to receive
|
|
361
|
+
// notifications.
|
|
362
|
+
//-----------------------------------------------------------------------------
|
|
363
|
+
void njsSubscription::EventHandler(njsSubscription *subscription,
|
|
364
|
+
dpiSubscrMessage *incomingMessage)
|
|
365
|
+
{
|
|
366
|
+
if (subscription->dpiSubscrHandle) {
|
|
367
|
+
uv_mutex_lock(&subscription->mutex);
|
|
368
|
+
uv_barrier_init(&subscription->barrier, 2);
|
|
369
|
+
subscription->message = incomingMessage;
|
|
370
|
+
uv_async_send(&subscription->async);
|
|
371
|
+
subscription->WaitOnBarrier();
|
|
372
|
+
uv_mutex_unlock(&subscription->mutex);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
//-----------------------------------------------------------------------------
|
|
378
|
+
// njsSubscription::New()
|
|
379
|
+
// Create new object accesible from JS. This is always called from within
|
|
380
|
+
// njsSubscription::Create() and never from any external JS.
|
|
381
|
+
//-----------------------------------------------------------------------------
|
|
382
|
+
NAN_METHOD(njsSubscription::New)
|
|
383
|
+
{
|
|
384
|
+
njsSubscription *subscription = new njsSubscription();
|
|
385
|
+
subscription->Wrap(info.Holder());
|
|
386
|
+
info.GetReturnValue().Set(info.Holder());
|
|
387
|
+
}
|
|
388
|
+
|