Skip to content

Commit ad4f201

Browse files
committed
Add support for fetching CLOB columns as STRINGs with oracledb.fetchAsString and fetchInfo
1 parent eda8681 commit ad4f201

File tree

12 files changed

+1268
-461
lines changed

12 files changed

+1268
-461
lines changed

doc/api.md

Lines changed: 260 additions & 195 deletions
Large diffs are not rendered by default.

examples/lobselect.js

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. */
2+
3+
/******************************************************************************
4+
*
5+
* You may not use the identified files except in compliance with the Apache
6+
* License, Version 2.0 (the "License.")
7+
*
8+
* You may obtain a copy of the License at
9+
* http://www.apache.org/licenses/LICENSE-2.0.
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
*
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*
18+
* NAME
19+
* lobselect.js
20+
*
21+
* DESCRIPTION
22+
* SELECTs a CLOB and displays it to the screen.
23+
*
24+
* 'Large' CLOBs should be streamed as shown in lobstream1.js
25+
*
26+
* Use demo.sql to create the required table or do:
27+
* DROP TABLE mylobs;
28+
* CREATE TABLE mylobs (id NUMBER, c CLOB, b BLOB);
29+
*
30+
* Run lobinsert1.js to load data before running this example.
31+
*
32+
*****************************************************************************/
33+
34+
var async = require('async');
35+
var oracledb = require('oracledb');
36+
var dbConfig = require('./dbconfig.js');
37+
38+
// force all CLOBs to be returned as Strings
39+
oracledb.fetchAsString = [ oracledb.CLOB ];
40+
41+
var doconnect = function(cb) {
42+
oracledb.getConnection(
43+
{
44+
user : dbConfig.user,
45+
password : dbConfig.password,
46+
connectString : dbConfig.connectString
47+
},
48+
function(err, conn) {
49+
if (err)
50+
return cb(err);
51+
else {
52+
return cb(null, conn);
53+
}
54+
});
55+
};
56+
57+
var dorelease = function(conn) {
58+
conn.close(function (err) {
59+
if (err)
60+
console.error(err.message);
61+
});
62+
};
63+
64+
var doquery = function(conn, cb) {
65+
conn.execute(
66+
"SELECT c FROM mylobs WHERE id = :idbv",
67+
[1],
68+
// An alternative to oracledb.fetchAsString is to use fetchInfo on a column:
69+
// { fetchInfo: {"C": {type: oracledb.STRING}} },
70+
function(err, result)
71+
{
72+
if (err) {
73+
return cb(err, conn);
74+
}
75+
if (result.rows.length === 0) {
76+
return cb(new Error("No results. Did you run lobinsert1.js?"), conn);
77+
}
78+
var clob = result.rows[0][0];
79+
console.log('The CLOB was: ');
80+
console.log(clob);
81+
return cb(null, conn);
82+
});
83+
};
84+
85+
// Connect and call the CLOB example
86+
async.waterfall([
87+
doconnect,
88+
doquery
89+
],
90+
function (err, conn) {
91+
if (err) { console.error("In waterfall error cb: ==>", err, "<=="); }
92+
if (conn)
93+
dorelease(conn);
94+
});

examples/selectjsonclob.js

Lines changed: 10 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -74,32 +74,18 @@ var dojsonquery = function (conn, cb) {
7474
console.log('Selecting JSON stored in a CLOB column');
7575
conn.execute(
7676
"SELECT po_document FROM j_purchaseorder_c WHERE JSON_EXISTS (po_document, '$.location')",
77+
[],
78+
{ fetchInfo: { "PO_DOCUMENT": { type: oracledb.STRING} } }, // Fetch as a String instead of a Stream
7779
function(err, result)
7880
{
79-
if (err) { return cb(err, conn); }
80-
if (result.rows.length === 0) { return cb(new Error('No results'), conn); }
81+
if (err)
82+
return cb(err, conn);
83+
if (result.rows.length === 0)
84+
return cb(new Error('No results'), conn);
8185

82-
var clob = '';
83-
var lob = result.rows[0][0]; // just show first record
84-
if (lob === null) { return cb(new Error('CLOB was NULL'), conn); }
85-
lob.setEncoding('utf8'); // set the encoding so we get a 'string' not a 'buffer'
86-
lob.on('data',
87-
function(chunk)
88-
{
89-
clob += chunk;
90-
});
91-
lob.on('close',
92-
function()
93-
{
94-
var js = JSON.parse(clob);
95-
console.log('Query results: ', js);
96-
return cb(null, conn);
97-
});
98-
lob.on('error',
99-
function(err)
100-
{
101-
return cb(err, conn);
102-
});
86+
console.log('Query results:');
87+
console.log(result.rows);
88+
return cb(null, conn);
10389
});
10490
};
10591

