Skip to content

Commit 3ebe956

Browse files
committed
Add BLOB fetchAsBuffer support
1 parent 62b069b commit 3ebe956

File tree

11 files changed

+13731
-600
lines changed

11 files changed

+13731
-600
lines changed

src/njs/src/njsConnection.cpp

Lines changed: 90 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2015, 2016, Oracle and/or its affiliates.
1+
/* Copyright (c) 2015, 2017, Oracle and/or its affiliates.
22
All rights reserved. */
33

44
/******************************************************************************
@@ -68,7 +68,7 @@ Nan::Persistent<FunctionTemplate> Connection::connectionTemplate_s;
6868
#define NJS_MAX_FETCH_AS_STRING_SIZE 200
6969

7070
// Size of block allocated each time when callback is called for
71-
// for fetch-CLOB-as-STRING. This constant is used only CLOB-as-STRING case
71+
// for fetch-CLOB-as-STRING/fetch-BLOB-as-Buffer.
7272
#if OCI_MAJOR_VERSION >= 12
7373
#define NJS_ITER_SIZE 524287 /* Use (512KB - 1) with 12c Clients */
7474
#else
@@ -490,13 +490,16 @@ NAN_METHOD(Connection::Execute)
490490
executeBaton->outFormat = connection->oracledb_->getOutFormat();
491491
executeBaton->autoCommit = connection->oracledb_->getAutoCommit();
492492
executeBaton->dpienv = connection->oracledb_->getDpiEnv();
493+
executeBaton->dpiconn = connection->dpiconn_;
494+
executeBaton->njsconn = connection;
493495
executeBaton->fetchAsStringTypes =
494496
(DataType*) connection->oracledb_->getFetchAsStringTypes ();
495497
executeBaton->fetchAsStringTypesCount =
496498
connection->oracledb_->getFetchAsStringTypesCount ();
497-
498-
executeBaton->dpiconn = connection->dpiconn_;
499-
executeBaton->njsconn = connection;
499+
executeBaton->fetchAsBufferTypes =
500+
(DataType*)connection->oracledb_->getFetchAsBufferTypes ();
501+
executeBaton->fetchAsBufferTypesCount =
502+
connection->oracledb_->getFetchAsBufferTypesCount () ;
500503
executeBaton->extendedMetaData =
501504
connection->oracledb_->getExtendedMetaData ();
502505

