Skip to content

Commit cffb782

Browse files
committed
Fix buffer size calculation to allow passing NULL into a PL/SQL IN OUT bind
1 parent bd98c2a commit cffb782

File tree

2 files changed

+118
-48
lines changed

2 files changed

+118
-48
lines changed

src/njs/src/njsConnection.cpp

Lines changed: 115 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -834,14 +834,13 @@ void Connection::GetBindUnit (Local<Value> val, Bind* bind, bool array,
834834
case NJS_BIND_IN :
835835
bind->isOut = false;
836836
bind->isInOut = false;
837-
Connection::GetInBindParams(element, bind, executeBaton, NJS_BIND_IN );
837+
Connection::GetInBindParams(element, bind, executeBaton );
838838
if(!executeBaton->error.empty()) goto exitGetBindUnit;
839839
break;
840840
case NJS_BIND_INOUT :
841841
bind->isOut = true;
842842
bind->isInOut = true;
843-
Connection::GetInBindParams(element, bind, executeBaton,
844-
NJS_BIND_INOUT);
843+
Connection::GetInBindParams(element, bind, executeBaton );
845844
if(!executeBaton->error.empty()) goto exitGetBindUnit;
846845
break;
847846
case NJS_BIND_OUT :
@@ -866,7 +865,7 @@ void Connection::GetBindUnit (Local<Value> val, Bind* bind, bool array,
866865
else
867866
{
868867
bind->isOut = false;
869-
Connection::GetInBindParams(val, bind, executeBaton, NJS_BIND_IN);
868+
Connection::GetInBindParams(val, bind, executeBaton );
870869
if(!executeBaton->error.empty()) goto exitGetBindUnit;
871870
}
872871
exitGetBindUnit:
@@ -957,17 +956,17 @@ void Connection::GetOutBindParams (unsigned short dataType, Bind* bind,
957956
allocate for one unit.
958957
*/
959958
void Connection::GetInBindParams(Local<Value> v8val, Bind* bind,
960-
eBaton* executeBaton, BindType type)
959+
eBaton* executeBaton )
961960
{
962961
Nan::HandleScope scope;
963962

964963
if (v8val->IsArray() )
965964
{
966-
GetInBindParamsArray(Local<Array>::Cast(v8val), bind, executeBaton, type);
965+
GetInBindParamsArray(Local<Array>::Cast(v8val), bind, executeBaton );
967966
}
968967
else
969968
{
970-
GetInBindParamsScalar(v8val, bind, executeBaton, type);
969+
GetInBindParamsScalar(v8val, bind, executeBaton );
971970
}
972971
}
973972

@@ -984,20 +983,54 @@ void Connection::GetInBindParams(Local<Value> v8val, Bind* bind,
984983
allocate for one unit.
985984
*/
986985
void Connection::GetInBindParamsScalar(Local<Value> v8val, Bind* bind,
987-
eBaton* executeBaton, BindType type)
986+
eBaton* executeBaton)
988987
{
989988
Nan::HandleScope scope;
990-
ValueType dataType = NJS_VALUETYPE_INVALID;
989+
ValueType valType = NJS_VALUETYPE_INVALID;
990+
boolean v8valNULL ; /* whether given v8 value is NULL/Undefined */
991991

992992
/* Allocate for scalar indicator & length */
993993
bind->ind = (short *)malloc ( sizeof ( short ) );
994994
bind->len = (DPI_BUFLEN_TYPE *)malloc ( sizeof ( DPI_BUFLEN_TYPE ) );
995995

996996
*(bind->ind) = 0;
997997

998-
dataType = Connection::GetValueType ( v8val );
998+
valType = Connection::GetValueType ( v8val );
999+
v8valNULL = ( valType == NJS_VALUETYPE_NULL ) ? true : false;
9991000

1000-
switch ( dataType )
1001+
/*
1002+
* In case of INOUT Bind, if given value is NULL
1003+
* make use of specified OUT bind type
1004+
*/
1005+
if ( v8valNULL && bind->isInOut )
1006+
{
1007+
switch ( bind->type )
1008+
{
1009+
case NJS_DATATYPE_STR:
1010+
valType = NJS_VALUETYPE_STRING;
1011+
break;
1012+
1013+
case NJS_DATATYPE_NUM:
1014+
valType = NJS_VALUETYPE_NUMBER;
1015+
break;
1016+
1017+
case NJS_DATATYPE_DATE:
1018+
valType = NJS_VALUETYPE_DATE;
1019+
break;
1020+
1021+
case NJS_DATATYPE_BUFFER:
1022+
valType = NJS_VALUETYPE_OBJECT; /* DB RAW Type, v8 Buffer */
1023+
break;
1024+
1025+
// The following types are NOT supported as IN BIND (for INOUT) ignore
1026+
case NJS_DATATYPE_CURSOR:
1027+
case NJS_DATATYPE_CLOB:
1028+
case NJS_DATATYPE_BLOB:
1029+
break;
1030+
}
1031+
}
1032+
1033+
switch ( valType )
10011034
{
10021035
case NJS_VALUETYPE_NULL:
10031036
bind->value = NULL;
@@ -1014,10 +1047,16 @@ void Connection::GetInBindParamsScalar(Local<Value> v8val, Bind* bind,
10141047
goto exitGetInBindParamsScalar;
10151048
}
10161049

1017-
v8::String::Utf8Value str(v8val->ToString());
1050+
/*
1051+
* Use empty string in case of IN value is NULL, but overriden for
1052+
* INOUT binds
1053+
*/
1054+
v8::String::Utf8Value str( v8valNULL ?
1055+
Nan::New<v8::String> ( "", 0 ).ToLocalChecked() :
1056+
v8val->ToString());
10181057

10191058
bind->type = dpi::DpiVarChar;
1020-
if(type == NJS_BIND_INOUT)
1059+
if( bind->isInOut )
10211060
{
10221061
*(bind->len) = str.length();
10231062
}
@@ -1053,7 +1092,7 @@ void Connection::GetInBindParamsScalar(Local<Value> v8val, Bind* bind,
10531092
bind->type = dpi::DpiInteger;
10541093
bind->maxSize = *(bind->len) = sizeof(int);
10551094
bind->value = (int*)malloc(*(bind->len));
1056-
*(int*)(bind->value) = v8val->ToInt32()->Value();
1095+
*(int*)(bind->value) = v8valNULL ? 0 : v8val->ToInt32()->Value();
10571096
break;
10581097

10591098
case NJS_VALUETYPE_UINTEGER:
@@ -1066,7 +1105,8 @@ void Connection::GetInBindParamsScalar(Local<Value> v8val, Bind* bind,
10661105
bind->type = dpi::DpiUnsignedInteger;
10671106
bind->maxSize = *(bind->len) = sizeof(unsigned int);
10681107
bind->value = (unsigned int*)malloc(*(bind->len));
1069-
*(unsigned int*)(bind->value) = v8val->ToUint32()->Value();
1108+
*(unsigned int*)(bind->value) = v8valNULL ? 0 :
1109+
v8val->ToUint32()->Value();
10701110
break;
10711111

10721112
case NJS_VALUETYPE_NUMBER:
@@ -1079,7 +1119,7 @@ void Connection::GetInBindParamsScalar(Local<Value> v8val, Bind* bind,
10791119
bind->type = dpi::DpiDouble;
10801120
bind->maxSize = *(bind->len) = sizeof(double);
10811121
bind->value = (double*)malloc(*(bind->len));
1082-
*(double*)(bind->value) = v8val->NumberValue();
1122+
*(double*)(bind->value) = v8valNULL ? 0 : v8val->NumberValue ();
10831123
break;
10841124

10851125
case NJS_VALUETYPE_DATE:
@@ -1104,11 +1144,23 @@ void Connection::GetInBindParamsScalar(Local<Value> v8val, Bind* bind,
11041144
case NJS_VALUETYPE_OBJECT:
11051145
{
11061146
Local<Object> obj = v8val->ToObject();
1107-
if (Buffer::HasInstance(obj))
1147+
1148+
if ( v8valNULL && bind->isInOut )
1149+
{
1150+
/*
1151+
* In case of RAW/Buffer type and INOUT Bind, if IN value is NULL,
1152+
* allocate based on OUT type, maxSize
1153+
*/
1154+
bind->type = dpi::DpiRaw;
1155+
*( bind->len ) = ( DPI_BUFLEN_TYPE ) (( bind->isInOut ) ?
1156+
bind->maxSize : 0 );
1157+
bind->value = ( char *) malloc ( *(bind -> len ) );
1158+
}
1159+
else if (Buffer::HasInstance(obj))
11081160
{
11091161
size_t bufLen = Buffer::Length(obj);
11101162
bind->type = dpi::DpiRaw;
1111-
if(type == NJS_BIND_INOUT)
1163+
if( bind->isInOut )
11121164
{
11131165
*(bind->len) = (DPI_BUFLEN_TYPE) bufLen;
11141166
}
@@ -1160,7 +1212,7 @@ void Connection::GetInBindParamsScalar(Local<Value> v8val, Bind* bind,
11601212
allocate for one unit.
11611213
*/
11621214
void Connection::GetInBindParamsArray(Local<Array> va8vals, Bind *bind,
1163-
eBaton *executeBaton, BindType type)
1215+
eBaton *executeBaton )
11641216
{
11651217
Nan::HandleScope scope;
11661218
size_t arrayElementSize = 0; // actual array element size
@@ -3906,8 +3958,9 @@ void Connection::v8Date2OraDate(v8::Local<v8::Value> val, Bind *bind)
39063958
Local<Date> date = val.As<Date>(); // Expects to be of v8::Date type
39073959

39083960
// Get the number of seconds from 1970-1-1 0:0:0
3909-
*(long double *)(bind->extvalue) = date->NumberValue ();
3910-
3961+
// In case given value is NULL/Undefined, set it to 0
3962+
*(long double *)(bind->extvalue) = (val->IsNull () || val->IsUndefined ()) ?
3963+
0 : date->NumberValue ();
39113964
}
39123965

39133966
/***************************************************************************/
@@ -3979,45 +4032,59 @@ void Connection::cbDynBufferAllocate ( void *ctx, bool dmlReturning,
39794032

39804033
Connection::AllocateBindArray ( bind->type, bind, executeBaton,
39814034
&arrayElementSize );
3982-
return;
4035+
goto exitcbDynBufferAllocate;
39834036
}
39844037

39854038

39864039
if ( NJS_SIZE_T_OVERFLOW ( sizeof ( short ), nRows ) )
39874040
{
39884041
executeBaton->error = NJSMessages::getErrorMsg( errResultsTooLarge );
3989-
return;
4042+
goto exitcbDynBufferAllocate;
39904043
}
39914044
else
39924045
{
3993-
bind->ind = (short *)malloc ( (size_t)nRows * sizeof ( short ) ) ;
3994-
if( !bind->ind )
4046+
if ( !bind->ind )
39954047
{
3996-
executeBaton->error = NJSMessages::getErrorMsg( errInsufficientMemory );
3997-
return;
4048+
bind->ind = (short *)malloc ( (size_t)nRows * sizeof ( short ) ) ;
4049+
if( !bind->ind )
4050+
{
4051+
executeBaton->error = NJSMessages::getErrorMsg(
4052+
errInsufficientMemory );
4053+
goto exitcbDynBufferAllocate;
4054+
}
39984055
}
39994056
}
40004057
if ( dmlReturning )
40014058
{
40024059
if ( NJS_SIZE_T_OVERFLOW ( sizeof ( unsigned int ), nRows ) )
40034060
{
40044061
executeBaton->error = NJSMessages::getErrorMsg( errResultsTooLarge );
4005-
return;
4062+
goto exitcbDynBufferAllocate;
40064063
}
40074064
else
40084065
{
40094066
bind->len2 = ( unsigned int *)malloc ( nRows * sizeof ( unsigned int ) );
40104067
if( !bind->len2 )
40114068
{
4012-
executeBaton->error = NJSMessages::getErrorMsg( errInsufficientMemory );
4013-
return;
4069+
executeBaton->error = NJSMessages::getErrorMsg(
4070+
errInsufficientMemory );
4071+
goto exitcbDynBufferAllocate;
40144072
}
40154073
}
40164074
}
40174075
else
40184076
{
4019-
bind->len = (DPI_BUFLEN_TYPE *)malloc ( nRows *
4020-
sizeof ( DPI_BUFLEN_TYPE ) );
4077+
if ( !bind->len )
4078+
{
4079+
bind->len = (DPI_BUFLEN_TYPE *)malloc ( nRows *
4080+
sizeof ( DPI_BUFLEN_TYPE ) );
4081+
if ( !bind->len )
4082+
{
4083+
executeBaton->error = NJSMessages::getErrorMsg (
4084+
errInsufficientMemory ) ;
4085+
goto exitcbDynBufferAllocate;
4086+
}
4087+
}
40214088
}
40224089

40234090
switch ( bind->type )
@@ -4028,7 +4095,7 @@ void Connection::cbDynBufferAllocate ( void *ctx, bool dmlReturning,
40284095
if ( NJS_SIZE_T_OVERFLOW ( (bind->maxSize + 1), nRows) )
40294096
{
40304097
executeBaton->error = NJSMessages::getErrorMsg( errResultsTooLarge );
4031-
return;
4098+
goto exitcbDynBufferAllocate;
40324099
}
40334100
else
40344101
{
@@ -4037,7 +4104,7 @@ void Connection::cbDynBufferAllocate ( void *ctx, bool dmlReturning,
40374104
{
40384105
executeBaton->error = NJSMessages::getErrorMsg(
40394106
errInsufficientMemory);
4040-
return;
4107+
goto exitcbDynBufferAllocate;
40414108
}
40424109
}
40434110

@@ -4055,7 +4122,7 @@ void Connection::cbDynBufferAllocate ( void *ctx, bool dmlReturning,
40554122
if ( NJS_SIZE_T_OVERFLOW ( sizeof (int), nRows) )
40564123
{
40574124
executeBaton->error = NJSMessages::getErrorMsg( errResultsTooLarge );
4058-
return;
4125+
goto exitcbDynBufferAllocate;
40594126
}
40604127
else
40614128
{
@@ -4064,7 +4131,7 @@ void Connection::cbDynBufferAllocate ( void *ctx, bool dmlReturning,
40644131
{
40654132
executeBaton->error = NJSMessages::getErrorMsg(
40664133
errInsufficientMemory);
4067-
return;
4134+
goto exitcbDynBufferAllocate;
40684135
}
40694136
}
40704137
if ( !dmlReturning )
@@ -4077,7 +4144,7 @@ void Connection::cbDynBufferAllocate ( void *ctx, bool dmlReturning,
40774144
if ( NJS_SIZE_T_OVERFLOW ( sizeof ( unsigned int ), nRows) )
40784145
{
40794146
executeBaton->error = NJSMessages::getErrorMsg( errResultsTooLarge );
4080-
return;
4147+
goto exitcbDynBufferAllocate;
40814148
}
40824149
else
40834150
{
@@ -4086,7 +4153,7 @@ void Connection::cbDynBufferAllocate ( void *ctx, bool dmlReturning,
40864153
{
40874154
executeBaton->error = NJSMessages::getErrorMsg(
40884155
errInsufficientMemory);
4089-
return;
4156+
goto exitcbDynBufferAllocate;
40904157
}
40914158
}
40924159
if ( !dmlReturning )
@@ -4099,7 +4166,7 @@ void Connection::cbDynBufferAllocate ( void *ctx, bool dmlReturning,
40994166
if ( NJS_SIZE_T_OVERFLOW ( sizeof ( double ), nRows) )
41004167
{
41014168
executeBaton->error = NJSMessages::getErrorMsg( errResultsTooLarge );
4102-
return;
4169+
goto exitcbDynBufferAllocate;
41034170
}
41044171
else
41054172
{
@@ -4108,7 +4175,7 @@ void Connection::cbDynBufferAllocate ( void *ctx, bool dmlReturning,
41084175
{
41094176
executeBaton->error = NJSMessages::getErrorMsg(
41104177
errInsufficientMemory);
4111-
return;
4178+
goto exitcbDynBufferAllocate;
41124179
}
41134180
}
41144181
if ( !dmlReturning )
@@ -4131,7 +4198,7 @@ void Connection::cbDynBufferAllocate ( void *ctx, bool dmlReturning,
41314198
if ( NJS_SIZE_T_OVERFLOW ( sizeof ( Descriptor * ), nRows) )
41324199
{
41334200
executeBaton->error = NJSMessages::getErrorMsg( errResultsTooLarge );
4134-
return;
4201+
goto exitcbDynBufferAllocate;
41354202
}
41364203
else
41374204
{
@@ -4140,7 +4207,7 @@ void Connection::cbDynBufferAllocate ( void *ctx, bool dmlReturning,
41404207
{
41414208
executeBaton->error = NJSMessages::getErrorMsg(
41424209
errInsufficientMemory);
4143-
return;
4210+
goto exitcbDynBufferAllocate;
41444211
}
41454212
}
41464213
// and allocate the underlying descriptor(s)
@@ -4161,7 +4228,7 @@ void Connection::cbDynBufferAllocate ( void *ctx, bool dmlReturning,
41614228
if ( NJS_SIZE_T_OVERFLOW ( sizeof ( long double ), nRows) )
41624229
{
41634230
executeBaton->error = NJSMessages::getErrorMsg( errResultsTooLarge );
4164-
return;
4231+
goto exitcbDynBufferAllocate;
41654232
}
41664233
else
41674234
{
@@ -4171,7 +4238,7 @@ void Connection::cbDynBufferAllocate ( void *ctx, bool dmlReturning,
41714238
{
41724239
executeBaton->error = NJSMessages::getErrorMsg(
41734240
errInsufficientMemory);
4174-
return;
4241+
goto exitcbDynBufferAllocate;
41754242
}
41764243
}
41774244
// needed to post-process DML RETURNING of TimestampLTZ
@@ -4194,7 +4261,7 @@ void Connection::cbDynBufferAllocate ( void *ctx, bool dmlReturning,
41944261
if ( NJS_SIZE_T_OVERFLOW ( bind->maxSize, nRows ) )
41954262
{
41964263
executeBaton->error = NJSMessages::getErrorMsg ( errResultsTooLarge );
4197-
return;
4264+
goto exitcbDynBufferAllocate;
41984265
}
41994266
else
42004267
{
@@ -4203,6 +4270,9 @@ void Connection::cbDynBufferAllocate ( void *ctx, bool dmlReturning,
42034270
}
42044271
break;
42054272
}
4273+
4274+
exitcbDynBufferAllocate:
4275+
;
42064276
}
42074277

42084278
/****************************************************************************/

0 commit comments

Comments
 (0)