Skip to content

Commit 578e4aa

Browse files
committed
Support array as regular in param and not as OutParam
1 parent afa7225 commit 578e4aa

File tree

5 files changed

+233
-86
lines changed

5 files changed

+233
-86
lines changed

src/connection.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,10 @@ int Connection::SetValuesOnStatement(oracle::occi::Statement* stmt, ExecuteBaton
222222
case VALUE_TYPE_TIMESTAMP:
223223
stmt->setTimestamp(index, *((oracle::occi::Timestamp*)val->value));
224224
break;
225+
case VALUE_TYPE_ARRAY:
226+
stmt->setDatabaseNCHARParam(index, true);
227+
stmt->setDataBufferArray(index, val->value, val->elemetnsType, val->collectionLength, &val->collectionLength, val->elementsSize, val->elementLength, NULL, NULL);
228+
break;
225229
case VALUE_TYPE_OUTPUT:
226230
outParam = static_cast<OutParam*>(val->value);
227231
// std::cout << "OutParam B: " << outParam << " "<< outParam->type() << " " << outParam->_inOut.hasInParam << std::endl;
@@ -279,6 +283,22 @@ int Connection::SetValuesOnStatement(oracle::occi::Statement* stmt, ExecuteBaton
279283
case OutParam::OCCIBLOB:
280284
stmt->registerOutParam(index, oracle::occi::OCCIBLOB);
281285
break;
286+
case OutParam::OCCIVECTOR:
287+
// OCCIVECTOR is supported only as an IN param.
288+
if(!outParam->_inOut.hasInParam) {
289+
ostringstream oss;
290+
oss << "SetValuesOnStatement: Unknown OutParam type: " << outParamType;
291+
baton->error = new std::string(oss.str());
292+
return -2;
293+
}
294+
295+
//if (outParam->_inOut.collectionValues == NULL)
296+
//throw NodeOracleException("OutParam::OCCIVECTOR has empty collection");
297+
298+
stmt->setDatabaseNCHARParam(index, true);
299+
stmt->setDataBufferArray(index, outParam->_inOut.collectionValues, outParam->_inOut.elemetnsType, outParam->_inOut.collectionLength,
300+
&outParam->_inOut.collectionLength, outParam->_inOut.elementsSize, outParam->_inOut.elementLength, NULL, NULL);
301+
break;
282302
default:
283303
{
284304
ostringstream oss;
@@ -507,6 +527,8 @@ void Connection::ExecuteStatement(ExecuteBaton* baton, oracle::occi::Statement*
507527
break;
508528
case OutParam::OCCINUMBER:
509529
output->numberVal = stmt->getNumber(output->index);
530+
break;
531+
case OutParam::OCCIVECTOR:
510532
break;
511533
default:
512534
{
@@ -841,6 +863,10 @@ void Connection::handleResult(ExecuteBaton* baton, Handle<Value> (&argv)[2]) {
841863
case OutParam::OCCINUMBER:
842864
obj->Set(String::New(returnParam.c_str()), Number::New(output->numberVal));
843865
break;
866+
case OutParam::OCCIVECTOR:
867+
//in vector
868+
obj->Set(String::New(returnParam.c_str()), String::New("in OCCIVECTOR was here"));
869+
break;
844870
default:
845871
{
846872
ostringstream oss;

src/executeBaton.cpp

Lines changed: 98 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,14 @@ void ExecuteBaton::CopyValuesToBaton(ExecuteBaton* baton, v8::Local<v8::Array>*
136136
baton->values.push_back(value);
137137
}
138138

139+
// array
140+
else if (val->IsArray()) {
141+
value->type = VALUE_TYPE_ARRAY;
142+
Local<Array> arr = Local<Array>::Cast(val);
143+
GetVectorParam(baton, value, arr);
144+
baton->values.push_back(value);
145+
}
146+
139147
// output
140148
else if(val->IsObject() && val->ToObject()->FindInstanceInPrototypeChain(uni::Deref(OutParam::constructorTemplate)) != v8::Null()) {
141149
OutParam* op = node::ObjectWrap::Unwrap<OutParam>(val->ToObject());
@@ -161,6 +169,95 @@ void ExecuteBaton::CopyValuesToBaton(ExecuteBaton* baton, v8::Local<v8::Array>*
161169
baton->error = new std::string(message.str());
162170
return;
163171
}
164-
165172
}
166173
}
174+
175+
void ExecuteBaton::GetVectorParam(ExecuteBaton* baton, value_t *value, Local<Array> arr) {
176+
// In case the array is empty just initialize the fields as we would need something in Connection::SetValuesOnStatement
177+
if (arr->Length() < 1) {
178+
value->value = new int[0];
179+
value->collectionLength = 0;
180+
value->elementsSize = 0;
181+
value->elementLength = new ub2[0];
182+
value->elemetnsType = oracle::occi::OCCIINT;
183+
return;
184+
}
185+
186+
// Next we create the array buffer that will be used later as the value for the param (in Connection::SetValuesOnStatement)
187+
// The array type will be derived from the type of the first element.
188+
Local<Value> val = arr->Get(0);
189+
190+
// String array
191+
if (val->IsString()) {
192+
value->elemetnsType = oracle::occi::OCCI_SQLT_STR;
193+
194+
// Find the longest string, this is necessary in order to create a buffer later.
195+
int longestString = 0;
196+
for(unsigned int i = 0; i < arr->Length(); i++) {
197+
Local<Value> currVal = arr->Get(i);
198+
if (currVal->ToString()->Utf8Length() > longestString)
199+
longestString = currVal->ToString()->Utf8Length();
200+
}
201+
202+
// Add 1 for '\0'
203+
++longestString;
204+
205+
// Create a long char* that will hold the entire array, it is important to create a FIXED SIZE array,
206+
// meaning all strings have the same allocated length.
207+
char* strArr = new char[arr->Length() * longestString];
208+
value->elementLength = new ub2[arr->Length()];
209+
210+
// loop thru the arr and copy the strings into the strArr
211+
int bytesWritten = 0;
212+
for(unsigned int i = 0; i < arr->Length(); i++) {
213+
Local<Value> currVal = arr->Get(i);
214+
if(!currVal->IsString()) {
215+
std::ostringstream message;
216+
message << "Input array has object with invalid type at index " << i << ", all object must be of type 'string' which is the type of the first element";
217+
baton->error = new std::string(message.str());
218+
return;
219+
}
220+
221+
String::Utf8Value utfStr(currVal);
222+
223+
// Copy this string onto the strArr (we put \0 in the beginning as this is what strcat expects).
224+
strArr[bytesWritten] = '\0';
225+
strncat(strArr + bytesWritten, *utfStr, longestString);
226+
bytesWritten += longestString;
227+
228+
// Set the length of this element, add +1 for the '\0'
229+
value->elementLength[i] = utfStr.length() + 1;
230+
}
231+
232+
value->value = strArr;
233+
value->collectionLength = arr->Length();
234+
value->elementsSize = longestString;
235+
}
236+
237+
// Integer array.
238+
else if (val->IsNumber()) {
239+
// Allocate memory and copy the ints.
240+
double* intArr = new double[arr->Length()];
241+
for(unsigned int i = 0; i < arr->Length(); i++) {
242+
Local<Value> currVal = arr->Get(i);
243+
if(!currVal->IsNumber()) {
244+
std::ostringstream message;
245+
message << "Input array has object with invalid type at index " << i << ", all object must be of type 'number' which is the type of the first element";
246+
baton->error = new std::string(message.str());
247+
return;
248+
}
249+
250+
intArr[i] = currVal->ToNumber()->Value();
251+
}
252+
253+
value->value = intArr;
254+
value->collectionLength = arr->Length();
255+
value->elementsSize = sizeof(double);
256+
value->elemetnsType = oracle::occi::OCCIFLOAT;
257+
}
258+
259+
// Unsupported type
260+
else {
261+
baton->error = new std::string("The type of the first element in the input array is not supported");
262+
}
263+
}

src/executeBaton.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ enum {
2323
VALUE_TYPE_DATE = 5,
2424
VALUE_TYPE_TIMESTAMP = 6,
2525
VALUE_TYPE_CLOB = 7,
26-
VALUE_TYPE_BLOB = 8
26+
VALUE_TYPE_BLOB = 8,
27+
VALUE_TYPE_ARRAY = 9
2728
};
2829

2930
struct column_t {
@@ -39,6 +40,12 @@ struct row_t {
3940
struct value_t {
4041
int type;
4142
void* value;
43+
44+
// This will hold the info needed for binding vectors values
45+
ub4 collectionLength;
46+
sb4 elementsSize; // The size of each element in the array
47+
ub2* elementLength; // An array that holds the actual length of each element in the array (in case of strings)
48+
oracle::occi::Type elemetnsType;
4249
};
4350

4451
struct output_t {
@@ -77,6 +84,7 @@ class ExecuteBaton {
7784
int updateCount;
7885

7986
static void CopyValuesToBaton(ExecuteBaton* baton, v8::Local<v8::Array>* values);
87+
static void GetVectorParam(ExecuteBaton* baton, value_t *value, v8::Local<v8::Array> arr);
8088
};
8189

8290
#endif

src/outParam.cpp

Lines changed: 99 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -61,90 +61,9 @@ uni::CallbackType OutParam::New(const uni::FunctionCallbackInfo& args) {
6161
break;
6262
}
6363
case OutParam::OCCIVECTOR: {
64-
// Get the vector's elements type
65-
Local<Value> valType = opts->Get(String::New("type"));
66-
if(valType->IsUndefined() || valType->IsNull())
67-
UNI_THROW(Exception::Error(String::New("OutParam::OCCIVECTOR missing `type` property")));
68-
69-
// Create the collection according to the elem type.
70-
int type = valType->ToInt32()->Value();
71-
switch(type) {
72-
// Here we create the array buffer that will be used later as the value for the param on the sp statement (Connection::SetValuesOnStatement)
73-
case OutParam::OCCISTRING: {
74-
outParam->_inOut.elemetnsType = oracle::occi::OCCI_SQLT_STR;
75-
76-
// Get the array
77-
Local<Array> arr = Local<Array>::Cast(opts->Get(String::New("in")));
78-
79-
// Find the longest string, this is necessary in order to create a buffer later.
80-
// If "size" was provided by the user we use it as the size of the "longest string", otherwise we would look for it.
81-
int longestString = 0;
82-
if (opts->Has(String::New("in"))) {
83-
longestString = outParam->_size;
84-
} else {
85-
for(unsigned int i = 0; i < arr->Length(); i++) {
86-
Local<Value> val = arr->Get(i);
87-
if (val->ToString()->Utf8Length() > longestString)
88-
longestString = val->ToString()->Utf8Length();
89-
}
90-
}
91-
92-
// Add 1 for '\0'
93-
++longestString;
94-
95-
// Create a long char* that will hold the entire array, it is important to create a FIXED SIZE array,
96-
// meaning all strings have the same allocated length.
97-
char* strArr = new char[arr->Length() * longestString];
98-
outParam->_inOut.elementLength = new ub2[arr->Length()];
99-
100-
// loop thru the arr and copy the strings into the strArr
101-
int bytesWritten = 0;
102-
for(unsigned int i = 0; i < arr->Length(); i++) {
103-
Local<Value> val = arr->Get(i);
104-
if(!val->IsString()) {
105-
UNI_THROW(Exception::Error(String::New("OutParam::OCCIVECTOR of type OCCISTRING must include string types only")));
106-
}
107-
108-
String::Utf8Value utfStr(val);
109-
110-
// Copy this string onto the strArr (we put \0 in the beginning as this is what strcat expects).
111-
strArr[bytesWritten] = '\0';
112-
strncat(strArr + bytesWritten, *utfStr, longestString);
113-
bytesWritten += longestString;
114-
115-
// Set the length of this element, add +1 for the '\0'
116-
outParam->_inOut.elementLength[i] = utfStr.length() + 1;
117-
}
118-
119-
outParam->_inOut.collectionValues = strArr;
120-
outParam->_inOut.collectionLength = arr->Length();
121-
outParam->_inOut.elementsSize = longestString;
122-
break;
123-
}
124-
case OutParam::OCCIINT: {
125-
Local<Array> arr = Local<Array>::Cast( opts->Get(String::New("in")));
126-
127-
// Allocate memory and copy the ints.
128-
int* intArr = new int[arr->Length()];
129-
for(unsigned int i = 0; i < arr->Length(); i++) {
130-
Local<Value> val = arr->Get(i);
131-
if(!val->IsInt32()) {
132-
UNI_THROW(Exception::Error(String::New("OutParam::OCCIVECTOR of type OCCIINT must include integer types only")));
133-
}
134-
135-
intArr[i] = val->ToInt32()->Value();
136-
}
137-
138-
outParam->_inOut.collectionValues = intArr;
139-
outParam->_inOut.collectionLength = arr->Length();
140-
outParam->_inOut.elementsSize = sizeof(int);
141-
outParam->_inOut.elemetnsType = oracle::occi::OCCIINT;
142-
break;
143-
}
144-
default:
145-
UNI_THROW(Exception::Error(String::New("OutParam::OCCIVECTOR unsupported `type`, only supports OCCIINT and OCCISTRING")));
146-
}
147-
// End case:OCCIVECTOR
64+
uni::CallbackType ret = OutParam::GetVectorParam(opts, outParam);
65+
if (!ret->IsNull())
66+
return ret;
14867
break;
14968
}
15069
default:
@@ -185,3 +104,99 @@ int OutParam::type() {
185104
int OutParam::size() {
186105
return _size;
187106
}
107+
108+
uni::CallbackType OutParam::GetVectorParam(Local<Object> opts, OutParam* outParam) {
109+
// Get the array
110+
Local<Value> val = opts->Get(String::New("in"));
111+
if (!val->IsArray())
112+
UNI_THROW(Exception::Error(String::New("OutParam::OCCIVECTOR must include array object as 'in' property")));
113+
114+
Local<Array> arr = Local<Array>::Cast(val);
115+
116+
if (arr->Length() < 1) {
117+
outParam->_inOut.collectionLength = arr->Length();
118+
outParam->_inOut.collectionValues = new int[0];
119+
outParam->_inOut.elementsSize = 0;
120+
outParam->_inOut.elementLength = new ub2[0];
121+
return v8::Null();
122+
}
123+
124+
125+
// Get the vector's elements type if specified, default is int.
126+
int type;
127+
OBJ_GET_NUMBER(opts, "type", type, OutParam::OCCIINT);
128+
129+
switch(type) {
130+
// Here we create the array buffer that will be used later as the value for the param on the sp statement (Connection::SetValuesOnStatement)
131+
case OutParam::OCCISTRING: {
132+
outParam->_inOut.elemetnsType = oracle::occi::OCCI_SQLT_STR;
133+
134+
// Find the longest string, this is necessary in order to create a buffer later.
135+
// If "size" was provided by the user we use it as the size of the "longest string".
136+
int longestString = 0;
137+
if (opts->Has(String::New("size"))) {
138+
longestString = outParam->_size;
139+
} else {
140+
// Loop thru all strings and save the length of the longest one.
141+
for(unsigned int i = 0; i < arr->Length(); i++) {
142+
Local<Value> val = arr->Get(i);
143+
if (val->ToString()->Utf8Length() > longestString)
144+
longestString = val->ToString()->Utf8Length();
145+
}
146+
}
147+
148+
// Add 1 for '\0'
149+
++longestString;
150+
151+
// Create a long char* that will hold the entire array, it is important to create a FIXED SIZE array,
152+
// meaning all strings have the same allocated length.
153+
char* strArr = new char[arr->Length() * longestString];
154+
outParam->_inOut.elementLength = new ub2[arr->Length()];
155+
156+
// loop thru the arr and copy the strings into the strArr
157+
int bytesWritten = 0;
158+
for(unsigned int i = 0; i < arr->Length(); i++) {
159+
Local<Value> val = arr->Get(i);
160+
if(!val->IsString())
161+
UNI_THROW(Exception::Error(String::New("OutParam::OCCIVECTOR of type OCCISTRING must include string types only")));
162+
163+
String::Utf8Value utfStr(val);
164+
165+
// Copy this string onto the strArr (we put \0 in the beginning as this is what strcat expects).
166+
strArr[bytesWritten] = '\0';
167+
strncat(strArr + bytesWritten, *utfStr, longestString);
168+
bytesWritten += longestString;
169+
170+
// Set the length of this element, add +1 for the '\0'
171+
outParam->_inOut.elementLength[i] = utfStr.length() + 1;
172+
}
173+
174+
outParam->_inOut.collectionValues = strArr;
175+
outParam->_inOut.collectionLength = arr->Length();
176+
outParam->_inOut.elementsSize = longestString;
177+
break;
178+
}
179+
case OutParam::OCCIINT: {
180+
// Allocate memory and copy the ints.
181+
int* intArr = new int[arr->Length()];
182+
for(unsigned int i = 0; i < arr->Length(); i++) {
183+
Local<Value> val = arr->Get(i);
184+
if(!val->IsInt32()) {
185+
UNI_THROW(Exception::Error(String::New("OutParam::OCCIVECTOR of type OCCIINT must include integer types only")));
186+
}
187+
188+
intArr[i] = val->ToInt32()->Value();
189+
}
190+
191+
outParam->_inOut.collectionValues = intArr;
192+
outParam->_inOut.collectionLength = arr->Length();
193+
outParam->_inOut.elementsSize = sizeof(int32_t);
194+
outParam->_inOut.elemetnsType = oracle::occi::OCCIINT;
195+
break;
196+
}
197+
default:
198+
UNI_THROW(Exception::Error(String::New("OutParam::OCCIVECTOR unsupported `type`, only supports OCCIINT and OCCISTRING")));
199+
}
200+
201+
return v8::Null();
202+
}

0 commit comments

Comments
 (0)