Skip to content

Commit 250ef9c

Browse files
committed
Fixed outBinds array counting to not give empty array entries for IN binds
1 parent 1d0548e commit 250ef9c

File tree

3 files changed

+109
-51
lines changed

3 files changed

+109
-51
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
- Changed the `isExternalAuth` attribute name to `externalAuth`.
88

9+
- Fixed outBinds array counting to not give empty array entries for IN binds.
10+
911
- Added support for DML RETURNING bind variables.
1012

1113
- Rectified the error message for invalid type properties.

src/njs/src/njsConnection.cpp

Lines changed: 96 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -500,13 +500,6 @@ void Connection::GetBindUnit (Handle<Value> val, Bind* bind,
500500
goto exitGetBindUnit;
501501
}
502502

503-
// For in binds allocate buffer for bind values (scalar).
504-
if ( dir != BIND_OUT )
505-
{
506-
Connection::cbDynBufferAllocate ( bind, 1 ) ;
507-
}
508-
509-
510503
Local<Value> element = bind_unit->Get(String::New("val"));
511504
switch(dir)
512505
{
@@ -535,8 +528,6 @@ void Connection::GetBindUnit (Handle<Value> val, Bind* bind,
535528
else
536529
{
537530
bind->isOut = false;
538-
// This is IN Bind, allocate.
539-
Connection::cbDynBufferAllocate ( bind, 1 ) ;
540531
Connection::GetInBindParams(val, bind, executeBaton, BIND_IN);
541532
if(!executeBaton->error.empty()) goto exitGetBindUnit;
542533
}
@@ -585,11 +576,20 @@ void Connection::GetOutBindParams (unsigned short dataType, Bind* bind,
585576
586577
PARAMETERS:
587578
Handle value, bind struct, eBaton struct
579+
580+
NOTE:
581+
For IN Bind only len field field is used, and for only a scalar value now,
582+
allocate for one unit.
588583
*/
589584
void Connection::GetInBindParams (Handle<Value> v8val, Bind* bind,
590585
eBaton* executeBaton, BindType type)
591586
{
587+
/* Allocate for scalar indicator & length */
588+
bind->ind = (short *)malloc ( sizeof ( short ) );
589+
bind->len = (DPI_BUFLEN_TYPE *)malloc ( sizeof ( DPI_BUFLEN_TYPE ) );
590+
592591
*(bind->ind) = 0;
592+
593593
if(v8val->IsUndefined() || v8val->IsNull())
594594
{
595595
bind->value = NULL;
@@ -739,7 +739,7 @@ void Connection::Async_Execute (uv_work_t *req)
739739
row ++ )
740740
{
741741
if (executeBaton->binds[b]->maxSize <
742-
executeBaton->binds[b]->len[row])
742+
(DPI_SZ_TYPE) executeBaton->binds[b]->len2[row])
743743
{
744744
/* Report insufficient buffer for OUT binds */
745745
executeBaton->error =
@@ -778,7 +778,19 @@ void Connection::Async_Execute (uv_work_t *req)
778778
}
779779
catch (dpi::Exception& e)
780780
{
781-
executeBaton->error = std::string(e.what());
781+
// In Case of DML Returning, if the buffer is small, and if the callback
782+
// is called multiple times, an ORA error 24343 was reported. Converting
783+
// that error to errInsufficientBufferForBinds.
784+
if ( !executeBaton->stmtIsReturning &&
785+
(e.errnum() != 24343) )
786+
{
787+
executeBaton->error = std::string(e.what ());
788+
}
789+
else
790+
{
791+
executeBaton->error = NJSMessages::getErrorMsg (
792+
errInsufficientBufferForBinds ) ;
793+
}
782794
}
783795
exitAsyncExecute:
784796
;
@@ -815,23 +827,24 @@ void Connection::PrepareAndBind (eBaton* executeBaton)
815827
errInvalidBindDataType, 2);
816828
return;
817829
}
830+
831+
// Allocate for OUT Binds
832+
// For DML Returning, allocation happens through callback.
833+
if ( executeBaton->binds[index]->isOut &&
834+
!executeBaton->stmtIsReturning &&
835+
!executeBaton->binds[index]->value )
836+
{
837+
Connection::cbDynBufferAllocate ( executeBaton->binds[index],
838+
false, 1 );
839+
}
840+
818841

819842
// Convert v8::Date to Oracle DB Type
820843
if ( executeBaton->binds[index]->type == DpiTimestampLTZ )
821844
{
822845
Connection::UpdateDateValue ( executeBaton ) ;
823846
}
824847

825-
// For OUT binds (with NO RETURNING INTO clause allocate for
826-
// scalar value. For RETURNING INTO clause, callback will allocate
827-
// NOTE: For IN Binds, the allocation & initialization happens
828-
// in GetBindUnit itself.
829-
if ( !executeBaton->stmtIsReturning &&
830-
executeBaton->binds[index]->isOut )
831-
{
832-
Connection::cbDynBufferAllocate ( executeBaton->binds[index], 1 );
833-
}
834-
835848
// Bind by name
836849
executeBaton->dpistmt->bind(
837850
(const unsigned char*)executeBaton->binds[index]->key.c_str(),
@@ -867,6 +880,16 @@ void Connection::PrepareAndBind (eBaton* executeBaton)
867880
return;
868881
}
869882

883+
// Allocate for OUT Binds
884+
// For DML Returning, allocation happens through callback
885+
if ( executeBaton->binds[index]->isOut &&
886+
!executeBaton->stmtIsReturning &&
887+
!executeBaton->binds[index]->value )
888+
{
889+
Connection::cbDynBufferAllocate ( executeBaton->binds[index],
890+
false, 1 );
891+
}
892+
870893
if ( executeBaton->binds[index]->type == DpiTimestampLTZ )
871894
{
872895
Connection::UpdateDateValue ( executeBaton ) ;
@@ -1243,7 +1266,7 @@ Handle<Value> Connection::GetArrayValue ( Bind *binds, unsigned long count )
12431266
( binds->ind[index] == -1 ) ? Null () :
12441267
String::New ((char *)binds->value +
12451268
(index * binds->maxSize ),
1246-
binds->len[index]));
1269+
binds->len2[index]));
12471270
break;
12481271
case dpi::DpiInteger:
12491272
arrVal->Set ( index,
@@ -1296,15 +1319,10 @@ Handle<Value> Connection::GetOutBinds (eBaton* executeBaton)
12961319
if( executeBaton->binds[0]->key.empty() )
12971320
{
12981321
// Binds as JS array
1299-
unsigned int outCount = 0;
1300-
for(unsigned int index = 0; index < executeBaton->binds.size(); index++)
1301-
{
1302-
if(executeBaton->binds[index]->isOut)
1303-
outCount++;
1304-
}
13051322
return scope.Close( GetOutBindArray( executeBaton->binds,
1323+
executeBaton->numOutBinds,
13061324
executeBaton->stmtIsReturning,
1307-
outCount ));
1325+
executeBaton->rowsAffected ));
13081326
}
13091327
else
13101328
{
@@ -1358,8 +1376,8 @@ Handle<Value> Connection::GetOutBindArray ( std::vector<Bind*> &binds,
13581376
val = Connection::GetArrayValue ( binds[index], rowcount );
13591377
}
13601378
arrayBinds->Set( it, val );
1379+
it ++;
13611380
}
1362-
it++;
13631381
}
13641382
return scope.Close(arrayBinds);
13651383
}
@@ -1856,7 +1874,8 @@ void Connection::UpdateDateValue ( eBaton * ebaton )
18561874
callback/Utility function to allocate for BIND values (IN & OUT).
18571875
This has been consolidated to a callback/utility funciton so that
18581876
allocation happens only once.
1859-
For IN binds, the allocation and initialization happens in GetBindUnit ()
1877+
For IN binds, the allocation and initialization happens in
1878+
GetInBindParams()
18601879
For OUT binds the allocation happens in PrepareAndBind ().
18611880
For OUT binds using RETURNING INTO clause, this function is used as
18621881
callback.
@@ -1868,30 +1887,59 @@ void Connection::UpdateDateValue ( eBaton * ebaton )
18681887
RETURNS
18691888
-None-
18701889
*/
1871-
void Connection::cbDynBufferAllocate ( void *ctx, DPI_SZ_TYPE nRows )
1890+
void Connection::cbDynBufferAllocate ( void *ctx, bool dmlReturning,
1891+
unsigned int nRows )
18721892
{
18731893
Bind *bind = (Bind *)ctx;
18741894

18751895
bind->ind = (short *)malloc ( nRows * sizeof ( short ) ) ;
1876-
bind->len = (DPI_BUFLEN_TYPE *)malloc ( nRows * sizeof ( DPI_BUFLEN_TYPE ) );
1896+
if ( dmlReturning )
1897+
{
1898+
bind->len2 = ( unsigned int *)malloc ( nRows * sizeof ( unsigned int ) );
1899+
}
1900+
else
1901+
{
1902+
bind->len = (DPI_BUFLEN_TYPE *)malloc ( nRows *
1903+
sizeof ( DPI_BUFLEN_TYPE ) );
1904+
}
18771905

18781906
switch ( bind->type )
18791907
{
18801908
case dpi::DpiVarChar:
1881-
/* one extra char for EOS; 1 more to determine insufficient buffer later */
1882-
bind->value = (char *)malloc ( ( bind->maxSize + 2) * nRows ) ;
1909+
/* one extra char for EOS */
1910+
bind->value = (char *)malloc ( ( bind->maxSize + 1) * nRows ) ;
1911+
if ( dmlReturning )
1912+
{
1913+
*(bind->len2) = bind->maxSize ;
1914+
}
1915+
else
1916+
{
1917+
*(bind->len) = bind->maxSize;
1918+
}
18831919
break;
18841920

18851921
case dpi::DpiInteger:
18861922
bind->value = ( int *) malloc ( sizeof (int) * nRows ) ;
1923+
if ( !dmlReturning )
1924+
{
1925+
*(bind->len) = sizeof ( int ) ;
1926+
}
18871927
break;
18881928

18891929
case dpi::DpiUnsignedInteger:
18901930
bind->value = ( unsigned int *)malloc ( sizeof ( unsigned int ) * nRows );
1931+
if ( !dmlReturning )
1932+
{
1933+
*(bind->len) = sizeof ( unsigned int ) ;
1934+
}
18911935
break;
18921936

18931937
case dpi::DpiDouble:
18941938
bind->value = ( double *)malloc ( sizeof ( double ) * nRows );
1939+
if ( !dmlReturning )
1940+
{
1941+
*(bind->len) = sizeof ( double ) ;
1942+
}
18951943
break;
18961944

18971945
case dpi::DpiTimestampLTZ:
@@ -1916,21 +1964,22 @@ void Connection::cbDynBufferAllocate ( void *ctx, DPI_SZ_TYPE nRows )
19161964
nRows (IN) # of rows (after execution, so knows rows-affected)
19171965
index (IN) row index
19181966
bufpp (INOUT) buffer for the cell
1919-
alenp (INOUT) buffer for actual length
1920-
indp (INOUT) buffer for the indicator
1967+
alenpp (INOUT) buffer for actual length
1968+
indpp (INOUT) buffer for the indicator
19211969
rcode (INOUT) return code - not used
19221970
piecep (INOUT) for piece wise operations.
19231971
19241972
RETURN
19251973
0. (Any non zero value to indicate errors).
19261974
19271975
NOTE:
1928-
OCI does not support DATE/TIMESTAMP for dynamic Binding.
1976+
1. DATE/TIMESTAMP not supported
1977+
2. using bind->len2 for DML returning (not bind->len)
19291978
*/
19301979

19311980
int Connection::cbDynBufferGet ( void *ctx, DPI_SZ_TYPE nRows,
19321981
unsigned long iter, unsigned long index,
1933-
dvoid **bufpp, void **alenp, void **indp,
1982+
dvoid **bufpp, void **alenpp, void **indpp,
19341983
unsigned short **rcode, unsigned char *piecep)
19351984
{
19361985
Bind *bind = (Bind *)ctx;
@@ -1948,15 +1997,16 @@ int Connection::cbDynBufferGet ( void *ctx, DPI_SZ_TYPE nRows,
19481997
// First time callback, allocate the buffer(s).
19491998
if ( index == 0 )
19501999
{
1951-
Connection::cbDynBufferAllocate (ctx, nRows );
2000+
Connection::cbDynBufferAllocate (ctx, true, nRows );
19522001
}
19532002

2003+
bind->ind[index] = -1;
19542004

19552005
// Find block of memory for this index
19562006
switch ( bind->type )
19572007
{
19582008
case dpi::DpiVarChar:
1959-
bind->len[index] = ( bind->maxSize + 1 );
2009+
bind->len2[index] = bind->maxSize;
19602010
/* 1 extra char for EOS, 1 extra to determine insufficient buf later */
19612011
*bufpp = (void *)&(((char *)bind->value)[ (bind->maxSize) * index]);
19622012
/* Buffer provided by the application could be small, in this case to
@@ -1966,16 +2016,16 @@ int Connection::cbDynBufferGet ( void *ctx, DPI_SZ_TYPE nRows,
19662016
*piecep = OCI_FIRST_PIECE;
19672017
break;
19682018
case dpi::DpiInteger:
1969-
bind->len[index] = sizeof ( int ) ;
2019+
bind->len2[index] = sizeof ( int ) ;
19702020
*bufpp = ( void *)&(((int *)bind->value)[index]);
19712021
break;
19722022
case dpi::DpiUnsignedInteger:
1973-
bind->len[index] = sizeof ( unsigned int ) ;
2023+
bind->len2[index] = sizeof ( unsigned int ) ;
19742024
*bufpp = ( void *)&(((unsigned int *)bind->value)[index]);
19752025
break;
19762026

19772027
case dpi::DpiDouble:
1978-
bind->len[index] = sizeof ( double ) ;
2028+
bind->len2[index] = sizeof ( double ) ;
19792029
*bufpp = (void *)&(((double *)bind->value)[index]);
19802030
break;
19812031

@@ -1984,8 +2034,8 @@ int Connection::cbDynBufferGet ( void *ctx, DPI_SZ_TYPE nRows,
19842034
break;
19852035
}
19862036

1987-
*alenp = &(bind->len[index]);
1988-
*indp = &(bind->ind[index]);
2037+
*alenpp = &(bind->len2[index]);
2038+
*indpp = &(bind->ind[index]);
19892039
}
19902040
else
19912041
{

src/njs/src/njsConnection.h

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,15 +46,16 @@ typedef struct Bind
4646
std::string key;
4747
void* value;
4848
void* extvalue;
49-
DPI_BUFLEN_TYPE *len;
49+
DPI_BUFLEN_TYPE *len; // actual length IN/OUT for bind APIs
50+
unsigned int *len2; // used for DML returning
5051
DPI_SZ_TYPE maxSize;
5152
unsigned short type;
5253
short *ind;
5354
bool isOut;
5455
dpi::DateTimeArray* dttmarr;
5556

56-
Bind () : key(""), value(NULL), extvalue (NULL), len(NULL), maxSize(0),
57-
type(0), ind(NULL), isOut(false), dttmarr ( NULL )
57+
Bind () : key(""), value(NULL), extvalue (NULL), len(NULL), len2(NULL),
58+
maxSize(0), type(0), ind(NULL), isOut(false), dttmarr ( NULL )
5859
{}
5960
}Bind;
6061

@@ -135,6 +136,10 @@ typedef struct eBaton
135136
{
136137
free ( binds[index]->len );
137138
}
139+
if ( binds[index]->len2 )
140+
{
141+
free ( binds[index]->len2 ) ;
142+
}
138143
}
139144
delete binds[index];
140145
}
@@ -258,14 +263,15 @@ class Connection: public ObjectWrap
258263
static void v8Date2OraDate ( v8::Handle<v8::Value>, Bind *bind);
259264

260265
// Callback/Utility function used to allocate buffer(s) for Bind Structs
261-
static void cbDynBufferAllocate ( void *ctx, DPI_SZ_TYPE nRows );
266+
static void cbDynBufferAllocate ( void *ctx, bool dmlReturning,
267+
unsigned int nRows );
262268

263269
// Callback used in DML-Return SQL statements to
264270
// identify block of memeory for each row.
265271
static int cbDynBufferGet ( void *ctx, DPI_SZ_TYPE nRows,
266272

267273
unsigned long iter, unsigned long index,
268-
dvoid **bufpp, void **alenp, void **indp,
274+
dvoid **bufpp, void **alenpp, void **indpp,
269275
unsigned short **rcode, unsigned char *piecep );
270276

271277
dpi::Conn* dpiconn_;

0 commit comments

Comments
 (0)