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.
@@ -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
- if (baton->fetchAsStringTypes || baton->fetchAsBufferTypes) {
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
- for (uint32_t i = 0; i < baton->numFetchAsStringTypes; i++) {
386
- if (baton->fetchAsStringTypes[i] == NJS_DATATYPE_NUM) {
387
- targetType = DPI_ORACLE_TYPE_VARCHAR;
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
- for (uint32_t i = 0; i < baton->numFetchAsStringTypes; i++) {
397
- if (baton->fetchAsStringTypes[i] == NJS_DATATYPE_DATE) {
398
- targetType = DPI_ORACLE_TYPE_VARCHAR;
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
- for (uint32_t i = 0; i < baton->numFetchAsStringTypes; i++) {
406
- if (baton->fetchAsStringTypes[i] == NJS_DATATYPE_CLOB) {
407
- targetType = DPI_ORACLE_TYPE_VARCHAR;
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 DPI_ORACLE_TYPE_BLOB:
413
- for (uint32_t i = 0; i < baton->numFetchAsBufferTypes; i++) {
414
- if (baton->fetchAsBufferTypes[i] == NJS_DATATYPE_BLOB) {
415
- targetType = DPI_ORACLE_TYPE_RAW;
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
- v8::String::Utf8Value utf8str(temp);
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 (byPosition)
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
- v8::String::Utf8Value v8str(temp->ToString());
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
- v8::String::Utf8Value utf8str(value);
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
- v8::String::Utf8Value utf8str(value->ToString());
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
- v8::String::Utf8Value utf8str(temp->ToString());
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
- v8::String::Utf8Value utfstr(value->ToString());
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, &params) < 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, &params,
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.
@@ -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
@@ -189,6 +189,10 @@ bool njsILob::ClearDPILobHandle(njsBaton *baton)
189
189
  baton->GetDPIError();
190
190
  return false;
191
191
  }
192
+ if (dpiLob_release(dpiLobHandle) < 0) {
193
+ baton->GetDPIError();
194
+ return false;
195
+ }
192
196
  dpiLobHandle = NULL;
193
197
  return true;
194
198
  }
@@ -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
@@ -92,6 +92,9 @@ typedef enum {
92
92
  errMaxSizeTooSmall,
93
93
  errMissingTypeByPos,
94
94
  errMissingTypeByName,
95
+ errInvalidSubscription,
96
+ errMissingSubscrCallback,
97
+ errMissingSubscrSql,
95
98
 
96
99
  // New ones should be added here
97
100
 
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 2
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
  };