Skip to content

Commit c1560fe

Browse files
committed
Added support for RAW data type by @bjouhier
1 parent 6da31bf commit c1560fe

File tree

9 files changed

+422
-9
lines changed

9 files changed

+422
-9
lines changed

CHANGELOG.md

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

33
## node-oracledb v1.2.0 (DD Mon YYYY)
44

5+
- Added support for RAW data type.
6+
57
- Fixed intermittent crash while setting `fetchAsString`, and incorrect output while reading the value.
68

79
- Changed write-only attributes to allow console.log() on Connection objects. Note the attribute values will show as null; refer to the documentation.

doc/api.md

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ limitations under the License.
2727
- BIND_INOUT
2828
- BIND_OUT
2929
- BLOB
30+
- BUFFER
3031
- CLOB
3132
- CURSOR
3233
- DATE
@@ -259,6 +260,8 @@ Oracledb.OBJECT // Fetch each row as an object
259260
```
260261
Oracledb.BLOB // Bind a BLOB to return a Node.js buffer
261262
263+
Oracledb.BUFFER // Bind a RAW to return a Node.js Buffer
264+
262265
Oracledb.CLOB // Bind a CLOB to return a Node.js string
263266
264267
Oracledb.CURSOR // Bind a REF CURSOR to a node-oracledb ResultSet class
@@ -1137,8 +1140,14 @@ Bind Property | Description
11371140
---------------|------------
11381141
`val` | The input value or variable to be used for an IN or IN OUT bind variable.
11391142
`dir` | The direction of the bind. One of the [Oracledb Constants](#oracledbconstants) `BIND_IN`, `BIND_INOUT`, or `BIND_OUT`.
1140-
`type` | The datatype to be bound. One of the [Oracledb Constants](#oracledbconstants) `STRING`, `NUMBER`, `DATE` or `CURSOR`.
1141-
`maxSize` | The maximum number of bytes that an OUT or IN OUT bind variable of type STRING can use. The default value is 200. The maximum limit is 32767.
1143+
`type` | The datatype to be bound. One of the [Oracledb Constants](#oracledbconstants) `STRING`, `NUMBER`, `DATE`, `CURSOR` or `BUFFER`.
1144+
`maxSize` | The maximum number of bytes that an OUT or IN OUT bind variable of type STRING or BUFFER can use. The default value is 200. The maximum limit is 32767.
1145+
1146+
In case of BUFFER type, when using Oracle Database 12c, in the init.ora file
1147+
if MAX_STRING_SIZE parameter has a value of STANDARD, then the maximum size of
1148+
BUFFER type is 4000. If MAX_STRING_SIZE parameter has a value of EXTENDED then
1149+
the maximum size of BUFFER type is 32767. In earlier versions of Oracle
1150+
Database, the maximum size of BUFFER type is 4000.
11421151

11431152
With OUT binds, where the type cannot be inferred by node-oracledb
11441153
because there is no input data value, the type defaults to `STRING`
@@ -2893,7 +2902,7 @@ connection.execute("INSERT INTO countries VALUES (:country_id, :country_name)",
28932902
```
28942903
28952904
For IN binds the direction must be `BIND_IN`. The type can be
2896-
`STRING`, `NUMBER` or `DATE`, matching the data. The type `CURSOR`
2905+
`STRING`, `NUMBER`, `DATE` or `BUFFER`, matching the data. The type `CURSOR`
28972906
cannot be used with IN binds.
28982907
28992908
### <a name="outbind"></a> 12.2 OUT and IN OUT Bind Parameters
@@ -2906,10 +2915,10 @@ properties is used.
29062915
The `dir` attribute should be `BIND_OUT` or `BIND_INOUT`.
29072916
29082917
For `BIND_INOUT` parameters, the `type` attribute should be `STRING`,
2909-
`NUMBER` or `DATE`.
2918+
`NUMBER`, `DATE` or `BUFFER`.
29102919
29112920
For `BIND_OUT` parameters the `type` attribute should be `STRING`,
2912-
`NUMBER`, `DATE`, `CURSOR`, `BLOB` or `CLOB`.
2921+
`NUMBER`, `DATE`, `CURSOR`, `BLOB`, `CLOB` or `BUFFER`.
29132922
29142923
If `type` is not specified then `STRING` is assumed.
29152924

