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.
Files changed (52) hide show
  1. package/CHANGELOG.md +174 -54
  2. package/LICENSE.md +52 -18
  3. package/README.md +35 -68
  4. package/binding.gyp +5 -4
  5. package/lib/connection.js +164 -14
  6. package/lib/oracledb.js +160 -11
  7. package/lib/pool.js +33 -22
  8. package/lib/querystream.js +3 -2
  9. package/lib/rel.txt +1 -1
  10. package/odpi/LICENSE.md +1 -1
  11. package/odpi/README.md +25 -84
  12. package/odpi/embed/README.md +1 -1
  13. package/odpi/include/dpi.h +51 -7
  14. package/odpi/src/dpiConn.c +78 -9
  15. package/odpi/src/dpiContext.c +24 -10
  16. package/odpi/src/dpiEnv.c +5 -1
  17. package/odpi/src/dpiError.c +4 -0
  18. package/odpi/src/dpiErrorMessages.h +6 -4
  19. package/odpi/src/dpiImpl.h +125 -68
  20. package/odpi/src/dpiMsgProps.c +33 -0
  21. package/odpi/src/dpiObject.c +17 -10
  22. package/odpi/src/dpiObjectType.c +1 -1
  23. package/odpi/src/dpiOci.c +55 -40
  24. package/odpi/src/dpiOracleType.c +2 -2
  25. package/odpi/src/dpiPool.c +88 -18
  26. package/odpi/src/dpiStmt.c +57 -36
  27. package/odpi/src/dpiSubscr.c +117 -9
  28. package/odpi/src/dpiUtils.c +20 -9
  29. package/odpi/src/dpiVar.c +504 -430
  30. package/package/MAKEPKG.BAT +64 -1
  31. package/package/README.md +9 -5
  32. package/package/createpackage.js +2 -2
  33. package/package/extractpackage.js +2 -1
  34. package/package/oracledbinstall.js +19 -19
  35. package/package/package.json +4 -4
  36. package/package.json +4 -4
  37. package/src/njsCommon.cpp +94 -10
  38. package/src/njsCommon.h +73 -21
  39. package/src/njsConnection.cpp +1425 -458
  40. package/src/njsConnection.h +68 -19
  41. package/src/njsIntLob.cpp +5 -1
  42. package/src/njsIntLob.h +1 -1
  43. package/src/njsMessages.cpp +9 -2
  44. package/src/njsMessages.h +9 -2
  45. package/src/njsOracle.cpp +213 -23
  46. package/src/njsOracle.h +18 -2
  47. package/src/njsPool.cpp +32 -14
  48. package/src/njsPool.h +4 -4
  49. package/src/njsResultSet.cpp +4 -3
  50. package/src/njsResultSet.h +1 -1
  51. package/src/njsSubscription.cpp +388 -0
  52. package/src/njsSubscription.h +111 -0
