oracledb 2.2.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 +44 -0
- package/README.md +2 -2
- package/binding.gyp +1 -0
- package/lib/connection.js +46 -0
- package/lib/oracledb.js +84 -0
- package/lib/pool.js +20 -9
- package/lib/querystream.js +2 -1
- package/lib/rel.txt +1 -1
- package/odpi/README.md +2 -2
- package/odpi/include/dpi.h +40 -4
- package/odpi/src/dpiConn.c +64 -5
- package/odpi/src/dpiContext.c +24 -10
- package/odpi/src/dpiEnv.c +5 -1
- package/odpi/src/dpiErrorMessages.h +3 -0
- package/odpi/src/dpiImpl.h +49 -4
- package/odpi/src/dpiOci.c +4 -3
- package/odpi/src/dpiPool.c +88 -18
- package/odpi/src/dpiStmt.c +35 -10
- package/odpi/src/dpiSubscr.c +98 -5
- package/odpi/src/dpiVar.c +7 -1
- package/package/MAKEPKG.BAT +64 -1
- package/package/README.md +5 -1
- package/package/oracledbinstall.js +1 -1
- package/package/package.json +2 -2
- package/package.json +2 -2
- package/src/njsCommon.cpp +56 -6
- package/src/njsCommon.h +28 -8
- package/src/njsConnection.cpp +285 -35
- package/src/njsConnection.h +12 -1
- package/src/njsIntLob.cpp +4 -0
- package/src/njsMessages.cpp +3 -0
- package/src/njsMessages.h +3 -0
- package/src/njsOracle.cpp +56 -0
- package/src/njsOracle.h +6 -1
- package/src/njsPool.cpp +21 -3
- package/src/njsSubscription.cpp +388 -0
- package/src/njsSubscription.h +111 -0
package/src/njsConnection.cpp
CHANGED
|
@@ -51,6 +51,7 @@
|
|
|
51
51
|
|
|
52
52
|
#include "njsConnection.h"
|
|
53
53
|
#include "njsResultSet.h"
|
|
54
|
+
#include "njsSubscription.h"
|
|
54
55
|
#include "njsIntLob.h"
|
|
55
56
|
#include <stdlib.h>
|
|
56
57
|
#include <limits>
|
|
@@ -89,6 +90,8 @@ void njsConnection::Init(Local<Object> target)
|
|
|
89
90
|
Nan::SetPrototypeMethod(tpl, "createLob", CreateLob);
|
|
90
91
|
Nan::SetPrototypeMethod(tpl, "changePassword", ChangePassword);
|
|
91
92
|
Nan::SetPrototypeMethod(tpl, "ping", Ping);
|
|
93
|
+
Nan::SetPrototypeMethod(tpl, "subscribe", Subscribe);
|
|
94
|
+
Nan::SetPrototypeMethod(tpl, "unsubscribe", Unsubscribe);
|
|
92
95
|
|
|
93
96
|
Nan::SetAccessor(tpl->InstanceTemplate(),
|
|
94
97
|
Nan::New<v8::String>("stmtCacheSize").ToLocalChecked(),
|
|
@@ -197,6 +200,9 @@ bool njsConnection::ProcessQueryVars(njsBaton *baton, dpiStmt *dpiStmtHandle,
|
|
|
197
200
|
case DPI_ORACLE_TYPE_NCHAR:
|
|
198
201
|
case DPI_ORACLE_TYPE_RAW:
|
|
199
202
|
vars[i].maxSize = queryInfo.typeInfo.clientSizeInBytes;
|
|
203
|
+
if (queryInfo.typeInfo.oracleTypeNum == DPI_ORACLE_TYPE_RAW &&
|
|
204
|
+
vars[i].varTypeNum == DPI_ORACLE_TYPE_VARCHAR)
|
|
205
|
+
vars[i].maxSize *= 2;
|
|
200
206
|
break;
|
|
201
207
|
case DPI_ORACLE_TYPE_DATE:
|
|
202
208
|
case DPI_ORACLE_TYPE_TIMESTAMP:
|
|
@@ -376,51 +382,56 @@ bool njsConnection::MapByName(njsBaton *baton, dpiQueryInfo *queryInfo,
|
|
|
376
382
|
bool njsConnection::MapByType(njsBaton *baton, dpiQueryInfo *queryInfo,
|
|
377
383
|
dpiOracleTypeNum &targetType)
|
|
378
384
|
{
|
|
379
|
-
|
|
385
|
+
uint32_t i;
|
|
386
|
+
|
|
387
|
+
// handle fetchAsString
|
|
388
|
+
for (i = 0; i < baton->numFetchAsStringTypes; i++) {
|
|
380
389
|
switch (queryInfo->typeInfo.oracleTypeNum) {
|
|
381
390
|
case DPI_ORACLE_TYPE_NUMBER:
|
|
382
391
|
case DPI_ORACLE_TYPE_NATIVE_FLOAT:
|
|
383
392
|
case DPI_ORACLE_TYPE_NATIVE_DOUBLE:
|
|
384
393
|
case DPI_ORACLE_TYPE_NATIVE_INT:
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
return true;
|
|
389
|
-
}
|
|
394
|
+
if (baton->fetchAsStringTypes[i] == NJS_DATATYPE_NUM) {
|
|
395
|
+
targetType = DPI_ORACLE_TYPE_VARCHAR;
|
|
396
|
+
return true;
|
|
390
397
|
}
|
|
391
398
|
break;
|
|
392
399
|
case DPI_ORACLE_TYPE_DATE:
|
|
393
400
|
case DPI_ORACLE_TYPE_TIMESTAMP:
|
|
394
401
|
case DPI_ORACLE_TYPE_TIMESTAMP_TZ:
|
|
395
402
|
case DPI_ORACLE_TYPE_TIMESTAMP_LTZ:
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
return true;
|
|
400
|
-
}
|
|
403
|
+
if (baton->fetchAsStringTypes[i] == NJS_DATATYPE_DATE) {
|
|
404
|
+
targetType = DPI_ORACLE_TYPE_VARCHAR;
|
|
405
|
+
return true;
|
|
401
406
|
}
|
|
402
407
|
break;
|
|
403
408
|
case DPI_ORACLE_TYPE_CLOB:
|
|
404
409
|
case DPI_ORACLE_TYPE_NCLOB:
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
return true;
|
|
409
|
-
}
|
|
410
|
+
if (baton->fetchAsStringTypes[i] == NJS_DATATYPE_CLOB) {
|
|
411
|
+
targetType = DPI_ORACLE_TYPE_VARCHAR;
|
|
412
|
+
return true;
|
|
410
413
|
}
|
|
411
414
|
break;
|
|
412
|
-
case
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
return true;
|
|
417
|
-
}
|
|
415
|
+
case DPI_ORACLE_TYPE_RAW:
|
|
416
|
+
if (baton->fetchAsStringTypes[i] == NJS_DATATYPE_BUFFER) {
|
|
417
|
+
targetType = DPI_ORACLE_TYPE_VARCHAR;
|
|
418
|
+
return true;
|
|
418
419
|
}
|
|
419
420
|
break;
|
|
420
421
|
default:
|
|
421
422
|
break;
|
|
422
423
|
}
|
|
423
424
|
}
|
|
425
|
+
|
|
426
|
+
// handle fetchAsBuffer
|
|
427
|
+
for (i = 0; i < baton->numFetchAsBufferTypes; i++) {
|
|
428
|
+
if (queryInfo->typeInfo.oracleTypeNum == DPI_ORACLE_TYPE_BLOB &&
|
|
429
|
+
baton->fetchAsBufferTypes[i] == NJS_DATATYPE_BLOB) {
|
|
430
|
+
targetType = DPI_ORACLE_TYPE_RAW;
|
|
431
|
+
return true;
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
424
435
|
return false;
|
|
425
436
|
}
|
|
426
437
|
|
|
@@ -630,7 +641,7 @@ bool njsConnection::ProcessExecuteBinds(Local<Object> binds, njsBaton *baton)
|
|
|
630
641
|
|
|
631
642
|
// determine bind names (if binding by name)
|
|
632
643
|
baton->bindArraySize = 1;
|
|
633
|
-
if (!binds->IsArray())
|
|
644
|
+
if (!binds->IsUndefined() && !binds->IsArray())
|
|
634
645
|
bindNames = binds->GetOwnPropertyNames();
|
|
635
646
|
|
|
636
647
|
// initialize variables; if there are no variables, nothing further to do!
|
|
@@ -752,7 +763,7 @@ bool njsConnection::ScanExecuteBindUnit(Local<Object> bindUnit,
|
|
|
752
763
|
for (uint32_t i = 0; i < keys->Length(); i++) {
|
|
753
764
|
Local<String> temp =
|
|
754
765
|
Nan::Get(keys, i).ToLocalChecked().As<String>();
|
|
755
|
-
|
|
766
|
+
Nan::Utf8String utf8str(temp);
|
|
756
767
|
std::string key =
|
|
757
768
|
std::string(*utf8str, static_cast<size_t>(utf8str.length()));
|
|
758
769
|
if (key.compare("dir") == 0 || key.compare("type") == 0 ||
|
|
@@ -852,7 +863,7 @@ bool njsConnection::ProcessExecuteManyBinds(Local<Array> binds,
|
|
|
852
863
|
// the number of bind variables and types
|
|
853
864
|
if (scanRequired)
|
|
854
865
|
bindDefs = Nan::Get(binds, 0).ToLocalChecked();
|
|
855
|
-
if (!bindDefs->IsArray())
|
|
866
|
+
if (!bindDefs->IsUndefined() && !bindDefs->IsArray())
|
|
856
867
|
bindNames = bindDefs.As<Object>()->GetOwnPropertyNames();
|
|
857
868
|
|
|
858
869
|
// initialize variables; if there are no variables, nothing further to do!
|
|
@@ -1023,12 +1034,11 @@ bool njsConnection::InitBindVars(Local<Object> bindObj,
|
|
|
1023
1034
|
|
|
1024
1035
|
// create bind variables (one for each element of the bind array or each
|
|
1025
1036
|
// property of the bind object)
|
|
1026
|
-
if (
|
|
1037
|
+
if (bindObj->IsUndefined())
|
|
1038
|
+
baton->numBindVars = 0;
|
|
1039
|
+
else if (byPosition)
|
|
1027
1040
|
baton->numBindVars = bindObj.As<Array>()->Length();
|
|
1028
|
-
else
|
|
1029
|
-
bindNames = bindObj->GetOwnPropertyNames();
|
|
1030
|
-
baton->numBindVars = bindNames->Length();
|
|
1031
|
-
}
|
|
1041
|
+
else baton->numBindVars = bindNames->Length();
|
|
1032
1042
|
baton->bindVars = new njsVariable[baton->numBindVars];
|
|
1033
1043
|
|
|
1034
1044
|
// initialize bind variables (set position or name)
|
|
@@ -1038,7 +1048,7 @@ bool njsConnection::InitBindVars(Local<Object> bindObj,
|
|
|
1038
1048
|
var->pos = i + 1;
|
|
1039
1049
|
else {
|
|
1040
1050
|
Local<Value> temp = Nan::Get(bindNames, i).ToLocalChecked();
|
|
1041
|
-
|
|
1051
|
+
Nan::Utf8String v8str(temp->ToString());
|
|
1042
1052
|
std::string str = std::string(*v8str,
|
|
1043
1053
|
static_cast<size_t>(v8str.length()));
|
|
1044
1054
|
var->name = ":" + str;
|
|
@@ -1120,7 +1130,7 @@ bool njsConnection::ProcessScalarBindValue(Local<Value> value,
|
|
|
1120
1130
|
bindOk = (var->varTypeNum == DPI_ORACLE_TYPE_VARCHAR ||
|
|
1121
1131
|
var->varTypeNum == DPI_ORACLE_TYPE_CLOB);
|
|
1122
1132
|
if (bindOk) {
|
|
1123
|
-
|
|
1133
|
+
Nan::Utf8String utf8str(value);
|
|
1124
1134
|
if (utf8str.length() == 0)
|
|
1125
1135
|
data->isNull = 1;
|
|
1126
1136
|
else if (inExecuteMany &&
|
|
@@ -1245,7 +1255,7 @@ bool njsConnection::GetBindTypeAndSizeFromValue(njsVariable *var,
|
|
|
1245
1255
|
*maxSize = 1;
|
|
1246
1256
|
} else if (value->IsString()) {
|
|
1247
1257
|
*bindType = NJS_DATATYPE_STR;
|
|
1248
|
-
|
|
1258
|
+
Nan::Utf8String utf8str(value->ToString());
|
|
1249
1259
|
*maxSize = static_cast<uint32_t>(utf8str.length());
|
|
1250
1260
|
} else if (value->IsInt32() || value->IsUint32()) {
|
|
1251
1261
|
*bindType = NJS_DATATYPE_INT;
|
|
@@ -1333,7 +1343,7 @@ bool njsConnection::ProcessExecuteOptions(Local<Object> options,
|
|
|
1333
1343
|
baton->fetchInfo = new njsFetchInfo[baton->numFetchInfo];
|
|
1334
1344
|
for (uint32_t i = 0; i < baton->numFetchInfo; i++) {
|
|
1335
1345
|
Local<Value> temp = Nan::Get(keys, i).ToLocalChecked();
|
|
1336
|
-
|
|
1346
|
+
Nan::Utf8String utf8str(temp->ToString());
|
|
1337
1347
|
baton->fetchInfo[i].name = std::string(*utf8str,
|
|
1338
1348
|
static_cast<size_t>(utf8str.length()));
|
|
1339
1349
|
Local<Object> colInfo =
|
|
@@ -1379,6 +1389,75 @@ bool njsConnection::ProcessExecuteManyOptions(Local<Object> options,
|
|
|
1379
1389
|
}
|
|
1380
1390
|
|
|
1381
1391
|
|
|
1392
|
+
//-----------------------------------------------------------------------------
|
|
1393
|
+
// njsConnection::ProcessSubscriptionOptions()
|
|
1394
|
+
// Processing of options for connection.subscribe(). If an error is detected,
|
|
1395
|
+
// the baton error is populated and false is returned.
|
|
1396
|
+
//-----------------------------------------------------------------------------
|
|
1397
|
+
bool njsConnection::ProcessSubscriptionOptions(Local<Object> options,
|
|
1398
|
+
njsBaton *baton)
|
|
1399
|
+
{
|
|
1400
|
+
Nan::HandleScope scope;
|
|
1401
|
+
uint32_t temp;
|
|
1402
|
+
|
|
1403
|
+
// if subscription doesn't exist, get options for creating subscription
|
|
1404
|
+
if (!baton->dpiSubscrHandle) {
|
|
1405
|
+
temp = DPI_SUBSCR_NAMESPACE_DBCHANGE;
|
|
1406
|
+
if (!baton->GetUnsignedIntFromJSON(options, "namespace", 1,
|
|
1407
|
+
&temp))
|
|
1408
|
+
return false;
|
|
1409
|
+
baton->subscription->SetNamespace((dpiSubscrNamespace) temp);
|
|
1410
|
+
if (!baton->GetStringFromJSON(options, "ipAddress", 1,
|
|
1411
|
+
baton->ipAddress))
|
|
1412
|
+
return false;
|
|
1413
|
+
if (!baton->GetUnsignedIntFromJSON(options, "port", 1,
|
|
1414
|
+
&baton->portNumber))
|
|
1415
|
+
return false;
|
|
1416
|
+
if (!baton->GetUnsignedIntFromJSON(options, "timeout", 1,
|
|
1417
|
+
&baton->timeout))
|
|
1418
|
+
return false;
|
|
1419
|
+
if (!baton->GetUnsignedIntFromJSON(options, "operations", 1,
|
|
1420
|
+
&baton->operations))
|
|
1421
|
+
return false;
|
|
1422
|
+
if (!baton->GetUnsignedIntFromJSON(options, "qos", 1, &baton->qos))
|
|
1423
|
+
return false;
|
|
1424
|
+
if (!baton->GetUnsignedIntFromJSON(options, "groupingClass", 1,
|
|
1425
|
+
&baton->subscrGroupingClass))
|
|
1426
|
+
return false;
|
|
1427
|
+
if (!baton->GetUnsignedIntFromJSON(options, "groupingValue", 1,
|
|
1428
|
+
&baton->subscrGroupingValue))
|
|
1429
|
+
return false;
|
|
1430
|
+
if (!baton->GetUnsignedIntFromJSON(options, "groupingType", 1,
|
|
1431
|
+
&baton->subscrGroupingType))
|
|
1432
|
+
return false;
|
|
1433
|
+
Local<Function> callback;
|
|
1434
|
+
if (!baton->GetFunctionFromJSON(options, "callback", 1, &callback))
|
|
1435
|
+
return false;
|
|
1436
|
+
if (callback.IsEmpty())
|
|
1437
|
+
baton->error = njsMessages::Get(errMissingSubscrCallback);
|
|
1438
|
+
else baton->subscription->SetCallback(callback);
|
|
1439
|
+
}
|
|
1440
|
+
|
|
1441
|
+
// get options that are used for registering queries
|
|
1442
|
+
if (baton->subscription->GetNamespace() == DPI_SUBSCR_NAMESPACE_DBCHANGE) {
|
|
1443
|
+
if (!baton->GetStringFromJSON(options, "sql", 1, baton->sql))
|
|
1444
|
+
return false;
|
|
1445
|
+
if (baton->sql.empty()) {
|
|
1446
|
+
baton->error = njsMessages::Get(errMissingSubscrSql);
|
|
1447
|
+
return false;
|
|
1448
|
+
}
|
|
1449
|
+
Local<Value> binds;
|
|
1450
|
+
Local<String> key = Nan::New("binds").ToLocalChecked();
|
|
1451
|
+
if (!Nan::Get(options, key).ToLocal(&binds))
|
|
1452
|
+
return false;
|
|
1453
|
+
if (!ProcessExecuteBinds(binds.As<Object>(), baton))
|
|
1454
|
+
return false;
|
|
1455
|
+
}
|
|
1456
|
+
|
|
1457
|
+
return true;
|
|
1458
|
+
}
|
|
1459
|
+
|
|
1460
|
+
|
|
1382
1461
|
//-----------------------------------------------------------------------------
|
|
1383
1462
|
// njsConnection::GetScalarValueFromVar()
|
|
1384
1463
|
// Get the value from the DPI variable of the specified type at the specified
|
|
@@ -1591,7 +1670,7 @@ void njsConnection::SetTextAttribute(Nan::NAN_SETTER_ARGS_TYPE args,
|
|
|
1591
1670
|
Nan::ThrowError(errMsg.c_str());
|
|
1592
1671
|
return;
|
|
1593
1672
|
}
|
|
1594
|
-
|
|
1673
|
+
Nan::Utf8String utfstr(value->ToString());
|
|
1595
1674
|
uint32_t valueLength = static_cast<uint32_t>(utfstr.length());
|
|
1596
1675
|
if ((*setter)(connection->dpiConnHandle, *utfstr, valueLength) < 0)
|
|
1597
1676
|
njsOracledb::ThrowDPIError();
|
|
@@ -2387,6 +2466,177 @@ void njsConnection::Async_Ping(njsBaton *baton)
|
|
|
2387
2466
|
}
|
|
2388
2467
|
|
|
2389
2468
|
|
|
2469
|
+
//-----------------------------------------------------------------------------
|
|
2470
|
+
// njsConnection::Subscribe()
|
|
2471
|
+
// Subscribe to events from the database. The provided callback will be
|
|
2472
|
+
// invoked each time a notification is received. The name is used to uniquely
|
|
2473
|
+
// identify a subscription and a reference is stored on the oracledb instance
|
|
2474
|
+
// for use by subsequent calls to subscribe() or unsubscribe().
|
|
2475
|
+
//
|
|
2476
|
+
// PARAMETERS
|
|
2477
|
+
// - JS callback which will receive (error)
|
|
2478
|
+
//-----------------------------------------------------------------------------
|
|
2479
|
+
NAN_METHOD(njsConnection::Subscribe)
|
|
2480
|
+
{
|
|
2481
|
+
njsConnection *connection;
|
|
2482
|
+
std::string name;
|
|
2483
|
+
njsBaton *baton;
|
|
2484
|
+
|
|
2485
|
+
connection = (njsConnection*) ValidateArgs(info, 3, 3);
|
|
2486
|
+
if (!connection)
|
|
2487
|
+
return;
|
|
2488
|
+
if (!connection->GetStringArg(info, 0, name))
|
|
2489
|
+
return;
|
|
2490
|
+
baton = connection->CreateBaton(info);
|
|
2491
|
+
if (!baton)
|
|
2492
|
+
return;
|
|
2493
|
+
baton->name = name;
|
|
2494
|
+
baton->SetDPIConnHandle(connection->dpiConnHandle);
|
|
2495
|
+
baton->subscription = njsOracledb::GetSubscription(name);
|
|
2496
|
+
if (baton->subscription)
|
|
2497
|
+
baton->subscription->SetDPISubscrHandle(baton);
|
|
2498
|
+
else {
|
|
2499
|
+
Local<Object> obj = njsSubscription::Create();
|
|
2500
|
+
baton->subscription = Nan::ObjectWrap::Unwrap<njsSubscription>(obj);
|
|
2501
|
+
baton->jsSubscription.Reset(obj);
|
|
2502
|
+
}
|
|
2503
|
+
Local<Object> options = info[1].As<Object>();
|
|
2504
|
+
ProcessSubscriptionOptions(options, baton);
|
|
2505
|
+
baton->QueueWork("Subscribe", Async_Subscribe, Async_AfterSubscribe, 1);
|
|
2506
|
+
}
|
|
2507
|
+
|
|
2508
|
+
|
|
2509
|
+
//-----------------------------------------------------------------------------
|
|
2510
|
+
// njsConnection::Async_Subscribe()
|
|
2511
|
+
// Worker function for njsConnection::Subscribe() method.
|
|
2512
|
+
//-----------------------------------------------------------------------------
|
|
2513
|
+
void njsConnection::Async_Subscribe(njsBaton *baton)
|
|
2514
|
+
{
|
|
2515
|
+
// create subscription, if necessary
|
|
2516
|
+
if (!baton->dpiSubscrHandle) {
|
|
2517
|
+
dpiSubscrCreateParams params;
|
|
2518
|
+
dpiContext *context = njsOracledb::GetDPIContext();
|
|
2519
|
+
if (dpiContext_initSubscrCreateParams(context, ¶ms) < 0) {
|
|
2520
|
+
baton->GetDPIError();
|
|
2521
|
+
return;
|
|
2522
|
+
}
|
|
2523
|
+
params.subscrNamespace = baton->subscription->GetNamespace();
|
|
2524
|
+
params.name = baton->name.c_str();
|
|
2525
|
+
params.nameLength = baton->name.length();
|
|
2526
|
+
params.protocol = DPI_SUBSCR_PROTO_CALLBACK;
|
|
2527
|
+
params.callback = (dpiSubscrCallback) njsSubscription::EventHandler;
|
|
2528
|
+
params.callbackContext = baton->subscription;
|
|
2529
|
+
params.ipAddress = baton->ipAddress.c_str();
|
|
2530
|
+
params.ipAddressLength = baton->ipAddress.length();
|
|
2531
|
+
params.portNumber = baton->portNumber;
|
|
2532
|
+
params.timeout = baton->timeout;
|
|
2533
|
+
params.qos = (dpiSubscrQOS) baton->qos;
|
|
2534
|
+
params.operations = (dpiOpCode) baton->operations;
|
|
2535
|
+
params.groupingClass = (uint8_t) baton->subscrGroupingClass;
|
|
2536
|
+
params.groupingValue = baton->subscrGroupingValue;
|
|
2537
|
+
params.groupingType = (uint8_t) baton->subscrGroupingType;
|
|
2538
|
+
if (dpiConn_subscribe(baton->dpiConnHandle, ¶ms,
|
|
2539
|
+
&baton->dpiSubscrHandle) < 0) {
|
|
2540
|
+
baton->GetDPIError();
|
|
2541
|
+
return;
|
|
2542
|
+
}
|
|
2543
|
+
}
|
|
2544
|
+
|
|
2545
|
+
// register query if applicable
|
|
2546
|
+
if (!baton->sql.empty()) {
|
|
2547
|
+
|
|
2548
|
+
// prepare statement for registration
|
|
2549
|
+
if (dpiSubscr_prepareStmt(baton->dpiSubscrHandle, baton->sql.c_str(),
|
|
2550
|
+
(uint32_t) baton->sql.length(), &baton->dpiStmtHandle) < 0) {
|
|
2551
|
+
baton->GetDPIError();
|
|
2552
|
+
return;
|
|
2553
|
+
}
|
|
2554
|
+
|
|
2555
|
+
// perform any binds necessary
|
|
2556
|
+
for (uint32_t i = 0; i < baton->numBindVars; i++) {
|
|
2557
|
+
int status;
|
|
2558
|
+
njsVariable *var = &baton->bindVars[i];
|
|
2559
|
+
if (var->name.empty())
|
|
2560
|
+
status = dpiStmt_bindByPos(baton->dpiStmtHandle, var->pos,
|
|
2561
|
+
var->dpiVarHandle);
|
|
2562
|
+
else status = dpiStmt_bindByName(baton->dpiStmtHandle,
|
|
2563
|
+
var->name.c_str(), (uint32_t) var->name.length(),
|
|
2564
|
+
var->dpiVarHandle);
|
|
2565
|
+
if (status < 0) {
|
|
2566
|
+
baton->GetDPIError();
|
|
2567
|
+
return;
|
|
2568
|
+
}
|
|
2569
|
+
}
|
|
2570
|
+
|
|
2571
|
+
// perform execute (which registers the query)
|
|
2572
|
+
if (dpiStmt_execute(baton->dpiStmtHandle, DPI_MODE_EXEC_DEFAULT,
|
|
2573
|
+
NULL) < 0)
|
|
2574
|
+
baton->GetDPIError();
|
|
2575
|
+
|
|
2576
|
+
}
|
|
2577
|
+
}
|
|
2578
|
+
|
|
2579
|
+
|
|
2580
|
+
//-----------------------------------------------------------------------------
|
|
2581
|
+
// njsConnection::Async_AfterSubscribe()
|
|
2582
|
+
// Returns result to JS by invoking JS callback.
|
|
2583
|
+
//-----------------------------------------------------------------------------
|
|
2584
|
+
void njsConnection::Async_AfterSubscribe(njsBaton *baton, Local<Value> argv[])
|
|
2585
|
+
{
|
|
2586
|
+
baton->subscription->StartNotifications(baton);
|
|
2587
|
+
}
|
|
2588
|
+
|
|
2589
|
+
|
|
2590
|
+
//-----------------------------------------------------------------------------
|
|
2591
|
+
// njsConnection::Unsubscribe()
|
|
2592
|
+
// Unsubscribe from events in the database that were originally subscribed
|
|
2593
|
+
// with a call to connection.subscribe().
|
|
2594
|
+
//
|
|
2595
|
+
// PARAMETERS
|
|
2596
|
+
// - JS callback which will receive (error)
|
|
2597
|
+
//-----------------------------------------------------------------------------
|
|
2598
|
+
NAN_METHOD(njsConnection::Unsubscribe)
|
|
2599
|
+
{
|
|
2600
|
+
njsConnection *connection;
|
|
2601
|
+
std::string name;
|
|
2602
|
+
njsBaton *baton;
|
|
2603
|
+
|
|
2604
|
+
connection = (njsConnection*) ValidateArgs(info, 2, 2);
|
|
2605
|
+
if (!connection)
|
|
2606
|
+
return;
|
|
2607
|
+
if (!connection->GetStringArg(info, 0, name))
|
|
2608
|
+
return;
|
|
2609
|
+
baton = connection->CreateBaton(info);
|
|
2610
|
+
if (!baton)
|
|
2611
|
+
return;
|
|
2612
|
+
baton->name = name;
|
|
2613
|
+
baton->subscription = njsOracledb::GetSubscription(name);
|
|
2614
|
+
if (baton->subscription) {
|
|
2615
|
+
baton->subscription->SetDPISubscrHandle(baton);
|
|
2616
|
+
baton->SetDPIConnHandle(connection->dpiConnHandle);
|
|
2617
|
+
} else {
|
|
2618
|
+
baton->error = njsMessages::Get(errInvalidSubscription);
|
|
2619
|
+
}
|
|
2620
|
+
baton->QueueWork("Unsubscribe", Async_Unsubscribe, NULL, 1);
|
|
2621
|
+
}
|
|
2622
|
+
|
|
2623
|
+
|
|
2624
|
+
//-----------------------------------------------------------------------------
|
|
2625
|
+
// njsConnection::Async_Unsubscribe()
|
|
2626
|
+
// Worker function for njsConnection::Unsubscribe() method.
|
|
2627
|
+
//-----------------------------------------------------------------------------
|
|
2628
|
+
void njsConnection::Async_Unsubscribe(njsBaton *baton)
|
|
2629
|
+
{
|
|
2630
|
+
if (dpiConn_unsubscribe(baton->dpiConnHandle, baton->dpiSubscrHandle) < 0)
|
|
2631
|
+
baton->GetDPIError();
|
|
2632
|
+
else {
|
|
2633
|
+
baton->dpiSubscrHandle = NULL;
|
|
2634
|
+
baton->subscription->StopNotifications();
|
|
2635
|
+
}
|
|
2636
|
+
baton->subscription = NULL;
|
|
2637
|
+
}
|
|
2638
|
+
|
|
2639
|
+
|
|
2390
2640
|
//-----------------------------------------------------------------------------
|
|
2391
2641
|
// njsConnection::GetStmtCacheSize()
|
|
2392
2642
|
// Get accessor of "stmtCacheSize" property.
|
package/src/njsConnection.h
CHANGED
|
@@ -73,6 +73,7 @@ public:
|
|
|
73
73
|
bool extendedMetaData);
|
|
74
74
|
static bool GetScalarValueFromVar(njsBaton *baton, njsVariable *var,
|
|
75
75
|
njsVariableBuffer *buffer, uint32_t pos, Local<Value> &value);
|
|
76
|
+
static bool ProcessExecuteBinds(Local<Object> binds, njsBaton *baton);
|
|
76
77
|
static bool ProcessQueryVars(njsBaton* baton, dpiStmt *dpiStmtHandle,
|
|
77
78
|
njsVariable *vars, uint32_t numVars);
|
|
78
79
|
static bool ProcessVars(njsBaton *baton, njsVariable *vars,
|
|
@@ -139,6 +140,15 @@ private:
|
|
|
139
140
|
static NAN_METHOD(Ping);
|
|
140
141
|
static void Async_Ping(njsBaton *baton);
|
|
141
142
|
|
|
143
|
+
// Subscribe Method on Connection class
|
|
144
|
+
static NAN_METHOD(Subscribe);
|
|
145
|
+
static void Async_Subscribe(njsBaton *baton);
|
|
146
|
+
static void Async_AfterSubscribe(njsBaton *baton, Local<Value> argv[]);
|
|
147
|
+
|
|
148
|
+
// Unsubscribe Method on Connection class
|
|
149
|
+
static NAN_METHOD(Unsubscribe);
|
|
150
|
+
static void Async_Unsubscribe(njsBaton *baton);
|
|
151
|
+
|
|
142
152
|
// Define Getter Accessors to properties
|
|
143
153
|
static NAN_GETTER(GetStmtCacheSize);
|
|
144
154
|
static NAN_GETTER(GetClientId);
|
|
@@ -176,7 +186,6 @@ private:
|
|
|
176
186
|
static bool PrepareAndBind(njsBaton* baton);
|
|
177
187
|
static bool ProcessBindValue(Local<Value> bindValue, njsVariable *var,
|
|
178
188
|
njsBaton *baton);
|
|
179
|
-
static bool ProcessExecuteBinds(Local<Object> binds, njsBaton *baton);
|
|
180
189
|
static bool ProcessExecuteManyBinds(Local<Array> binds,
|
|
181
190
|
Local<Object> options, njsBaton *baton);
|
|
182
191
|
static bool ProcessExecuteOptions(Local<Object> options, njsBaton *baton);
|
|
@@ -185,6 +194,8 @@ private:
|
|
|
185
194
|
static bool ProcessScalarBindValue(Local<Value> bindValue,
|
|
186
195
|
njsVariable *var, uint32_t pos, bool inExecuteMany,
|
|
187
196
|
njsBaton *baton);
|
|
197
|
+
static bool ProcessSubscriptionOptions(Local<Object> options,
|
|
198
|
+
njsBaton *baton);
|
|
188
199
|
static bool ProcessVarBuffer(njsBaton *baton, njsVariable *var,
|
|
189
200
|
njsVariableBuffer *buffer);
|
|
190
201
|
static bool ScanExecuteBinds(Local<Object> binds, Local<Array> bindNames,
|
package/src/njsIntLob.cpp
CHANGED
package/src/njsMessages.cpp
CHANGED
|
@@ -89,6 +89,9 @@ static const char *errMsg[] = {
|
|
|
89
89
|
"NJS-058: maxSize of %u is too small for value of length %u in row %u", // errMaxSizeTooSmall
|
|
90
90
|
"NJS-059: type must be specified for bind position %u", // errMissingTypeByPos
|
|
91
91
|
"NJS-060: type must be specified for bind \"%s\"", // errMissingTypeByName
|
|
92
|
+
"NJS-061: invalid subscription", // errInvalidSubscription
|
|
93
|
+
"NJS-062: subscription notification callback missing", // errMissingSubscrCallback
|
|
94
|
+
"NJS-063: subscription notification SQL missing", // errMissingSubscrSql
|
|
92
95
|
};
|
|
93
96
|
|
|
94
97
|
|
package/src/njsMessages.h
CHANGED
package/src/njsOracle.cpp
CHANGED
|
@@ -56,11 +56,15 @@
|
|
|
56
56
|
#include "njsResultSet.h"
|
|
57
57
|
#include "njsMessages.h"
|
|
58
58
|
#include "njsIntLob.h"
|
|
59
|
+
#include "njsSubscription.h"
|
|
59
60
|
#include <sstream>
|
|
60
61
|
|
|
61
62
|
// peristent Oracledb class handle
|
|
62
63
|
Nan::Persistent<FunctionTemplate> njsOracledb::oracledbTemplate_s;
|
|
63
64
|
|
|
65
|
+
// persistent handle for subscriptions
|
|
66
|
+
Nan::Persistent<Object> njsOracledb::subscriptions;
|
|
67
|
+
|
|
64
68
|
// DPI context
|
|
65
69
|
dpiContext *njsOracledb::globalDPIContext = NULL;
|
|
66
70
|
|
|
@@ -191,6 +195,9 @@ void njsOracledb::Init(Local<Object> target)
|
|
|
191
195
|
oracledbTemplate_s.Reset(temp);
|
|
192
196
|
Nan::Set(target, Nan::New<v8::String>("Oracledb").ToLocalChecked(),
|
|
193
197
|
temp->GetFunction());
|
|
198
|
+
|
|
199
|
+
Local<Object> obj = Nan::New<v8::Object>();
|
|
200
|
+
subscriptions.Reset(obj);
|
|
194
201
|
}
|
|
195
202
|
|
|
196
203
|
|
|
@@ -729,6 +736,7 @@ NAN_SETTER(njsOracledb::SetFetchAsString)
|
|
|
729
736
|
switch (type) {
|
|
730
737
|
case NJS_DATATYPE_NUM:
|
|
731
738
|
case NJS_DATATYPE_DATE:
|
|
739
|
+
case NJS_DATATYPE_BUFFER:
|
|
732
740
|
case NJS_DATATYPE_CLOB:
|
|
733
741
|
break;
|
|
734
742
|
default:
|
|
@@ -1052,6 +1060,7 @@ NAN_METHOD(njsOracledb::CreatePool)
|
|
|
1052
1060
|
baton->GetIntFromJSON(poolProps, "poolPingInterval", 0,
|
|
1053
1061
|
&baton->poolPingInterval);
|
|
1054
1062
|
baton->GetBoolFromJSON(poolProps, "externalAuth", 0, &baton->externalAuth);
|
|
1063
|
+
baton->GetBoolFromJSON(poolProps, "homogeneous", 0, &baton->homogeneous);
|
|
1055
1064
|
baton->GetBoolFromJSON(poolProps, "events", 0, &baton->events);
|
|
1056
1065
|
baton->GetStringFromJSON(poolProps, "edition", 0, baton->edition);
|
|
1057
1066
|
baton->lobPrefetchSize = oracledb->lobPrefetchSize;
|
|
@@ -1079,6 +1088,8 @@ void njsOracledb::Async_CreatePool(njsBaton *baton)
|
|
|
1079
1088
|
params.maxSessions = baton->poolMax;
|
|
1080
1089
|
params.sessionIncrement = baton->poolIncrement;
|
|
1081
1090
|
params.externalAuth = baton->externalAuth;
|
|
1091
|
+
params.homogeneous = baton->homogeneous;
|
|
1092
|
+
|
|
1082
1093
|
if (params.externalAuth)
|
|
1083
1094
|
params.homogeneous = 0;
|
|
1084
1095
|
params.pingInterval = baton->poolPingInterval;
|
|
@@ -1183,6 +1194,50 @@ void njsOracledb::ThrowDPIError(void)
|
|
|
1183
1194
|
}
|
|
1184
1195
|
|
|
1185
1196
|
|
|
1197
|
+
//-----------------------------------------------------------------------------
|
|
1198
|
+
// njsOracledb::GetSubscription()
|
|
1199
|
+
// Gets the subscription with the give name if it exists, or returns NULL if
|
|
1200
|
+
// it does not exist in the subscriptions object.
|
|
1201
|
+
//-----------------------------------------------------------------------------
|
|
1202
|
+
njsSubscription *njsOracledb::GetSubscription(std::string &name)
|
|
1203
|
+
{
|
|
1204
|
+
Nan::HandleScope scope;
|
|
1205
|
+
Local<String> nameObj = Nan::New<String>(name).ToLocalChecked();
|
|
1206
|
+
Local<Object> allSubscriptions = Nan::New(subscriptions);
|
|
1207
|
+
Local<Value> value = Nan::Get(allSubscriptions, nameObj).ToLocalChecked();
|
|
1208
|
+
if (value->IsUndefined())
|
|
1209
|
+
return NULL;
|
|
1210
|
+
return Nan::ObjectWrap::Unwrap<njsSubscription>(value.As<Object>());
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
|
|
1214
|
+
//-----------------------------------------------------------------------------
|
|
1215
|
+
// njsOracledb::SetSubscription()
|
|
1216
|
+
// Sets the subscription in the subscriptions object for later recovery,
|
|
1217
|
+
// either to subscribe another query or to unsubscribe.
|
|
1218
|
+
//-----------------------------------------------------------------------------
|
|
1219
|
+
void njsOracledb::SetSubscription(std::string &name, Local<Value> subscription)
|
|
1220
|
+
{
|
|
1221
|
+
Nan::HandleScope scope;
|
|
1222
|
+
Local<String> nameObj = Nan::New<String>(name).ToLocalChecked();
|
|
1223
|
+
Local<Object> allSubscriptions = Nan::New(subscriptions);
|
|
1224
|
+
Nan::Set(allSubscriptions, nameObj, subscription);
|
|
1225
|
+
}
|
|
1226
|
+
|
|
1227
|
+
|
|
1228
|
+
//-----------------------------------------------------------------------------
|
|
1229
|
+
// njsOracledb::ClearSubscription()
|
|
1230
|
+
// Clears the subscription from the subscriptions object.
|
|
1231
|
+
//-----------------------------------------------------------------------------
|
|
1232
|
+
void njsOracledb::ClearSubscription(std::string &name)
|
|
1233
|
+
{
|
|
1234
|
+
Nan::HandleScope scope;
|
|
1235
|
+
Local<String> nameObj = Nan::New<String>(name).ToLocalChecked();
|
|
1236
|
+
Local<Object> allSubscriptions = Nan::New(subscriptions);
|
|
1237
|
+
Nan::Delete(allSubscriptions, nameObj);
|
|
1238
|
+
}
|
|
1239
|
+
|
|
1240
|
+
|
|
1186
1241
|
//-----------------------------------------------------------------------------
|
|
1187
1242
|
// init()
|
|
1188
1243
|
// Invoked when require on oracledb is called.
|
|
@@ -1196,6 +1251,7 @@ extern "C"
|
|
|
1196
1251
|
njsPool::Init(target);
|
|
1197
1252
|
njsResultSet::Init(target);
|
|
1198
1253
|
njsILob::Init(target);
|
|
1254
|
+
njsSubscription::Init(target);
|
|
1199
1255
|
}
|
|
1200
1256
|
|
|
1201
1257
|
NODE_MODULE(oracledb, init)
|
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,6 +104,7 @@ 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:
|
|
@@ -127,6 +128,9 @@ 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
|
|
|
@@ -224,6 +228,7 @@ private:
|
|
|
224
228
|
int32_t poolPingInterval;
|
|
225
229
|
|
|
226
230
|
static Nan::Persistent<FunctionTemplate> oracledbTemplate_s;
|
|
231
|
+
static Nan::Persistent<Object> subscriptions;
|
|
227
232
|
static dpiContext *globalDPIContext;
|
|
228
233
|
|
|
229
234
|
};
|