src/njs/src/njsConnection.cpp

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -572,7 +572,7 @@ void Connection::GetBindUnit (Handle<Value> val, Bind* bind,
572572
NanScope();
573573
unsigned int dir = BIND_IN;
574574

575-
if(val->IsObject() && !val->IsDate())
575+
if(val->IsObject() && !val->IsDate() && !Buffer::HasInstance(val))
576576
{
577577
dir = BIND_UNKNOWN;
578578
Local<Object> bind_unit = val->ToObject();
@@ -674,6 +674,10 @@ void Connection::GetOutBindParams (unsigned short dataType, Bind* bind,
674674
bind->type = dpi::DpiRSet;
675675
bind->maxSize = 0;
676676
break;
677+
case DATA_BUFFER :
678+
bind->type = dpi::DpiRaw;
679+
bind->maxSize = 0;
680+
break;
677681
case DATA_CLOB :
678682
bind->type = dpi::DpiClob;
679683
bind->maxSize = 0;
@@ -807,6 +811,33 @@ void Connection::GetInBindParams (Handle<Value> v8val, Bind* bind,
807811
/* Convert v8::Date value to long double */
808812
Connection::v8Date2OraDate ( v8val, bind);
809813
}
814+
else if(v8val->IsObject ())
815+
{
816+
Local<Object> obj = v8val->ToObject();
817+
if (Buffer::HasInstance(obj)) {
818+
size_t bufLen = Buffer::Length(obj);
819+
bind->type = dpi::DpiRaw;
820+
if(type == BIND_INOUT)
821+
{
822+
*(bind->len) = bufLen;
823+
}
824+
else // IN
825+
{
826+
bind->maxSize = *(bind->len) = bufLen;
827+
}
828+
DPI_SZ_TYPE size = (bind->maxSize >= *(bind->len) ) ?
829+
bind->maxSize : *(bind->len);
830+
if(size)
831+
{
832+
bind->value = (char*)malloc(size);
833+
if(bufLen)
834+
memcpy(bind->value, Buffer::Data(obj), bufLen);
835+
}
836+
} else {
837+
executeBaton->error= NJSMessages::getErrorMsg(errInvalidBindDataType,2);
838+
goto exitGetInBindParams;
839+
}
840+
}
810841
else
811842
{
812843
executeBaton->error= NJSMessages::getErrorMsg(errInvalidBindDataType,2);
@@ -839,6 +870,23 @@ void Connection::Async_Execute (uv_work_t *req)
839870

840871
if ( !executeBaton->error.empty() ) goto exitAsyncExecute;
841872

873+
// In DML Returning statements, Buffer type is not allowed temporarily.
874+
if ( executeBaton->stmtIsReturning )
875+
{
876+
for ( unsigned int b = 0; b < executeBaton->binds.size () ; b ++ )
877+
{
878+
if ( executeBaton->binds[b]->isOut &&
879+
executeBaton->binds[b]->type == dpi::DpiRaw )
880+
{
881+
executeBaton->error = NJSMessages::getErrorMsg (
882+
errBufferReturningInvalid );
883+
return;
884+
885+
}
886+
}
887+
}
888+
889+
842890
if (executeBaton->st == DpiStmtSelect)
843891
{
844892
// set prefetch
@@ -1523,6 +1571,26 @@ void Connection::DoDefines ( eBaton* executeBaton, const dpi::MetaData* meta,
15231571

15241572
}
15251573
break;
1574+
case dpi::DpiRaw :
1575+
defines[col].fetchType = DpiRaw;
1576+
defines[col].maxSize = meta[col].dbSize;
1577+
1578+
if ( NJS_SIZE_T_OVERFLOW ( defines[col].maxSize,
1579+
executeBaton->maxRows ) )
1580+
{
1581+
executeBaton->error = NJSMessages::getErrorMsg (
1582+
errResultsTooLarge ) ;
1583+
return;
1584+
}
1585+
defines[col].buf = (char *)malloc(defines[col].maxSize *
1586+
executeBaton->maxRows) ;
1587+
if ( !defines[col].buf )
1588+
{
1589+
executeBaton->error = NJSMessages::getErrorMsg (
1590+
errInsufficientMemory );
1591+
return;
1592+
}
1593+
break;
15261594

15271595
case dpi::DpiClob:
15281596
case dpi::DpiBlob:
@@ -2174,6 +2242,9 @@ Handle<Value> Connection::GetValueCommon ( eBaton *executeBaton,
21742242
date = NanNew<v8::Date>( *(long double*)val );
21752243
value = date;
21762244
break;
2245+
case (dpi::DpiRaw) :
2246+
value = NanNewBufferHandle((char*)val, len);
2247+
break;
21772248
// The LOB types are hit only by the define code path
21782249
// The bind code path has its own Connection::GetValueLob method
21792250
case (dpi::DpiClob):

src/njs/src/njsMessages.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ static const char *errMsg[] =
6060
"NJS-024: memory allocation failed",
6161
"NJS-025: overflow when calculating results area size",
6262
"NJS-026: maxRows must be greater than zero",
63+
"NJS-027: raw database type is not supported with DML Returning statements",
6364
};
6465

6566
string NJSMessages::getErrorMsg ( NJSErrorType err, ... )

src/njs/src/njsMessages.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ typedef enum
5959
errInsufficientMemory,
6060
errResultsTooLarge,
6161
errInvalidmaxRows,
62+
errBufferReturningInvalid,
6263

6364
// New ones should be added here
6465

test/dataTypeAssist.js

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,8 @@ assist.allDataTypeNames =
6060
"oracledb_timestamp6" : "TIMESTAMP (9) WITH LOCAL TIME ZONE",
6161
"oracledb_rowid" : "ROWID",
6262
"oracledb_myclobs" : "CLOB",
63-
"oracledb_myblobs" : "BLOB"
63+
"oracledb_myblobs" : "BLOB",
64+
"oracledb_raw" : "RAW(2000)"
6465
};
6566

6667
assist.data = {
@@ -368,6 +369,15 @@ assist.createCharString = function(size) {
368369
return buffer.toString();
369370
}
370371

372+
assist.createBuffer = function(size) {
373+
var array = [];
374+
for(var i = 0; i < size; i++) {
375+
var b = Math.floor(Math.random() * 256); // generate a random integer among 0-255
376+
array.push(b);
377+
}
378+
return new Buffer(array);
379+
}
380+
371381
assist.setUp = function(connection, tableName, array, done)
372382
{
373383
async.series([
@@ -483,6 +493,8 @@ assist.dataTypeSupport = function(connection, tableName, array, done) {
483493
result.rows[i].CONTENT.trim().should.eql(array[result.rows[i].NUM]);
484494
else if( (typeof result.rows[i].CONTENT) === 'number' )
485495
result.rows[i].CONTENT.should.eql(array[result.rows[i].NUM]);
496+
else if( Buffer.isBuffer(result.rows[i].CONTENT) )
497+
result.rows[i].CONTENT.toString('hex').should.eql(array[result.rows[i].NUM].toString('hex'));
486498
else
487499
result.rows[i].CONTENT.toUTCString().should.eql(array[result.rows[i].NUM].toUTCString());
488500
}
@@ -560,6 +572,8 @@ function fetchRowsFromRS(rs, array, cb)
560572
rows[i].CONTENT.trim().should.eql(array[rows[i].NUM]);
561573
else if( (typeof rows[i].CONTENT) === 'number' )
562574
rows[i].CONTENT.should.eql(array[rows[i].NUM]);
575+
else if( Buffer.isBuffer(rows[i].CONTENT) )
576+
rows[i].CONTENT.toString('hex').should.eql(array[rows[i].NUM].toString('hex'));
563577
else
564578
rows[i].CONTENT.toUTCString().should.eql(array[rows[i].NUM].toUTCString());
565579
}

0 commit comments

Comments
 (0)