@@ -637,9 +640,11 @@ void Connection::ProcessOptions (Nan::NAN_METHOD_ARGS_TYPE args, unsigned int in
637640

638641
fInfo[index].njsType = (DataType) tmptype;
639642

640-
// Only Conversion to STRING allowed now. Either STRING or DB type.
643+
// Only Conversion to STRING/Buffer allowed now.
644+
// Either STRING/BUFFER or DB type.
641645
if ( ( fInfo[index].njsType != NJS_DATATYPE_DEFAULT ) &&
642-
( fInfo[index].njsType != NJS_DATATYPE_STR ) )
646+
( fInfo[index].njsType != NJS_DATATYPE_STR ) &&
647+
( fInfo[index].njsType != NJS_DATATYPE_BUFFER) )
643648
{
644649
executeBaton->error = NJSMessages::getErrorMsg (
645650
errInvalidTypeForConversion );
@@ -2796,8 +2801,11 @@ void Connection::CopyMetaData ( MetaInfo *mInfo,
27962801
break;
27972802

27982803
case dpi::DpiBlob:
2799-
mInfo[col].dpiFetchType = mData[col].dbType;
2800-
mInfo[col].njsFetchType = NJS_DATATYPE_BLOB;
2804+
mInfo[col].dpiFetchType = Connection::GetTargetType ( executeBaton,
2805+
mInfo[col].name,
2806+
dpi::DpiBlob );
2807+
mInfo[col].njsFetchType = ( mInfo[col].dpiFetchType == dpi::DpiRaw ) ?
2808+
NJS_DATATYPE_BUFFER : NJS_DATATYPE_BLOB ;
28012809
break;
28022810

28032811
case dpi::DpiRowid:
@@ -2907,6 +2915,10 @@ boolean Connection::MapByName ( eBaton *executeBaton, std::string &name,
29072915
{
29082916
targetType = dpi::DpiVarChar;
29092917
}
2918+
else if ( executeBaton->fetchInfo[f].njsType == NJS_DATATYPE_BUFFER )
2919+
{
2920+
targetType = dpi::DpiRaw ;
2921+
}
29102922
else if ( executeBaton->fetchInfo[f].njsType == NJS_DATATYPE_DEFAULT )
29112923
{
29122924
targetType = Connection::SourceDBType2TargetDBType ( targetType );
@@ -2939,7 +2951,7 @@ boolean Connection::MapByType ( eBaton *executeBaton, unsigned short &dbType )
29392951
boolean modified = false;
29402952
unsigned int count = 0 ;
29412953

2942-
/* If oracledb property is set map using that */
2954+
/* Process Fetch-As-string settings from global oracledb property first */
29432955
if ( executeBaton->fetchAsStringTypes )
29442956
{
29452957
count = executeBaton->fetchAsStringTypesCount;
@@ -3000,6 +3012,26 @@ boolean Connection::MapByType ( eBaton *executeBaton, unsigned short &dbType )
30003012
}
30013013
}
30023014

3015+
/* Process fetch-blob-as-buffer from global oracledb property */
3016+
if ( !modified && executeBaton->fetchAsBufferTypes )
3017+
{
3018+
count = executeBaton->fetchAsBufferTypesCount;
3019+
switch ( dbType )
3020+
{
3021+
case dpi::DpiBlob:
3022+
for ( unsigned int t = 0 ; !modified && ( t < count ) ; t ++ )
3023+
{
3024+
if ( executeBaton->fetchAsBufferTypes[t] == NJS_DATATYPE_BLOB )
3025+
{
3026+
/* convert all BLOB column values to BUFFER */
3027+
dbType = dpi::DpiRaw;
3028+
modified = true;
3029+
break;
3030+
}
3031+
}
3032+
}
3033+
}
3034+
30033035
return dbType;
30043036
}
30053037

@@ -3215,9 +3247,17 @@ void Connection::DoDefines ( eBaton* executeBaton )
32153247
case dpi::DpiBlob:
32163248
case dpi::DpiBfile:
32173249
defines[col].fetchType = executeBaton->mInfo[col].dpiFetchType;
3218-
defines[col].maxSize =
3219-
( defines[col].fetchType == dpi::DpiVarChar ) ?
3220-
sizeof ( char *) : sizeof ( Descriptor *) ;
3250+
if ( executeBaton->mInfo[col].dbType == dpi::DpiClob )
3251+
{
3252+
defines[col].maxSize =
3253+
( defines[col].fetchType == dpi::DpiVarChar ) ?
3254+
sizeof ( char *) : sizeof ( Descriptor *) ;
3255+
}
3256+
else if ( executeBaton->mInfo[col].dbType == dpi::DpiBlob )
3257+
{
3258+
defines[col].maxSize = ( defines[col].fetchType == dpi::DpiRaw ) ?
3259+
sizeof ( void *) : sizeof ( Descriptor * ) ;
3260+
}
32213261

32223262
if ( NJS_SIZE_T_OVERFLOW ( defines[col].maxSize,
32233263
executeBaton->maxRows ) )
@@ -3242,13 +3282,17 @@ void Connection::DoDefines ( eBaton* executeBaton )
32423282
{
32433283
for (unsigned int j = 0; j < executeBaton->maxRows; j++)
32443284
{
3245-
if ( defines[col].fetchType == dpi::DpiVarChar )
3285+
switch ( defines[col].fetchType )
32463286
{
3287+
case dpi::DpiVarChar:
32473288
// Clob-Fetch-As-String - allocation happens in callback
32483289
((char **)(defines[col].buf))[j] = NULL;
3249-
}
3250-
else
3251-
{
3290+
break;
3291+
case dpi::DpiRaw:
3292+
// Blob-Fetch-As-Buffer - allocation happens in callback
3293+
((void **)(defines[col].buf))[j] = NULL;
3294+
break;
3295+
default:
32523296
((Descriptor **)(defines[col].buf))[j] =
32533297
executeBaton->dpienv->allocDescriptor(LobDescriptorType);
32543298
}
@@ -3309,32 +3353,34 @@ void Connection::DoDefines ( eBaton* executeBaton )
33093353

33103354
void *buf = NULL ;
33113355
DpiDefineCallbackCtx *ctx = NULL ;
3312-
bool clobAsStr = false ;
3356+
bool lobAs = false ;
33133357

3314-
if ( ( defines[col].fetchType == dpi::DpiVarChar ) &&
3315-
( executeBaton->mInfo[col].dbType == dpi::DpiClob ) )
3358+
if ( ( ( defines[col].fetchType == dpi::DpiVarChar ) &&
3359+
( executeBaton->mInfo[col].dbType == dpi::DpiClob ) ) ||
3360+
( ( defines[col].fetchType == dpi::DpiRaw ) &&
3361+
( executeBaton->mInfo[col].dbType == dpi::DpiBlob ) ) )
33163362
{
3363+
/* Fetch Clob-As-String or Blob-As-Buffer case */
33173364
ctx = ( DpiDefineCallbackCtx * )malloc (
33183365
sizeof ( DpiDefineCallbackCtx ) );
33193366
ctx->callbackfn = (definecbtype ) Connection::cbDynDefine ;
33203367
ctx->data = (void *)executeBaton ;
33213368
ctx->definePos = col ;
33223369
ctx->prevIter = -1L ; /* no row processed yet */
3323-
clobAsStr = true ;
3370+
lobAs = true ;
33243371
executeBaton->extDefines[col] = new ExtDefine (
3325-
NJS_EXTDEFINE_CLOBASSTR ) ;
3326-
executeBaton->extDefines[col]->fields.extClobAsStr.ctx = (void *) ctx;
3372+
NJS_EXTDEFINE_CONVERT_LOB ) ;
3373+
executeBaton->extDefines[col]->fields.extConvertLob.ctx = (void *) ctx;
33273374

3328-
executeBaton->extDefines[col]->fields.extClobAsStr.len2 =
3375+
executeBaton->extDefines[col]->fields.extConvertLob.len2 =
33293376
( unsigned int * ) malloc ( sizeof ( unsigned int ) *
33303377
executeBaton->maxRows );
3331-
if( !executeBaton->extDefines[col]->fields.extClobAsStr.len2 )
3378+
if( !executeBaton->extDefines[col]->fields.extConvertLob.len2 )
33323379
{
33333380
executeBaton->error = NJSMessages::getErrorMsg (
33343381
errInsufficientMemory );
33353382
error = true;
33363383
}
3337-
33383384
}
33393385
else
33403386
{
@@ -3343,10 +3389,10 @@ void Connection::DoDefines ( eBaton* executeBaton )
33433389

33443390
executeBaton->dpistmt->define(col+1, defines[col].fetchType,
33453391
buf,
3346-
clobAsStr ?
3392+
lobAs ?
33473393
DPI_MAX_BUFLEN :defines[col].maxSize,
3348-
clobAsStr ? NULL : defines[col].ind,
3349-
clobAsStr ? NULL : defines[col].len,
3394+
lobAs ? NULL : defines[col].ind,
3395+
lobAs ? NULL : defines[col].len,
33503396
ctx );
33513397
}
33523398
}
@@ -3372,17 +3418,17 @@ void Connection::DoFetch (eBaton* executeBaton)
33723418
Define *define = &(executeBaton->defines[col] );
33733419
ExtDefine *extDefine = executeBaton->extDefines[col];
33743420

3375-
if ( extDefine && extDefine -> extDefType == NJS_EXTDEFINE_CLOBASSTR )
3421+
if ( extDefine && extDefine -> extDefType == NJS_EXTDEFINE_CONVERT_LOB )
33763422
{
3377-
/* In case of fetch-clob-as-string, the last read operation has partial
3423+
/* In case of fetch-lob-as-xxx the last read operation has partial
33783424
* size read, and consolidated len is maintained in extDefine, add both
33793425
* and set it back to define->len[row] it can be used later
33803426
*/
33813427
for ( unsigned int row = 0; row < executeBaton->rowsFetched ; row ++ )
33823428
{
33833429
define->len[row] = ( DPI_BUFLEN_TYPE )
3384-
extDefine->fields.extClobAsStr.len2[row];
3385-
define->len[row] += extDefine->fields.extClobAsStr.cLen ;
3430+
extDefine->fields.extConvertLob.len2[row];
3431+
define->len[row] += extDefine->fields.extConvertLob.cLen ;
33863432
}
33873433
}
33883434
}
@@ -3982,6 +4028,11 @@ Local<Value> Connection::GetValue ( eBaton *executeBaton,
39824028
{
39834029
buf = ((char **) (define->buf))[row];
39844030
}
4031+
else if ( ( define->fetchType == dpi::DpiRaw ) &&
4032+
( executeBaton->mInfo[col].dbType == dpi::DpiBlob ) )
4033+
{
4034+
buf = ((void **) (define->buf))[row];
4035+
}
39854036
else
39864037
{
39874038
buf = ((char *)(define->buf) + ( row * ( define->maxSize ) ) );
@@ -5607,12 +5658,12 @@ int Connection::cbDynDefine ( void *octxp, unsigned long definePos,
56075658
if ( *prevIter != iter )
56085659
{
56095660
*prevIter = iter;
5610-
extDefine->fields.extClobAsStr.cLen = 0;
5661+
extDefine->fields.extConvertLob.cLen = 0;
56115662
}
56125663
else
56135664
{
56145665
// maintain incremental size of clob
5615-
extDefine->fields.extClobAsStr.cLen += NJS_ITER_SIZE ;
5666+
extDefine->fields.extConvertLob.cLen += NJS_ITER_SIZE ;
56165667
}
56175668

56185669
tmp = buf[iter]; // preserve the current memory address
@@ -5621,7 +5672,7 @@ int Connection::cbDynDefine ( void *octxp, unsigned long definePos,
56215672
buf[iter] = (char *) ( ( !buf[iter] ) ?
56225673
malloc ( maxLen ) :
56235674
realloc ( buf[iter],
5624-
maxLen + extDefine->fields.extClobAsStr.cLen ) ) ;
5675+
maxLen + extDefine->fields.extConvertLob.cLen ) ) ;
56255676
if ( !buf[iter] )
56265677
{
56275678
// If realloc fails, the IN parameter requires to be freed and untouched
@@ -5631,13 +5682,13 @@ int Connection::cbDynDefine ( void *octxp, unsigned long definePos,
56315682
}
56325683
else
56335684
{
5634-
extDefine->fields.extClobAsStr.len2[iter] = maxLen;
5685+
extDefine->fields.extConvertLob.len2[iter] = maxLen;
56355686
define->ind[iter] = 0; // default value for indicator
56365687

5637-
*bufpp = (void *) (&buf[iter][extDefine->fields.extClobAsStr.cLen]);
5688+
*bufpp = (void *) (&buf[iter][extDefine->fields.extConvertLob.cLen]);
56385689

56395690
// size for this iter
5640-
*alenpp = (unsigned int *) &(extDefine->fields.extClobAsStr.len2[iter]) ;
5691+
*alenpp = (unsigned int *) &(extDefine->fields.extConvertLob.len2[iter]) ;
56415692

56425693
*indpp = (void *) &(define->ind[iter]); // indicator
56435694
}

src/njs/src/njsConnection.h

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2015, 2016, Oracle and/or its affiliates.
1+
/* Copyright (c) 2015, 2017, Oracle and/or its affiliates.
22
All rights reserved. */
33

44
/******************************************************************************
@@ -81,7 +81,7 @@ typedef enum
8181
typedef enum
8282
{
8383
NJS_EXTDEFINE_UNDEFINED = 0, /* Not defined yet */
84-
NJS_EXTDEFINE_CLOBASSTR = 1, /* Used as part of Fetch Clob As String */
84+
NJS_EXTDEFINE_CONVERT_LOB = 1, /* Used as part of lob As String/buffer */
8585
} ExtDefineType;
8686

8787

@@ -235,23 +235,23 @@ typedef struct ExtDefine
235235
// containter for type specific data
236236
union
237237
{
238-
// Fields required for Fetch-Clob-As-String case
238+
// Fields required for Fetch-Clob-As-String case or Fetch-Blob-As-Buffer
239239
struct
240240
{
241241
void *ctx; /* Context pointer used by the call back */
242-
DPI_BUFLEN_TYPE cLen;
243-
unsigned int *len2; /* Length of the buffer */
244-
} extClobAsStr ;
242+
DPI_BUFLEN_TYPE cLen; /* cummulative length from each callback */
243+
unsigned int *len2; /* size of the buffer for each row */
244+
} extConvertLob ;
245245
} fields;
246246

247247
ExtDefine ( ExtDefineType type )
248248
{
249249
extDefType = type;
250-
if ( type == NJS_EXTDEFINE_CLOBASSTR )
250+
if ( type == NJS_EXTDEFINE_CONVERT_LOB )
251251
{
252-
fields.extClobAsStr.ctx = NULL ;
253-
fields.extClobAsStr.cLen = 0;
254-
fields.extClobAsStr.len2 = NULL;
252+
fields.extConvertLob.ctx = NULL ;
253+
fields.extConvertLob.cLen = 0;
254+
fields.extConvertLob.len2 = NULL;
255255
}
256256
}
257257
} ExtDefine;
@@ -318,6 +318,8 @@ typedef struct eBaton
318318
std::vector<ExtDefine*> extDefines;
319319
unsigned int fetchAsStringTypesCount;
320320
DataType *fetchAsStringTypes; // Global by type settings
321+
unsigned int fetchAsBufferTypesCount;
322+
DataType *fetchAsBufferTypes;
321323
unsigned int fetchInfoCount; // Conversion requested count
322324
FetchInfo *fetchInfo; // Conversion meta data
323325
Nan::Persistent<Function> cb;
@@ -337,6 +339,7 @@ typedef struct eBaton
337339
numCols(0), dpistmt(NULL), st(DpiStmtUnknown),
338340
stmtIsReturning (false), numOutBinds(0), defines(NULL),
339341
fetchAsStringTypesCount (0), fetchAsStringTypes(NULL),
342+
fetchAsBufferTypesCount (0), fetchAsBufferTypes(NULL),
340343
fetchInfoCount(0), fetchInfo(NULL), counter ( count ),
341344
extendedMetaData(false), mInfo(NULL), lobInfo(NULL)
342345
{
@@ -486,12 +489,12 @@ typedef struct eBaton
486489
if ( extDefines[i] )
487490
{
488491
// Fetch-Clob-As_string case
489-
if ( extDefines[i]->extDefType == NJS_EXTDEFINE_CLOBASSTR )
492+
if ( extDefines[i]->extDefType == NJS_EXTDEFINE_CONVERT_LOB )
490493
{
491-
free ( extDefines[i]->fields.extClobAsStr.ctx );
492-
extDefines[i]->fields.extClobAsStr.ctx = NULL ;
493-
free ( extDefines[i]->fields.extClobAsStr.len2 );
494-
extDefines[i]->fields.extClobAsStr.len2 = NULL ;
494+
free ( extDefines[i]->fields.extConvertLob.ctx );
495+
extDefines[i]->fields.extConvertLob.ctx = NULL ;
496+
free ( extDefines[i]->fields.extConvertLob.len2 );
497+
extDefines[i]->fields.extConvertLob.len2 = NULL ;
495498
delete extDefines[i];
496499
}
497500
}

0 commit comments

Comments
 (0)