@@ -1960,6 +1960,26 @@ void Connection::Async_Execute (uv_work_t *req)
1960
1960
executeBaton->dpistmt ->release ();
1961
1961
}
1962
1962
1963
+ // Auto close the IN-LOB used for INOUT bind
1964
+ for ( unsigned int index = 0 ;index < executeBaton->binds .size ();
1965
+ index++ )
1966
+ {
1967
+ Bind *bind = executeBaton->binds [index];
1968
+
1969
+ if ( ( bind->type == DpiClob || bind->type == DpiBlob ) && bind->isInOut )
1970
+ {
1971
+ if ( executeBaton->extBinds [index] &&
1972
+ executeBaton->extBinds [index]->type == NJS_EXTBIND_LOB &&
1973
+ !executeBaton->extBinds [index]->fields .extLob .isStringBuffer2LOB )
1974
+ {
1975
+ ILob *iLob = ( ILob * )
1976
+ ( executeBaton->extBinds [index]->fields .extLob .value );
1977
+ // cleanupNJS() will be called later in Async_AfterExecute()
1978
+ iLob->cleanupDPI ();
1979
+ }
1980
+ }
1981
+ }
1982
+
1963
1983
// In case of error, free the allocated resources
1964
1984
if ( !(executeBaton->error ).empty () )
1965
1985
{
@@ -2103,14 +2123,24 @@ void Connection::LOB2StringOrBuffer ( eBaton* executeBaton, unsigned int index,
2103
2123
lobLocator, byteAmount, charAmount, offset,
2104
2124
bind->value , bufLen );
2105
2125
2106
- // There is more data in the LOB than the maxSize, set the error
2126
+ /*
2127
+ * byteAmount returns the number of bytes read into the buffer irrespective
2128
+ * of charAmount or byteAmount passed to Lob::read()
2129
+ * If there is more data in the LOB than the maxSize, set the error
2130
+ */
2107
2131
if ( byteAmount > ( unsigned long long ) bind->maxSize )
2108
2132
{
2109
2133
executeBaton->error = NJSMessages::getErrorMsg (
2110
2134
errInsufficientBufferForBinds);
2111
2135
goto exitLOB2StringOrBuffer;
2112
2136
}
2113
2137
2138
+ // Treat empty LOB case as NULL to be consistent with varchar/buffer columns
2139
+ if ( !byteAmount )
2140
+ {
2141
+ *bind->ind = -1 ;
2142
+ }
2143
+
2114
2144
*bind->len = ( DPI_BUFLEN_TYPE ) byteAmount;
2115
2145
2116
2146
exitLOB2StringOrBuffer:
@@ -3390,40 +3420,58 @@ void Connection::Descr2protoILob( eBaton *executeBaton, unsigned int numCols,
3390
3420
{
3391
3421
Bind *bind = executeBaton->binds [obndpos];
3392
3422
3393
- if ((!bind->isOut && !bind->isInOut ) ||
3394
- ( bind->ind && *(sb2 *)bind->ind == -1 ))
3395
- continue ; // we only need to process the non-null OUT binds
3396
-
3397
- if (bind->type == DpiClob || bind->type == DpiBlob)
3423
+ if ( ( bind->isOut || bind->isInOut ) &&
3424
+ ( bind->type == DpiClob || bind->type == DpiBlob ) )
3398
3425
{
3399
- Descriptor *lobLocator = NULL ;
3400
-
3401
- if ( executeBaton->stmtIsReturning )
3426
+ // Free the allocated descriptors in case of NULL OUTs or DML returning
3427
+ if ( *bind->ind == -1 )
3402
3428
{
3403
- // TODO: Update this loop when support for array binds is added.
3404
- // For UPDATE, loop through all the rows returned for each bind
3405
- // For INSERT, eventually we will consider the iters.
3406
- // For now only 1 row will be inserted.
3407
- for ( unsigned int rowidx = 0 ; rowidx < bind->rowsReturned ; rowidx++ )
3429
+ if ( executeBaton->stmtIsReturning )
3408
3430
{
3409
- lobLocator =
3410
- ( ( Descriptor ** ) bind->value )[ rowidx ];
3411
- ProtoILob *protoILob = new ProtoILob ( executeBaton, lobLocator,
3412
- bind->type );
3413
-
3414
- ( ( Descriptor ** )( bind->value ) )[rowidx] =
3415
- reinterpret_cast <Descriptor *>( protoILob );
3431
+ for ( unsigned int rowidx = 0 ; rowidx < bind->rowsReturned ;
3432
+ rowidx++ )
3433
+ {
3434
+ Env::freeDescriptor ( ( ( Descriptor ** ) bind->value )[ rowidx ],
3435
+ LobDescriptorType);
3436
+ }
3437
+ }
3438
+ else
3439
+ {
3440
+ Env::freeDescriptor ( *( ( Descriptor ** ) bind->value ),
3441
+ LobDescriptorType);
3416
3442
}
3417
3443
}
3418
- else // case for PLSQL INOUT or OUT
3444
+ else
3419
3445
{
3420
- lobLocator = *( ( Descriptor ** ) bind->value );
3446
+ Descriptor *lobLocator = NULL ;
3447
+
3448
+ if ( executeBaton->stmtIsReturning )
3449
+ {
3450
+ // TODO: Update this loop when support for array binds is added.
3451
+ // For UPDATE, loop through all the rows returned for each bind
3452
+ // For INSERT, eventually we will consider the iters.
3453
+ // For now only 1 row will be inserted.
3454
+ for ( unsigned int rowidx = 0 ; rowidx < bind->rowsReturned ; rowidx++ )
3455
+ {
3456
+ lobLocator =
3457
+ ( ( Descriptor ** ) bind->value )[ rowidx ];
3458
+ ProtoILob *protoILob = new ProtoILob ( executeBaton, lobLocator,
3459
+ bind->type );
3421
3460
3422
- ProtoILob *protoILob = new ProtoILob ( executeBaton,
3423
- lobLocator,
3424
- bind->type );
3425
- *((Descriptor **)bind->value ) =
3426
- reinterpret_cast <Descriptor *>( protoILob );
3461
+ ( ( Descriptor ** )( bind->value ) )[rowidx] =
3462
+ reinterpret_cast <Descriptor *>( protoILob );
3463
+ }
3464
+ }
3465
+ else
3466
+ {
3467
+ lobLocator = *( ( Descriptor ** ) bind->value );
3468
+
3469
+ ProtoILob *protoILob = new ProtoILob ( executeBaton,
3470
+ lobLocator,
3471
+ bind->type );
3472
+ *((Descriptor **)bind->value ) =
3473
+ reinterpret_cast <Descriptor *>( protoILob );
3474
+ }
3427
3475
}
3428
3476
}
3429
3477
}
@@ -3465,6 +3513,13 @@ void Connection::Async_AfterExecute(uv_work_t *req)
3465
3513
( executeBaton->extBinds [index]->fields .extLob .value );
3466
3514
iLob->postBind ();
3467
3515
3516
+ // Auto-close the IN-LOB used for INOUT bind
3517
+ if ( bind->isInOut )
3518
+ {
3519
+ // cleanupDPI() called in Async_Execute since it is a DPI/OCI call
3520
+ iLob->cleanupNJS ();
3521
+ }
3522
+
3468
3523
executeBaton->extBinds [index]->fields .extLob .value = NULL ;
3469
3524
}
3470
3525
}
0 commit comments