Skip to content

Commit afa7225

Browse files
committed
add initial support for vectors
1 parent aa46f36 commit afa7225

File tree

4 files changed

+112
-3
lines changed

4 files changed

+112
-3
lines changed

lib/oracle.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ exports.OCCIDATE = 6;
3434
exports.OCCITIMESTAMP = 7;
3535
exports.OCCINUMBER = 8;
3636
exports.OCCIBLOB = 9;
37+
exports.OCCIVECTOR = 10;
3738

3839
// Reader is implemented in JS around a C++ handle
3940
// This is easier and also more efficient because we don't cross the JS/C++ boundary

src/outParam.cpp

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,93 @@ uni::CallbackType OutParam::New(const uni::FunctionCallbackInfo& args) {
6060
OBJ_GET_STRING(opts, "in", outParam->_inOut.stringVal);
6161
break;
6262
}
63+
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
148+
break;
149+
}
63150
default:
64151
UNI_THROW(Exception::Error(String::New("Unhandled OutPram type!")));
65152
}
@@ -76,6 +163,19 @@ OutParam::OutParam() {
76163
}
77164

78165
OutParam::~OutParam() {
166+
if (_inOut.collectionValues != NULL) {
167+
// This can be either a char* or int*
168+
if (_inOut.elemetnsType == oracle::occi::OCCIINT)
169+
delete (int*)(_inOut.collectionValues);
170+
else if (_inOut.elemetnsType == oracle::occi::OCCI_SQLT_STR)
171+
delete (char*)(_inOut.collectionValues);
172+
}
173+
174+
if (_inOut.elementLength != 0)
175+
delete _inOut.elementLength;
176+
177+
if (_inOut.stringVal != NULL)
178+
delete _inOut.stringVal;
79179
}
80180

81181
int OutParam::type() {

src/outParam.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,13 @@ struct inout_t {
2222
oracle::occi::Date dateVal;
2323
oracle::occi::Timestamp timestampVal;
2424
oracle::occi::Number numberVal;
25+
26+
// This will hold the info needed for binding vectors values
27+
void* collectionValues;
28+
ub4 collectionLength;
29+
sb4 elementsSize; // The size of each element in the array
30+
ub2* elementLength; // An array that holds the actual length of each element in the array (in case of strings)
31+
oracle::occi::Type elemetnsType;
2532
};
2633

2734
class OutParam : public ObjectWrap {
@@ -47,6 +54,7 @@ class OutParam : public ObjectWrap {
4754
static const int OCCITIMESTAMP = 7;
4855
static const int OCCINUMBER = 8;
4956
static const int OCCIBLOB = 9;
57+
static const int OCCIVECTOR = 10;
5058

5159
private:
5260
};

tests-settings.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"hostname": "localhost",
3-
"user": "test",
4-
"password": "test"
2+
"hostname": "yubuntu",
3+
"user": "yuvalw",
4+
"password": "123457"
55
}

0 commit comments

Comments
 (0)