@@ -301,6 +301,8 @@ static dpiOracleTypeNum dpiOracleType__convertFromOracle(uint16_t typeCode,
301
301
  case DPI_SQLT_FLT:
302
302
  case DPI_SQLT_NUM:
303
303
  case DPI_SQLT_VNU:
304
+ case DPI_SQLT_BFLOAT:
305
+ case DPI_SQLT_BDOUBLE:
304
306
  return DPI_ORACLE_TYPE_NUMBER;
305
307
  case DPI_SQLT_DAT:
306
308
  case DPI_SQLT_ODT:
@@ -314,10 +316,8 @@ static dpiOracleTypeNum dpiOracleType__convertFromOracle(uint16_t typeCode,
314
316
  case DPI_SQLT_INT:
315
317
  case DPI_OCI_TYPECODE_SMALLINT:
316
318
  return DPI_ORACLE_TYPE_NATIVE_INT;
317
- case DPI_SQLT_BFLOAT:
318
319
  case DPI_SQLT_IBFLOAT:
319
320
  return DPI_ORACLE_TYPE_NATIVE_FLOAT;
320
- case DPI_SQLT_BDOUBLE:
321
321
  case DPI_SQLT_IBDOUBLE:
322
322
  return DPI_ORACLE_TYPE_NATIVE_DOUBLE;
323
323
  case DPI_SQLT_DATE:
@@ -119,6 +119,31 @@ static int dpiPool__create(dpiPool *pool, const char *userName,
119
119
  DPI_OCI_ATTR_SPOOL_GETMODE, "set get mode", error) < 0)
120
120
  return DPI_FAILURE;
121
121
 
122
+ // set the session timeout on the pool
123
+ if (dpiOci__attrSet(pool->handle, DPI_OCI_HTYPE_SPOOL, (void*)
124
+ &createParams->timeout, 0, DPI_OCI_ATTR_SPOOL_TIMEOUT,
125
+ "set timeout", error) < 0)
126
+ return DPI_FAILURE;
127
+
128
+ // set the wait timeout on the pool (valid in 12.2 and higher)
129
+ if (pool->env->versionInfo->versionNum > 12 ||
130
+ (pool->env->versionInfo->versionNum == 12 &&
131
+ pool->env->versionInfo->releaseNum >= 2)) {
132
+ if (dpiOci__attrSet(pool->handle, DPI_OCI_HTYPE_SPOOL, (void*)
133
+ &createParams->waitTimeout, 0, DPI_OCI_ATTR_SPOOL_WAIT_TIMEOUT,
134
+ "set wait timeout", error) < 0)
135
+ return DPI_FAILURE;
136
+ }
137
+
138
+ // set the maximum lifetime session on the pool (valid in 12.1 and higher)
139
+ if (pool->env->versionInfo->versionNum >= 12) {
140
+ if (dpiOci__attrSet(pool->handle, DPI_OCI_HTYPE_SPOOL, (void*)
141
+ &createParams->maxLifetimeSession, 0,
142
+ DPI_OCI_ATTR_SPOOL_MAX_LIFETIME_SESSION,
143
+ "set max lifetime session", error) < 0)
144
+ return DPI_FAILURE;
145
+ }
146
+
122
147
  // set reamining attributes directly
123
148
  pool->homogeneous = createParams->homogeneous;
124
149
  pool->externalAuth = createParams->externalAuth;
@@ -154,26 +179,37 @@ void dpiPool__free(dpiPool *pool, dpiError *error)
154
179
  static int dpiPool__getAttributeUint(dpiPool *pool, uint32_t attribute,
155
180
  uint32_t *value, const char *fnName)
156
181
  {
182
+ int status, supported = 1;
157
183
  dpiError error;
158
- int status;
159
184
 
160
185
  if (dpiPool__checkConnected(pool, fnName, &error) < 0)
161
186
  return dpiGen__endPublicFn(pool, DPI_FAILURE, &error);
162
187
  DPI_CHECK_PTR_NOT_NULL(pool, value)
163
188
  switch (attribute) {
164
- case DPI_OCI_ATTR_SPOOL_BUSY_COUNT:
165
189
  case DPI_OCI_ATTR_SPOOL_MAX_LIFETIME_SESSION:
190
+ if (pool->env->versionInfo->versionNum < 12)
191
+ supported = 0;
192
+ break;
193
+ case DPI_OCI_ATTR_SPOOL_WAIT_TIMEOUT:
194
+ if (pool->env->versionInfo->versionNum < 12 ||
195
+ (pool->env->versionInfo->versionNum == 12 &&
196
+ pool->env->versionInfo->releaseNum < 2))
197
+ supported = 0;
198
+ break;
199
+ case DPI_OCI_ATTR_SPOOL_BUSY_COUNT:
166
200
  case DPI_OCI_ATTR_SPOOL_OPEN_COUNT:
167
201
  case DPI_OCI_ATTR_SPOOL_STMTCACHESIZE:
168
202
  case DPI_OCI_ATTR_SPOOL_TIMEOUT:
169
- status = dpiOci__attrGet(pool->handle, DPI_OCI_HTYPE_SPOOL, value,
170
- NULL, attribute, "get attribute value", &error);
171
203
  break;
172
204
  default:
173
- status = dpiError__set(&error, "get attribute",
174
- DPI_ERR_NOT_SUPPORTED);
205
+ supported = 0;
175
206
  break;
176
207
  }
208
+ if (supported)
209
+ status = dpiOci__attrGet(pool->handle, DPI_OCI_HTYPE_SPOOL, value,
210
+ NULL, attribute, "get attribute value", &error);
211
+ else status = dpiError__set(&error, "get attribute value",
212
+ DPI_ERR_NOT_SUPPORTED);
177
213
  return dpiGen__endPublicFn(pool, status, &error);
178
214
  }
179
215
 
@@ -185,10 +221,10 @@ static int dpiPool__getAttributeUint(dpiPool *pool, uint32_t attribute,
185
221
  static int dpiPool__setAttributeUint(dpiPool *pool, uint32_t attribute,
186
222
  uint32_t value, const char *fnName)
187
223
  {
224
+ int status, supported = 1;
225
+ void *ociValue = &value;
188
226
  uint8_t shortValue;
189
- void *ociValue;
190
227
  dpiError error;
191
- int status;
192
228
 
193
229
  // make sure session pool is connected
194
230
  if (dpiPool__checkConnected(pool, fnName, &error) < 0)
@@ -201,18 +237,29 @@ static int dpiPool__setAttributeUint(dpiPool *pool, uint32_t attribute,
201
237
  ociValue = &shortValue;
202
238
  break;
203
239
  case DPI_OCI_ATTR_SPOOL_MAX_LIFETIME_SESSION:
240
+ if (pool->env->versionInfo->versionNum < 12)
241
+ supported = 0;
242
+ break;
243
+ case DPI_OCI_ATTR_SPOOL_WAIT_TIMEOUT:
244
+ if (pool->env->versionInfo->versionNum < 12 ||
245
+ (pool->env->versionInfo->versionNum == 12 &&
246
+ pool->env->versionInfo->releaseNum < 2))
247
+ supported = 0;
248
+ break;
204
249
  case DPI_OCI_ATTR_SPOOL_STMTCACHESIZE:
205
250
  case DPI_OCI_ATTR_SPOOL_TIMEOUT:
206
- ociValue = &value;
207
251
  break;
208
252
  default:
209
- dpiError__set(&error, "set attribute", DPI_ERR_NOT_SUPPORTED);
210
- return dpiGen__endPublicFn(pool, DPI_FAILURE, &error);
253
+ supported = 0;
254
+ break;
211
255
  }
212
256
 
213
257
  // set value in the OCI
214
- status = dpiOci__attrSet(pool->handle, DPI_OCI_HTYPE_SPOOL, ociValue, 0,
215
- attribute, "set attribute value", &error);
258
+ if (supported)
259
+ status = dpiOci__attrSet(pool->handle, DPI_OCI_HTYPE_SPOOL, ociValue,
260
+ 0, attribute, "set attribute value", &error);
261
+ else status = dpiError__set(&error, "set attribute value",
262
+ DPI_ERR_NOT_SUPPORTED);
216
263
  return dpiGen__endPublicFn(pool, status, &error);
217
264
  }
218
265
 
@@ -226,7 +273,6 @@ int dpiPool_acquireConnection(dpiPool *pool, const char *userName,
226
273
  dpiConnCreateParams *params, dpiConn **conn)
227
274
  {
228
275
  dpiConnCreateParams localParams;
229
- size_t structSize;
230
276
  dpiError error;
231
277
  int status;
232
278
 
@@ -239,10 +285,9 @@ int dpiPool_acquireConnection(dpiPool *pool, const char *userName,
239
285
 
240
286
  // use default parameters if none provided
241
287
  if (!params || pool->env->context->dpiMinorVersion == 0) {
242
- dpiContext__initConnCreateParams(pool->env->context, &localParams,
243
- &structSize);
288
+ dpiContext__initConnCreateParams(&localParams);
244
289
  if (params)
245
- memcpy(&localParams, params, structSize);
290
+ memcpy(&localParams, params, sizeof(dpiConnCreateParams__v20));
246
291
  params = &localParams;
247
292
  }
248
293
 
@@ -309,8 +354,11 @@ int dpiPool_create(const dpiContext *context, const char *userName,
309
354
  dpiContext__initCommonCreateParams(&localCommonParams);
310
355
  commonParams = &localCommonParams;
311
356
  }
312
- if (!createParams) {
357
+ if (!createParams || context->dpiMinorVersion < 4) {
313
358
  dpiContext__initPoolCreateParams(&localCreateParams);
359
+ if (createParams)
360
+ memcpy(&localCreateParams, createParams,
361
+ sizeof(dpiPoolCreateParams__v23));
314
362
  createParams = &localCreateParams;
315
363
  }
316
364
 
@@ -433,6 +481,17 @@ int dpiPool_getTimeout(dpiPool *pool, uint32_t *value)
433
481
  }
434
482
 
435
483
 
484
+ //-----------------------------------------------------------------------------
485
+ // dpiPool_getWaitTimeout() [PUBLIC]
486
+ // Return the pool's wait timeout value.
487
+ //-----------------------------------------------------------------------------
488
+ int dpiPool_getWaitTimeout(dpiPool *pool, uint32_t *value)
489
+ {
490
+ return dpiPool__getAttributeUint(pool, DPI_OCI_ATTR_SPOOL_WAIT_TIMEOUT,
491
+ value, __func__);
492
+ }
493
+
494
+
436
495
  //-----------------------------------------------------------------------------
437
496
  // dpiPool_release() [PUBLIC]
438
497
  // Release a reference to the pool.
@@ -486,3 +545,14 @@ int dpiPool_setTimeout(dpiPool *pool, uint32_t value)
486
545
  __func__);
487
546
  }
488
547
 
548
+
549
+ //-----------------------------------------------------------------------------
550
+ // dpiPool_setWaitTimeout() [PUBLIC]
551
+ // Set the pool's wait timeout value.
552
+ //-----------------------------------------------------------------------------
553
+ int dpiPool_setWaitTimeout(dpiPool *pool, uint32_t value)
554
+ {
555
+ return dpiPool__setAttributeUint(pool, DPI_OCI_ATTR_SPOOL_WAIT_TIMEOUT,
556
+ value, __func__);
557
+ }
558
+
@@ -22,7 +22,7 @@ static int dpiStmt__getQueryInfo(dpiStmt *stmt, uint32_t pos,
22
22
  static int dpiStmt__getQueryInfoFromParam(dpiStmt *stmt, void *param,
23
23
  dpiQueryInfo *info, dpiError *error);
24
24
  static int dpiStmt__postFetch(dpiStmt *stmt, dpiError *error);
25
- static int dpiStmt__preFetch(dpiStmt *stmt, dpiError *error);
25
+ static int dpiStmt__beforeFetch(dpiStmt *stmt, dpiError *error);
26
26
  static int dpiStmt__reExecute(dpiStmt *stmt, uint32_t numIters,
27
27
  uint32_t mode, dpiError *error);
28
28
 
@@ -184,18 +184,13 @@ static int dpiStmt__bind(dpiStmt *stmt, dpiVar *var, int addReference,
184
184
  }
185
185
 
186
186
  // bind object, if applicable
187
- if (var->objectIndicator && dpiOci__bindObject(var, bindHandle, error) < 0)
187
+ if (var->buffer.objectIndicator &&
188
+ dpiOci__bindObject(var, bindHandle, error) < 0)
188
189
  return DPI_FAILURE;
189
190
 
190
- // setup dynamic bind, if applicable; reset actual array size to 0 as
191
- // dynamic bind doesn't get called if there are no rows returned in a DML
192
- // returning statement
193
- if (dynamicBind) {
194
- if (stmt->isReturning)
195
- var->actualArraySize = 0;
196
- if (dpiOci__bindDynamic(var, bindHandle, error) < 0)
197
- return DPI_FAILURE;
198
- }
191
+ // setup dynamic bind, if applicable
192
+ if (dynamicBind && dpiOci__bindDynamic(var, bindHandle, error) < 0)
193
+ return DPI_FAILURE;
199
194
 
200
195
  return DPI_SUCCESS;
201
196
  }
@@ -510,7 +505,7 @@ static int dpiStmt__define(dpiStmt *stmt, uint32_t pos, dpiVar *var,
510
505
  }
511
506
 
512
507
  // define objects, if applicable
513
- if (var->objectIndicator && dpiOci__defineObject(var, defineHandle,
508
+ if (var->buffer.objectIndicator && dpiOci__defineObject(var, defineHandle,
514
509
  error) < 0)
515
510
  return DPI_FAILURE;
516
511
 
@@ -543,21 +538,28 @@ static int dpiStmt__execute(dpiStmt *stmt, uint32_t numIters,
543
538
  // buffer structures
544
539
  for (i = 0; i < stmt->numBindVars; i++) {
545
540
  var = stmt->bindVars[i].var;
546
- for (j = 0; j < var->maxArraySize; j++) {
547
- data = &var->externalData[j];
541
+ if (var->isArray && numIters > 1)
542
+ return dpiError__set(error, "bind array var",
543
+ DPI_ERR_ARRAY_VAR_NOT_SUPPORTED);
544
+ for (j = 0; j < var->buffer.maxArraySize; j++) {
545
+ data = &var->buffer.externalData[j];
548
546
  if (var->type->oracleTypeNum == DPI_ORACLE_TYPE_STMT &&
549
547
  data->value.asStmt == stmt)
550
548
  return dpiError__set(error, "bind to self",
551
549
  DPI_ERR_NOT_SUPPORTED);
552
- if (dpiVar__setValue(var, j, data, error) < 0)
550
+ if (dpiVar__setValue(var, &var->buffer, j, data, error) < 0)
553
551
  return DPI_FAILURE;
552
+ if (var->dynBindBuffers)
553
+ var->dynBindBuffers[j].actualArraySize = 0;
554
554
  }
555
555
  if (stmt->isReturning || var->isDynamic)
556
556
  var->error = error;
557
557
  }
558
558
 
559
- // for queries, set the prefetch rows to the fetch array size in order to
560
- // avoid the network round trip for the first fetch
559
+ // for queries, set the OCI prefetch to a fixed value; this prevents an
560
+ // additional round trip for single row fetches while avoiding the overhead
561
+ // of copying from the OCI prefetch buffer to our own buffers for larger
562
+ // fetches
561
563
  if (stmt->statementType == DPI_STMT_TYPE_SELECT) {
562
564
  prefetchSize = DPI_PREFETCH_ROWS_DEFAULT;
563
565
  if (dpiOci__attrSet(stmt->handle, DPI_OCI_HTYPE_STMT, &prefetchSize,
@@ -595,9 +597,8 @@ static int dpiStmt__execute(dpiStmt *stmt, uint32_t numIters,
595
597
  stmt->statementType == DPI_STMT_TYPE_CALL) {
596
598
  for (i = 0; i < stmt->numBindVars; i++) {
597
599
  var = stmt->bindVars[i].var;
598
- for (j = 0; j < var->maxArraySize; j++) {
599
- if (dpiVar__getValue(var, j, &var->externalData[j],
600
- error) < 0)
600
+ for (j = 0; j < var->buffer.maxArraySize; j++) {
601
+ if (dpiVar__getValue(var, &var->buffer, j, 0, error) < 0)
601
602
  return DPI_FAILURE;
602
603
  }
603
604
  var->error = NULL;
@@ -606,6 +607,7 @@ static int dpiStmt__execute(dpiStmt *stmt, uint32_t numIters,
606
607
 
607
608
  // create query variables (if applicable)
608
609
  if (stmt->statementType == DPI_STMT_TYPE_SELECT &&
610
+ !(mode & DPI_MODE_EXEC_PARSE_ONLY) &&
609
611
  dpiStmt__createQueryVars(stmt, error) < 0)
610
612
  return DPI_FAILURE;
611
613
 
@@ -620,7 +622,7 @@ static int dpiStmt__execute(dpiStmt *stmt, uint32_t numIters,
620
622
  static int dpiStmt__fetch(dpiStmt *stmt, dpiError *error)
621
623
  {
622
624
  // perform any pre-fetch activities required
623
- if (dpiStmt__preFetch(stmt, error) < 0)
625
+ if (dpiStmt__beforeFetch(stmt, error) < 0)
624
626
  return DPI_FAILURE;
625
627
 
626
628
  // perform fetch
@@ -840,7 +842,7 @@ static int dpiStmt__postFetch(dpiStmt *stmt, dpiError *error)
840
842
  for (i = 0; i < stmt->numQueryVars; i++) {
841
843
  var = stmt->queryVars[i];
842
844
  for (j = 0; j < stmt->bufferRowCount; j++) {
843
- if (dpiVar__getValue(var, j, &var->externalData[j], error) < 0)
845
+ if (dpiVar__getValue(var, &var->buffer, j, 1, error) < 0)
844
846
  return DPI_FAILURE;
845
847
  if (var->type->requiresPreFetch)
846
848
  var->requiresPreFetch = 1;
@@ -853,13 +855,13 @@ static int dpiStmt__postFetch(dpiStmt *stmt, dpiError *error)
853
855
 
854
856
 
855
857
  //-----------------------------------------------------------------------------
856
- // dpiStmt__preFetch() [INTERNAL]
858
+ // dpiStmt__beforeFetch() [INTERNAL]
857
859
  // Performs work that needs to be done prior to fetch for each variable. In
858
860
  // addition, variables are created if they do not already exist. A check is
859
861
  // also made to ensure that the variable has enough space to support a fetch
860
862
  // of the requested size.
861
863
  //-----------------------------------------------------------------------------
862
- static int dpiStmt__preFetch(dpiStmt *stmt, dpiError *error)
864
+ static int dpiStmt__beforeFetch(dpiStmt *stmt, dpiError *error)
863
865
  {
864
866
  dpiQueryInfo *queryInfo;
865
867
  dpiData *data;
@@ -883,10 +885,11 @@ static int dpiStmt__preFetch(dpiStmt *stmt, dpiError *error)
883
885
  dpiGen__setRefCount(var, error, -1);
884
886
  }
885
887
  var->error = error;
886
- if (stmt->fetchArraySize > var->maxArraySize)
888
+ if (stmt->fetchArraySize > var->buffer.maxArraySize)
887
889
  return dpiError__set(error, "check array size",
888
- DPI_ERR_ARRAY_SIZE_TOO_SMALL, var->maxArraySize);
889
- if (var->requiresPreFetch && dpiVar__extendedPreFetch(var, error) < 0)
890
+ DPI_ERR_ARRAY_SIZE_TOO_SMALL, var->buffer.maxArraySize);
891
+ if (var->requiresPreFetch && dpiVar__extendedPreFetch(var,
892
+ &var->buffer, error) < 0)
890
893
  return DPI_FAILURE;
891
894
  }
892
895
 
@@ -949,7 +952,7 @@ static int dpiStmt__reExecute(dpiStmt *stmt, uint32_t numIters,
949
952
  // so that it does not return with the invalid metadata; again, if this
950
953
  // cannot be done, let the original error propagate
951
954
  origHandle = stmt->handle;
952
- status = dpiStmt__prepare(stmt, sql, sqlLength, NULL, 0, &localError);
955
+ status = dpiOci__stmtPrepare2(stmt, sql, sqlLength, NULL, 0, &localError);
953
956
  newHandle = stmt->handle;
954
957
  stmt->handle = origHandle;
955
958
  stmt->deleteFromCache = 1;
@@ -1197,13 +1200,25 @@ int dpiStmt_executeMany(dpiStmt *stmt, dpiExecMode mode, uint32_t numIters)
1197
1200
  return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
1198
1201
  }
1199
1202
 
1203
+ // batch errors and array DML row counts are only supported with DML
1204
+ // statements (insert, update, delete and merge)
1205
+ if ((mode & DPI_MODE_EXEC_BATCH_ERRORS ||
1206
+ mode & DPI_MODE_EXEC_ARRAY_DML_ROWCOUNTS) &&
1207
+ stmt->statementType != DPI_STMT_TYPE_INSERT &&
1208
+ stmt->statementType != DPI_STMT_TYPE_UPDATE &&
1209
+ stmt->statementType != DPI_STMT_TYPE_DELETE &&
1210
+ stmt->statementType != DPI_STMT_TYPE_MERGE) {
1211
+ dpiError__set(&error, "check mode", DPI_ERR_EXEC_MODE_ONLY_FOR_DML);
1212
+ return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
1213
+ }
1214
+
1200
1215
  // ensure that all bind variables have a big enough maxArraySize to
1201
1216
  // support this operation
1202
1217
  for (i = 0; i < stmt->numBindVars; i++) {
1203
- if (stmt->bindVars[i].var->maxArraySize < numIters) {
1218
+ if (stmt->bindVars[i].var->buffer.maxArraySize < numIters) {
1204
1219
  dpiError__set(&error, "check array size",
1205
1220
  DPI_ERR_ARRAY_SIZE_TOO_SMALL,
1206
- stmt->bindVars[i].var->maxArraySize);
1221
+ stmt->bindVars[i].var->buffer.maxArraySize);
1207
1222
  return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
1208
1223
  }
1209
1224
  }
@@ -1564,15 +1579,16 @@ int dpiStmt_getQueryValue(dpiStmt *stmt, uint32_t pos,
1564
1579
  return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
1565
1580
  }
1566
1581
  *nativeTypeNum = var->nativeTypeNum;
1567
- *data = &var->externalData[stmt->bufferRowIndex - 1];
1582
+ *data = &var->buffer.externalData[stmt->bufferRowIndex - 1];
1568
1583
  return dpiGen__endPublicFn(stmt, DPI_SUCCESS, &error);
1569
1584
  }
1570
1585
 
1571
1586
 
1572
1587
  //-----------------------------------------------------------------------------
1573
1588
  // dpiStmt_getRowCount() [PUBLIC]
1574
- // Return the number of rows affected by the last SQL executed (for insert,
1575
- // update or delete) or the number of rows fetched (for queries).
1589
+ // Return the number of rows affected by the last DML executed (for insert,
1590
+ // update, delete and merge) or the number of rows fetched (for queries). In
1591
+ // all other cases, 0 is returned.
1576
1592
  //-----------------------------------------------------------------------------
1577
1593
  int dpiStmt_getRowCount(dpiStmt *stmt, uint64_t *count)
1578
1594
  {
@@ -1584,7 +1600,12 @@ int dpiStmt_getRowCount(dpiStmt *stmt, uint64_t *count)
1584
1600
  DPI_CHECK_PTR_NOT_NULL(stmt, count)
1585
1601
  if (stmt->statementType == DPI_STMT_TYPE_SELECT)
1586
1602
  *count = stmt->rowCount;
1587
- else if (stmt->env->versionInfo->versionNum < 12) {
1603
+ else if (stmt->statementType != DPI_STMT_TYPE_INSERT &&
1604
+ stmt->statementType != DPI_STMT_TYPE_UPDATE &&
1605
+ stmt->statementType != DPI_STMT_TYPE_DELETE &&
1606
+ stmt->statementType != DPI_STMT_TYPE_MERGE) {
1607
+ *count = 0;
1608
+ } else if (stmt->env->versionInfo->versionNum < 12) {
1588
1609
  if (dpiOci__attrGet(stmt->handle, DPI_OCI_HTYPE_STMT, &rowCount32, 0,
1589
1610
  DPI_OCI_ATTR_ROW_COUNT, "get row count", &error) < 0)
1590
1611
  return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
@@ -1703,7 +1724,7 @@ int dpiStmt_scroll(dpiStmt *stmt, dpiFetchMode mode, int32_t offset,
1703
1724
  }
1704
1725
 
1705
1726
  // perform any pre-fetch activities required
1706
- if (dpiStmt__preFetch(stmt, &error) < 0)
1727
+ if (dpiStmt__beforeFetch(stmt, &error) < 0)
1707
1728
  return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
1708
1729
 
1709
1730
  // perform fetch; when fetching the last row, only fetch a single row
@@ -1767,7 +1788,7 @@ int dpiStmt_setFetchArraySize(dpiStmt *stmt, uint32_t arraySize)
1767
1788
  arraySize = DPI_DEFAULT_FETCH_ARRAY_SIZE;
1768
1789
  for (i = 0; i < stmt->numQueryVars; i++) {
1769
1790
  var = stmt->queryVars[i];
1770
- if (var && var->maxArraySize < arraySize) {
1791
+ if (var && var->buffer.maxArraySize < arraySize) {
1771
1792
  dpiError__set(&error, "check array size",
1772
1793
  DPI_ERR_ARRAY_SIZE_TOO_BIG, arraySize);
1773
1794
  return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
@@ -50,6 +50,7 @@ static void dpiSubscr__callback(dpiSubscr *subscr, UNUSED void *handle,
50
50
  dpiError__getInfo(&error, &errorInfo);
51
51
  message.errorInfo = &errorInfo;
52
52
  }
53
+ message.registered = subscr->registered;
53
54
 
54
55
  // invoke user callback
55
56
  (*subscr->callback)(subscr->callbackContext, &message);
@@ -60,6 +61,23 @@ static void dpiSubscr__callback(dpiSubscr *subscr, UNUSED void *handle,
60
61
  }
61
62
 
62
63
 
64
+ //-----------------------------------------------------------------------------
65
+ // dpiSubscr__checkOpen() [INTERNAL]
66
+ // Determine if the subscription is open and available for use.
67
+ //-----------------------------------------------------------------------------
68
+ static int dpiSubscr__checkOpen(dpiSubscr *subscr, const char *fnName,
69
+ dpiError *error)
70
+ {
71
+ if (dpiGen__startPublicFn(subscr, DPI_HTYPE_SUBSCR, fnName, 1, error) < 0)
72
+ return DPI_FAILURE;
73
+ if (!subscr->handle)
74
+ return dpiError__set(error, "check closed", DPI_ERR_SUBSCR_CLOSED);
75
+ if (!subscr->conn->handle || subscr->conn->closing)
76
+ return dpiError__set(error, "check connection", DPI_ERR_NOT_CONNECTED);
77
+ return DPI_SUCCESS;
78
+ }
79
+
80
+
63
81
  //-----------------------------------------------------------------------------
64
82
  // dpiSubscr__create() [INTERNAL]
65
83
  // Create a new subscription structure and return it. In case of error NULL
@@ -69,6 +87,7 @@ int dpiSubscr__create(dpiSubscr *subscr, dpiConn *conn,
69
87
  dpiSubscrCreateParams *params, uint64_t *subscrId, dpiError *error)
70
88
  {
71
89
  uint32_t qosFlags;
90
+ int32_t int32Val;
72
91
  int rowids;
73
92
 
74
93
  // retain a reference to the connection
@@ -76,6 +95,7 @@ int dpiSubscr__create(dpiSubscr *subscr, dpiConn *conn,
76
95
  subscr->conn = conn;
77
96
  subscr->callback = params->callback;
78
97
  subscr->callbackContext = params->callbackContext;
98
+ subscr->subscrNamespace = params->subscrNamespace;
79
99
  subscr->qos = params->qos;
80
100
 
81
101
  // create the subscription handle
@@ -101,6 +121,13 @@ int dpiSubscr__create(dpiSubscr *subscr, dpiConn *conn,
101
121
  DPI_OCI_ATTR_SUBSCR_TIMEOUT, "set timeout", error) < 0)
102
122
  return DPI_FAILURE;
103
123
 
124
+ // set the IP address used on the client to listen for events
125
+ if (params->ipAddress && params->ipAddressLength > 0 &&
126
+ dpiOci__attrSet(subscr->env->handle, DPI_OCI_HTYPE_ENV,
127
+ (void*) params->ipAddress, params->ipAddressLength,
128
+ DPI_OCI_ATTR_SUBSCR_IPADDR, "set IP address", error) < 0)
129
+ return DPI_FAILURE;
130
+
104
131
  // set the port number used on the client to listen for events
105
132
  if (params->portNumber > 0 && dpiOci__attrSet(subscr->env->handle,
106
133
  DPI_OCI_HTYPE_ENV, (void*) &params->portNumber, 0,
@@ -163,9 +190,44 @@ int dpiSubscr__create(dpiSubscr *subscr, dpiConn *conn,
163
190
  DPI_OCI_ATTR_CHNF_OPERATIONS, "set operations", error) < 0)
164
191
  return DPI_FAILURE;
165
192
 
193
+ // set grouping information, if applicable
194
+ if (params->groupingClass) {
195
+
196
+ // set grouping class
197
+ if (dpiOci__attrSet(subscr->handle, DPI_OCI_HTYPE_SUBSCRIPTION,
198
+ (void*) &params->groupingClass, 0,
199
+ DPI_OCI_ATTR_SUBSCR_NTFN_GROUPING_CLASS, "set grouping class",
200
+ error) < 0)
201
+ return DPI_FAILURE;
202
+
203
+ // set grouping value
204
+ if (dpiOci__attrSet(subscr->handle, DPI_OCI_HTYPE_SUBSCRIPTION,
205
+ (void*) &params->groupingValue, 0,
206
+ DPI_OCI_ATTR_SUBSCR_NTFN_GROUPING_VALUE, "set grouping value",
207
+ error) < 0)
208
+ return DPI_FAILURE;
209
+
210
+ // set grouping type
211
+ if (dpiOci__attrSet(subscr->handle, DPI_OCI_HTYPE_SUBSCRIPTION,
212
+ (void*) &params->groupingType, 0,
213
+ DPI_OCI_ATTR_SUBSCR_NTFN_GROUPING_TYPE, "set grouping type",
214
+ error) < 0)
215
+ return DPI_FAILURE;
216
+
217
+ // set grouping repeat count
218
+ int32Val = DPI_SUBSCR_GROUPING_FOREVER;
219
+ if (dpiOci__attrSet(subscr->handle, DPI_OCI_HTYPE_SUBSCRIPTION,
220
+ (void*) &int32Val, 0,
221
+ DPI_OCI_ATTR_SUBSCR_NTFN_GROUPING_REPEAT_COUNT,
222
+ "set grouping repeat count", error) < 0)
223
+ return DPI_FAILURE;
224
+
225
+ }
226
+
166
227
  // register the subscription
167
228
  if (dpiOci__subscriptionRegister(conn, &subscr->handle, error) < 0)
168
229
  return DPI_FAILURE;
230
+ subscr->registered = 1;
169
231
 
170
232
  // get the registration id, if applicable
171
233
  if (subscrId && dpiOci__attrGet(subscr->handle, DPI_OCI_HTYPE_SUBSCRIPTION,
@@ -184,7 +246,9 @@ int dpiSubscr__create(dpiSubscr *subscr, dpiConn *conn,
184
246
  void dpiSubscr__free(dpiSubscr *subscr, dpiError *error)
185
247
  {
186
248
  if (subscr->handle) {
187
- dpiOci__subscriptionUnRegister(subscr, error);
249
+ if (subscr->registered)
250
+ dpiOci__subscriptionUnRegister(subscr->conn, subscr, error);
251
+ dpiOci__handleFree(subscr->handle, DPI_OCI_HTYPE_SUBSCRIPTION);
188
252
  subscr->handle = NULL;
189
253
  }
190
254
  if (subscr->conn) {
@@ -230,6 +294,41 @@ static void dpiSubscr__freeMessage(dpiSubscrMessage *message)
230
294
  }
231
295
 
232
296
 
297
+ //-----------------------------------------------------------------------------
298
+ // dpiSubscr__populateAQMessage() [INTERNAL]
299
+ // Populate message with details.
300
+ //-----------------------------------------------------------------------------
301
+ static int dpiSubscr__populateAQMessage(dpiSubscr *subscr,
302
+ dpiSubscrMessage *message, void *descriptor, dpiError *error)
303
+ {
304
+ uint32_t flags = 0;
305
+
306
+ // determine if message is a deregistration message
307
+ if (dpiOci__attrGet(descriptor, DPI_OCI_DTYPE_AQNFY_DESCRIPTOR, &flags,
308
+ NULL, DPI_OCI_ATTR_NFY_FLAGS, "get flags", error) < 0)
309
+ return DPI_FAILURE;
310
+ message->eventType = (flags == 1) ? DPI_EVENT_DEREG : DPI_EVENT_AQ;
311
+ if (message->eventType == DPI_EVENT_DEREG) {
312
+ subscr->registered = 0;
313
+ return DPI_SUCCESS;
314
+ }
315
+
316
+ // determine the name of the queue which spawned the event
317
+ if (dpiOci__attrGet(descriptor, DPI_OCI_DTYPE_AQNFY_DESCRIPTOR,
318
+ (void*) &message->queueName, &message->queueNameLength,
319
+ DPI_OCI_ATTR_QUEUE_NAME, "get queue name", error) < 0)
320
+ return DPI_FAILURE;
321
+
322
+ // determine the consumer name for the queue that spawned the event
323
+ if (dpiOci__attrGet(descriptor, DPI_OCI_DTYPE_AQNFY_DESCRIPTOR,
324
+ (void*) &message->consumerName, &message->consumerNameLength,
325
+ DPI_OCI_ATTR_CONSUMER_NAME, "get consumer name", error) < 0)
326
+ return DPI_FAILURE;
327
+
328
+ return DPI_SUCCESS;
329
+ }
330
+
331
+
233
332
  //-----------------------------------------------------------------------------
234
333
  // dpiSubscr__populateObjectChangeMessage() [INTERNAL]
235
334
  // Populate object change message with details.
@@ -284,6 +383,17 @@ static int dpiSubscr__populateMessage(dpiSubscr *subscr,
284
383
  {
285
384
  void *rawValue;
286
385
 
386
+ // if quality of service flag indicates that deregistration should take
387
+ // place when the first notification is received, mark the subscription
388
+ // as no longer registered
389
+ if (subscr->qos & DPI_SUBSCR_QOS_DEREG_NFY)
390
+ subscr->registered = 0;
391
+
392
+ // handle AQ messages, if applicable
393
+ if (subscr->subscrNamespace == DPI_SUBSCR_NAMESPACE_AQ)
394
+ return dpiSubscr__populateAQMessage(subscr, message, descriptor,
395
+ error);
396
+
287
397
  // determine the type of event that was spawned
288
398
  if (dpiOci__attrGet(descriptor, DPI_OCI_DTYPE_CHDES, &message->eventType,
289
399
  NULL, DPI_OCI_ATTR_CHDES_NFYTYPE, "get event type", error) < 0)
@@ -311,7 +421,7 @@ static int dpiSubscr__populateMessage(dpiSubscr *subscr,
311
421
  return dpiSubscr__populateQueryChangeMessage(subscr, message,
312
422
  descriptor, error);
313
423
  case DPI_EVENT_DEREG:
314
- subscr->handle = NULL;
424
+ subscr->registered = 0;
315
425
  break;
316
426
  default:
317
427
  return dpiError__set(error, "event type", DPI_ERR_NOT_SUPPORTED);
@@ -543,13 +653,12 @@ int dpiSubscr_close(dpiSubscr *subscr)
543
653
  {
544
654
  dpiError error;
545
655
 
546
- if (dpiGen__startPublicFn(subscr, DPI_HTYPE_SUBSCR, __func__, 1,
547
- &error) < 0)
656
+ if (dpiSubscr__checkOpen(subscr, __func__, &error) < 0)
548
657
  return dpiGen__endPublicFn(subscr, DPI_FAILURE, &error);
549
- if (subscr->handle) {
550
- if (dpiOci__subscriptionUnRegister(subscr, &error) < 0)
658
+ if (subscr->registered) {
659
+ if (dpiOci__subscriptionUnRegister(subscr->conn, subscr, &error) < 0)
551
660
  return dpiGen__endPublicFn(subscr, DPI_FAILURE, &error);
552
- subscr->handle = NULL;
661
+ subscr->registered = 0;
553
662
  }
554
663
 
555
664
  return dpiGen__endPublicFn(subscr, DPI_SUCCESS, &error);
@@ -566,8 +675,7 @@ int dpiSubscr_prepareStmt(dpiSubscr *subscr, const char *sql,
566
675
  dpiStmt *tempStmt;
567
676
  dpiError error;
568
677
 
569
- if (dpiGen__startPublicFn(subscr, DPI_HTYPE_SUBSCR, __func__, 1,
570
- &error) < 0)
678
+ if (dpiSubscr__checkOpen(subscr, __func__, &error) < 0)
571
679
  return dpiGen__endPublicFn(subscr, DPI_FAILURE, &error);
572
680
  DPI_CHECK_PTR_NOT_NULL(subscr, sql)
573
681
  DPI_CHECK_PTR_NOT_NULL(subscr, stmt)