@@ -108,7 +94,7 @@ async.waterfall(
10894
doconnect,
10995
checkver,
11096
doinsert,
111-
dojsonquery,
97+
dojsonquery
11298
],
11399
function (err, conn) {
114100
if (err) { console.error("In waterfall error cb: ==>", err, "<=="); }

src/dpi/include/dpiStmt.h

Lines changed: 47 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,48 @@ typedef enum
141141
#endif
142142

143143

144+
// Forward declaration
145+
class Stmt;
146+
147+
148+
// Application (Driver) level callback function prototype
149+
typedef int (*bindcbtype) (void *ctx, DPI_SZ_TYPE nRows, unsigned int bndpos,
150+
unsigned long iter,
151+
unsigned long index, void **bufpp, void **alenp,
152+
void **indpp, unsigned short **rcodepp,
153+
unsigned char *piecep );
154+
155+
// Application (Driver) level callback funciton prototype
156+
typedef int (*definecbtype) ( void *ctx, unsigned long definePos,
157+
unsigned long iter, unsigned long *prevIter,
158+
void **bufpp, void **alenp, void **indpp,
159+
unsigned short **rcodepp );
160+
161+
162+
163+
// Bind-Dynamic Context structure - used for DML RETURNING case.
164+
typedef struct
165+
{
166+
bindcbtype callbackfn; /* Application specific callback */
167+
void* data; /* Data for application specific callback */
168+
unsigned long nrows; /* number of rows affected by this DML */
169+
unsigned long iter; /* iteration - used in Array Bind */
170+
unsigned int bndpos; /* position in the bind array */
171+
short nullInd; /* DML RETURNING: to pass null from inbind cbk */
172+
Stmt *dpistmt; /* DPI Statement Implementation */
173+
} DpiBindCallbackCtx;
174+
175+
176+
// Define-Dynamic Context structure - used for CLOB-as-STRING case
177+
typedef struct
178+
{
179+
definecbtype callbackfn; /* Application specific callback */
180+
void *data; /* data for application specific callback */
181+
unsigned int definePos; /* 0-based define column position */
182+
unsigned long prevIter; /* earlier iter, used to detect iter changing */
183+
} DpiDefineCallbackCtx;
184+
185+
144186
typedef struct MetaData
145187
{
146188
unsigned char *colName; // column name
@@ -158,12 +200,6 @@ typedef struct MetaData
158200
} MetaData;
159201

160202

161-
// Application (Driver) level callback function prototype
162-
typedef int (*cbtype) (void *ctx, DPI_SZ_TYPE nRows, unsigned int bndpos,
163-
unsigned long iter,
164-
unsigned long index, dvoid **bufpp, void **alenp,
165-
dvoid **indpp, unsigned short **rcodepp,
166-
unsigned char *piecep );
167203

168204
class Stmt
169205
{
@@ -187,21 +223,21 @@ class Stmt
187223
virtual void bind(unsigned int pos, unsigned short type, void *buf,
188224
DPI_SZ_TYPE bufSize, short *ind, DPI_BUFLEN_TYPE *bufLen,
189225
unsigned int maxarr_len, unsigned int *curelen,
190-
void *data,
191-
cbtype cb = NULL ) = 0;
226+
DpiBindCallbackCtx *ctx = NULL) = 0;
192227

193228
virtual void bind(const unsigned char *name, int nameLen,
194229
unsigned int bndpos,
195230
unsigned short type, void *buf, DPI_SZ_TYPE bufSize,
196231
short *ind, DPI_BUFLEN_TYPE *bufLen,
197232
unsigned int maxarr_len, unsigned int *curelen,
198-
void *data,
199-
cbtype cb = NULL ) = 0;
233+
DpiBindCallbackCtx *ctx = NULL ) = 0;
200234

201235
virtual void execute ( int numIterations, bool autoCommit = false) = 0;
202236

203237
virtual void define(unsigned int pos, unsigned short type, void *buf,
204-
DPI_SZ_TYPE bufSize, short *ind, DPI_BUFLEN_TYPE *bufLen) = 0;
238+
DPI_SZ_TYPE bufSize, short *ind,
239+
DPI_BUFLEN_TYPE *bufLen,
240+
DpiDefineCallbackCtx *ctx = NULL ) = 0;
205241

206242
virtual void fetch(unsigned int numRows = 1) = 0;
207243

0 commit comments

Comments
 (0)