knex 0.21.20 → 0.21.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/CONTRIBUTING.md +184 -184
- package/LICENSE +22 -22
- package/README.md +95 -95
- package/bin/cli.js +414 -414
- package/bin/utils/cli-config-utils.js +151 -151
- package/bin/utils/constants.js +7 -7
- package/bin/utils/migrationsLister.js +37 -37
- package/knex.js +8 -8
- package/lib/client.js +413 -413
- package/lib/config-resolver.js +61 -61
- package/lib/constants.js +44 -44
- package/lib/dialects/mssql/index.js +390 -390
- package/lib/dialects/mssql/query/compiler.js +444 -444
- package/lib/dialects/mssql/schema/columncompiler.js +103 -103
- package/lib/dialects/mssql/schema/compiler.js +59 -59
- package/lib/dialects/mssql/schema/tablecompiler.js +245 -245
- package/lib/dialects/mssql/transaction.js +97 -97
- package/lib/dialects/mysql/index.js +191 -191
- package/lib/dialects/mysql/query/compiler.js +142 -142
- package/lib/dialects/mysql/schema/columncompiler.js +171 -171
- package/lib/dialects/mysql/schema/compiler.js +60 -60
- package/lib/dialects/mysql/schema/tablecompiler.js +262 -262
- package/lib/dialects/mysql/transaction.js +48 -48
- package/lib/dialects/mysql2/index.js +35 -35
- package/lib/dialects/mysql2/transaction.js +46 -46
- package/lib/dialects/oracle/DEAD_CODE.md +5 -5
- package/lib/dialects/oracle/formatter.js +20 -20
- package/lib/dialects/oracle/index.js +79 -79
- package/lib/dialects/oracle/query/compiler.js +327 -327
- package/lib/dialects/oracle/schema/columnbuilder.js +18 -18
- package/lib/dialects/oracle/schema/columncompiler.js +139 -139
- package/lib/dialects/oracle/schema/compiler.js +81 -81
- package/lib/dialects/oracle/schema/tablecompiler.js +165 -165
- package/lib/dialects/oracle/schema/trigger.js +126 -126
- package/lib/dialects/oracle/utils.js +86 -86
- package/lib/dialects/oracledb/index.js +489 -489
- package/lib/dialects/oracledb/query/compiler.js +363 -363
- package/lib/dialects/oracledb/schema/columncompiler.js +35 -35
- package/lib/dialects/oracledb/transaction.js +76 -76
- package/lib/dialects/oracledb/utils.js +14 -14
- package/lib/dialects/postgres/index.js +319 -319
- package/lib/dialects/postgres/query/compiler.js +206 -206
- package/lib/dialects/postgres/schema/columncompiler.js +125 -125
- package/lib/dialects/postgres/schema/compiler.js +109 -109
- package/lib/dialects/postgres/schema/tablecompiler.js +183 -183
- package/lib/dialects/redshift/index.js +73 -73
- package/lib/dialects/redshift/query/compiler.js +119 -119
- package/lib/dialects/redshift/schema/columnbuilder.js +20 -20
- package/lib/dialects/redshift/schema/columncompiler.js +60 -60
- package/lib/dialects/redshift/schema/compiler.js +14 -14
- package/lib/dialects/redshift/schema/tablecompiler.js +123 -123
- package/lib/dialects/redshift/transaction.js +18 -18
- package/lib/dialects/sqlite3/formatter.js +21 -21
- package/lib/dialects/sqlite3/index.js +169 -169
- package/lib/dialects/sqlite3/query/compiler.js +222 -222
- package/lib/dialects/sqlite3/schema/columncompiler.js +27 -27
- package/lib/dialects/sqlite3/schema/compiler.js +49 -49
- package/lib/dialects/sqlite3/schema/ddl.js +525 -525
- package/lib/dialects/sqlite3/schema/tablecompiler.js +238 -238
- package/lib/formatter.js +295 -295
- package/lib/functionhelper.js +14 -14
- package/lib/helpers.js +92 -92
- package/lib/index.js +3 -3
- package/lib/interface.js +115 -115
- package/lib/knex.js +42 -42
- package/lib/logger.js +76 -76
- package/lib/migrate/MigrationGenerator.js +82 -82
- package/lib/migrate/Migrator.js +611 -611
- package/lib/migrate/configuration-merger.js +60 -60
- package/lib/migrate/migrate-stub.js +17 -17
- package/lib/migrate/migration-list-resolver.js +36 -36
- package/lib/migrate/sources/fs-migrations.js +99 -99
- package/lib/migrate/stub/cjs.stub +15 -15
- package/lib/migrate/stub/coffee.stub +13 -13
- package/lib/migrate/stub/eg.stub +14 -14
- package/lib/migrate/stub/js.stub +15 -15
- package/lib/migrate/stub/knexfile-coffee.stub +34 -34
- package/lib/migrate/stub/knexfile-eg.stub +43 -43
- package/lib/migrate/stub/knexfile-js.stub +44 -44
- package/lib/migrate/stub/knexfile-ls.stub +35 -35
- package/lib/migrate/stub/knexfile-ts.stub +44 -44
- package/lib/migrate/stub/ls.stub +14 -14
- package/lib/migrate/stub/ts.stub +21 -21
- package/lib/migrate/table-creator.js +67 -67
- package/lib/migrate/table-resolver.js +27 -27
- package/lib/query/builder.js +1372 -1372
- package/lib/query/compiler.js +889 -889
- package/lib/query/constants.js +13 -13
- package/lib/query/joinclause.js +263 -263
- package/lib/query/methods.js +92 -92
- package/lib/query/string.js +190 -190
- package/lib/raw.js +188 -188
- package/lib/ref.js +39 -39
- package/lib/runner.js +285 -285
- package/lib/schema/builder.js +82 -82
- package/lib/schema/columnbuilder.js +117 -117
- package/lib/schema/columncompiler.js +177 -177
- package/lib/schema/compiler.js +101 -101
- package/lib/schema/helpers.js +51 -51
- package/lib/schema/tablebuilder.js +288 -288
- package/lib/schema/tablecompiler.js +296 -296
- package/lib/seed/Seeder.js +203 -203
- package/lib/seed/seed-stub.js +13 -13
- package/lib/seed/stub/coffee.stub +9 -9
- package/lib/seed/stub/eg.stub +11 -11
- package/lib/seed/stub/js.stub +13 -13
- package/lib/seed/stub/ls.stub +11 -11
- package/lib/seed/stub/ts.stub +13 -13
- package/lib/transaction.js +363 -363
- package/lib/util/batchInsert.js +59 -59
- package/lib/util/delay.js +6 -6
- package/lib/util/fake-client.js +9 -9
- package/lib/util/finally-mixin.js +13 -13
- package/lib/util/fs.js +76 -76
- package/lib/util/import-file.js +13 -13
- package/lib/util/is-module-type.js +14 -14
- package/lib/util/is.js +32 -32
- package/lib/util/make-knex.js +338 -338
- package/lib/util/nanoid.js +29 -29
- package/lib/util/noop.js +1 -1
- package/lib/util/parse-connection.js +66 -66
- package/lib/util/save-async-stack.js +14 -14
- package/lib/util/template.js +52 -52
- package/lib/util/timeout.js +29 -29
- package/lib/util/timestamp.js +16 -16
- package/package.json +1 -1
- package/scripts/build.js +125 -125
- package/scripts/docker-compose.yml +111 -111
- package/scripts/next-release-howto.md +24 -24
- package/scripts/release.sh +34 -34
- package/scripts/runkit-example.js +34 -34
- package/scripts/stress-test/README.txt +18 -18
- package/scripts/stress-test/docker-compose.yml +47 -47
- package/scripts/stress-test/knex-stress-test.js +196 -196
- package/scripts/stress-test/mysql2-random-hanging-every-now-and-then.js +145 -145
- package/scripts/stress-test/mysql2-sudden-exit-without-error.js +100 -100
- package/scripts/stress-test/reconnect-test-mysql-based-drivers.js +184 -184
- package/types/index.d.ts +2249 -2249
- package/types/result.d.ts +27 -27
- package/types/tables.d.ts +4 -4
|
@@ -1,489 +1,489 @@
|
|
|
1
|
-
// Oracledb Client
|
|
2
|
-
// -------
|
|
3
|
-
const each = require('lodash/each');
|
|
4
|
-
const flatten = require('lodash/flatten');
|
|
5
|
-
const isEmpty = require('lodash/isEmpty');
|
|
6
|
-
const map = require('lodash/map');
|
|
7
|
-
const values = require('lodash/values');
|
|
8
|
-
const QueryCompiler = require('./query/compiler');
|
|
9
|
-
const ColumnCompiler = require('./schema/columncompiler');
|
|
10
|
-
const { BlobHelper, ReturningHelper, isConnectionError } = require('./utils');
|
|
11
|
-
const stream = require('stream');
|
|
12
|
-
const { promisify, inherits } = require('util');
|
|
13
|
-
const Transaction = require('./transaction');
|
|
14
|
-
const Client_Oracle = require('../oracle');
|
|
15
|
-
const Oracle_Formatter = require('../oracle/formatter');
|
|
16
|
-
const { isString } = require('../../util/is');
|
|
17
|
-
|
|
18
|
-
function Client_Oracledb() {
|
|
19
|
-
Client_Oracle.apply(this, arguments);
|
|
20
|
-
// Node.js only have 4 background threads by default, oracledb needs one by connection
|
|
21
|
-
if (this.driver) {
|
|
22
|
-
process.env.UV_THREADPOOL_SIZE = process.env.UV_THREADPOOL_SIZE || 1;
|
|
23
|
-
process.env.UV_THREADPOOL_SIZE =
|
|
24
|
-
parseInt(process.env.UV_THREADPOOL_SIZE) + this.driver.poolMax;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
inherits(Client_Oracledb, Client_Oracle);
|
|
28
|
-
|
|
29
|
-
Client_Oracledb.prototype.driverName = 'oracledb';
|
|
30
|
-
|
|
31
|
-
Client_Oracledb.prototype._driver = function () {
|
|
32
|
-
const client = this;
|
|
33
|
-
const oracledb = require('oracledb');
|
|
34
|
-
client.fetchAsString = [];
|
|
35
|
-
if (this.config.fetchAsString && Array.isArray(this.config.fetchAsString)) {
|
|
36
|
-
this.config.fetchAsString.forEach(function (type) {
|
|
37
|
-
if (!isString(type)) return;
|
|
38
|
-
type = type.toUpperCase();
|
|
39
|
-
if (oracledb[type]) {
|
|
40
|
-
if (
|
|
41
|
-
type !== 'NUMBER' &&
|
|
42
|
-
type !== 'DATE' &&
|
|
43
|
-
type !== 'CLOB' &&
|
|
44
|
-
type !== 'BUFFER'
|
|
45
|
-
) {
|
|
46
|
-
this.logger.warn(
|
|
47
|
-
'Only "date", "number", "clob" and "buffer" are supported for fetchAsString'
|
|
48
|
-
);
|
|
49
|
-
}
|
|
50
|
-
client.fetchAsString.push(oracledb[type]);
|
|
51
|
-
}
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
return oracledb;
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
Client_Oracledb.prototype.queryCompiler = function () {
|
|
58
|
-
return new QueryCompiler(this, ...arguments);
|
|
59
|
-
};
|
|
60
|
-
Client_Oracledb.prototype.columnCompiler = function () {
|
|
61
|
-
return new ColumnCompiler(this, ...arguments);
|
|
62
|
-
};
|
|
63
|
-
Client_Oracledb.prototype.formatter = function () {
|
|
64
|
-
return new Oracledb_Formatter(this, ...arguments);
|
|
65
|
-
};
|
|
66
|
-
Client_Oracledb.prototype.transaction = function () {
|
|
67
|
-
return new Transaction(this, ...arguments);
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
Client_Oracledb.prototype.prepBindings = function (bindings) {
|
|
71
|
-
return map(bindings, (value) => {
|
|
72
|
-
if (value instanceof BlobHelper && this.driver) {
|
|
73
|
-
return { type: this.driver.BLOB, dir: this.driver.BIND_OUT };
|
|
74
|
-
// Returning helper always use ROWID as string
|
|
75
|
-
} else if (value instanceof ReturningHelper && this.driver) {
|
|
76
|
-
return { type: this.driver.STRING, dir: this.driver.BIND_OUT };
|
|
77
|
-
} else if (typeof value === 'boolean') {
|
|
78
|
-
return value ? 1 : 0;
|
|
79
|
-
}
|
|
80
|
-
return value;
|
|
81
|
-
});
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
function resolveConnectString(connectionSettings) {
|
|
85
|
-
if (connectionSettings.connectString) {
|
|
86
|
-
return connectionSettings.connectString;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
if (!connectionSettings.port) {
|
|
90
|
-
return connectionSettings.host + '/' + connectionSettings.database;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
return (
|
|
94
|
-
connectionSettings.host +
|
|
95
|
-
':' +
|
|
96
|
-
connectionSettings.port +
|
|
97
|
-
'/' +
|
|
98
|
-
connectionSettings.database
|
|
99
|
-
);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// Get a raw connection, called by the `pool` whenever a new
|
|
103
|
-
// connection needs to be added to the pool.
|
|
104
|
-
Client_Oracledb.prototype.acquireRawConnection = function () {
|
|
105
|
-
const client = this;
|
|
106
|
-
const asyncConnection = new Promise(function (resolver, rejecter) {
|
|
107
|
-
// If external authentication don't have to worry about username/password and
|
|
108
|
-
// if not need to set the username and password
|
|
109
|
-
const oracleDbConfig = client.connectionSettings.externalAuth
|
|
110
|
-
? { externalAuth: client.connectionSettings.externalAuth }
|
|
111
|
-
: {
|
|
112
|
-
user: client.connectionSettings.user,
|
|
113
|
-
password: client.connectionSettings.password,
|
|
114
|
-
};
|
|
115
|
-
|
|
116
|
-
// In the case of external authentication connection string will be given
|
|
117
|
-
oracleDbConfig.connectString = resolveConnectString(
|
|
118
|
-
client.connectionSettings
|
|
119
|
-
);
|
|
120
|
-
|
|
121
|
-
if (client.connectionSettings.prefetchRowCount) {
|
|
122
|
-
oracleDbConfig.prefetchRows = client.connectionSettings.prefetchRowCount;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
if (client.connectionSettings.stmtCacheSize !== undefined) {
|
|
126
|
-
oracleDbConfig.stmtCacheSize = client.connectionSettings.stmtCacheSize;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
client.driver.fetchAsString = client.fetchAsString;
|
|
130
|
-
|
|
131
|
-
client.driver.getConnection(oracleDbConfig, function (err, connection) {
|
|
132
|
-
if (err) {
|
|
133
|
-
return rejecter(err);
|
|
134
|
-
}
|
|
135
|
-
connection.commitAsync = function () {
|
|
136
|
-
return new Promise((commitResolve, commitReject) => {
|
|
137
|
-
this.commit(function (err) {
|
|
138
|
-
if (err) {
|
|
139
|
-
return commitReject(err);
|
|
140
|
-
}
|
|
141
|
-
commitResolve();
|
|
142
|
-
});
|
|
143
|
-
});
|
|
144
|
-
};
|
|
145
|
-
connection.rollbackAsync = function () {
|
|
146
|
-
return new Promise((rollbackResolve, rollbackReject) => {
|
|
147
|
-
this.rollback(function (err) {
|
|
148
|
-
if (err) {
|
|
149
|
-
return rollbackReject(err);
|
|
150
|
-
}
|
|
151
|
-
rollbackResolve();
|
|
152
|
-
});
|
|
153
|
-
});
|
|
154
|
-
};
|
|
155
|
-
const fetchAsync = promisify(function (sql, bindParams, options, cb) {
|
|
156
|
-
options = options || {};
|
|
157
|
-
options.outFormat =
|
|
158
|
-
client.driver.OUT_FORMAT_OBJECT || client.driver.OBJECT;
|
|
159
|
-
if (!options.outFormat) {
|
|
160
|
-
throw new Error('not found oracledb.outFormat constants');
|
|
161
|
-
}
|
|
162
|
-
if (options.resultSet) {
|
|
163
|
-
connection.execute(
|
|
164
|
-
sql,
|
|
165
|
-
bindParams || [],
|
|
166
|
-
options,
|
|
167
|
-
function (err, result) {
|
|
168
|
-
if (err) {
|
|
169
|
-
if (isConnectionError(err)) {
|
|
170
|
-
connection.close().catch(function (err) {});
|
|
171
|
-
connection.__knex__disposed = err;
|
|
172
|
-
}
|
|
173
|
-
return cb(err);
|
|
174
|
-
}
|
|
175
|
-
const fetchResult = { rows: [], resultSet: result.resultSet };
|
|
176
|
-
const numRows = 100;
|
|
177
|
-
const fetchRowsFromRS = function (
|
|
178
|
-
connection,
|
|
179
|
-
resultSet,
|
|
180
|
-
numRows
|
|
181
|
-
) {
|
|
182
|
-
resultSet.getRows(numRows, function (err, rows) {
|
|
183
|
-
if (err) {
|
|
184
|
-
if (isConnectionError(err)) {
|
|
185
|
-
connection.close().catch(function (err) {});
|
|
186
|
-
connection.__knex__disposed = err;
|
|
187
|
-
}
|
|
188
|
-
resultSet.close(function () {
|
|
189
|
-
return cb(err);
|
|
190
|
-
});
|
|
191
|
-
} else if (rows.length === 0) {
|
|
192
|
-
return cb(null, fetchResult);
|
|
193
|
-
} else if (rows.length > 0) {
|
|
194
|
-
if (rows.length === numRows) {
|
|
195
|
-
fetchResult.rows = fetchResult.rows.concat(rows);
|
|
196
|
-
fetchRowsFromRS(connection, resultSet, numRows);
|
|
197
|
-
} else {
|
|
198
|
-
fetchResult.rows = fetchResult.rows.concat(rows);
|
|
199
|
-
return cb(null, fetchResult);
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
});
|
|
203
|
-
};
|
|
204
|
-
fetchRowsFromRS(connection, result.resultSet, numRows);
|
|
205
|
-
}
|
|
206
|
-
);
|
|
207
|
-
} else {
|
|
208
|
-
connection.execute(
|
|
209
|
-
sql,
|
|
210
|
-
bindParams || [],
|
|
211
|
-
options,
|
|
212
|
-
function (err, result) {
|
|
213
|
-
if (err) {
|
|
214
|
-
// dispose the connection on connection error
|
|
215
|
-
if (isConnectionError(err)) {
|
|
216
|
-
connection.close().catch(function (err) {});
|
|
217
|
-
connection.__knex__disposed = err;
|
|
218
|
-
}
|
|
219
|
-
return cb(err);
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
return cb(null, result);
|
|
223
|
-
}
|
|
224
|
-
);
|
|
225
|
-
}
|
|
226
|
-
});
|
|
227
|
-
connection.executeAsync = function (sql, bindParams, options) {
|
|
228
|
-
// Read all lob
|
|
229
|
-
return fetchAsync(sql, bindParams, options).then(async (results) => {
|
|
230
|
-
const closeResultSet = () => {
|
|
231
|
-
return results.resultSet
|
|
232
|
-
? promisify(results.resultSet.close).call(results.resultSet)
|
|
233
|
-
: Promise.resolve();
|
|
234
|
-
};
|
|
235
|
-
|
|
236
|
-
// Collect LOBs to read
|
|
237
|
-
const lobs = [];
|
|
238
|
-
if (results.rows) {
|
|
239
|
-
if (Array.isArray(results.rows)) {
|
|
240
|
-
for (let i = 0; i < results.rows.length; i++) {
|
|
241
|
-
// Iterate through the rows
|
|
242
|
-
const row = results.rows[i];
|
|
243
|
-
for (const column in row) {
|
|
244
|
-
if (row[column] instanceof stream.Readable) {
|
|
245
|
-
lobs.push({ index: i, key: column, stream: row[column] });
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
try {
|
|
253
|
-
for (const lob of lobs) {
|
|
254
|
-
// todo should be fetchAsString/fetchAsBuffer polyfill only
|
|
255
|
-
results.rows[lob.index][lob.key] = await lobProcessing(
|
|
256
|
-
lob.stream
|
|
257
|
-
);
|
|
258
|
-
}
|
|
259
|
-
} catch (e) {
|
|
260
|
-
await closeResultSet().catch(() => {});
|
|
261
|
-
|
|
262
|
-
throw e;
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
await closeResultSet();
|
|
266
|
-
|
|
267
|
-
return results;
|
|
268
|
-
});
|
|
269
|
-
};
|
|
270
|
-
resolver(connection);
|
|
271
|
-
});
|
|
272
|
-
});
|
|
273
|
-
return asyncConnection;
|
|
274
|
-
};
|
|
275
|
-
|
|
276
|
-
// Used to explicitly close a connection, called internally by the pool
|
|
277
|
-
// when a connection times out or the pool is shutdown.
|
|
278
|
-
Client_Oracledb.prototype.destroyRawConnection = function (connection) {
|
|
279
|
-
return connection.release();
|
|
280
|
-
};
|
|
281
|
-
|
|
282
|
-
// Runs the query on the specified connection, providing the bindings
|
|
283
|
-
// and any other necessary prep work.
|
|
284
|
-
Client_Oracledb.prototype._query = function (connection, obj) {
|
|
285
|
-
if (!obj.sql) throw new Error('The query is empty');
|
|
286
|
-
|
|
287
|
-
const options = { autoCommit: false };
|
|
288
|
-
if (obj.method === 'select') {
|
|
289
|
-
options.resultSet = true;
|
|
290
|
-
}
|
|
291
|
-
return connection
|
|
292
|
-
.executeAsync(obj.sql, obj.bindings, options)
|
|
293
|
-
.then(async function (response) {
|
|
294
|
-
// Flatten outBinds
|
|
295
|
-
let outBinds = flatten(response.outBinds);
|
|
296
|
-
obj.response = response.rows || [];
|
|
297
|
-
obj.rowsAffected = response.rows
|
|
298
|
-
? response.rows.rowsAffected
|
|
299
|
-
: response.rowsAffected;
|
|
300
|
-
|
|
301
|
-
//added for outBind parameter
|
|
302
|
-
if (obj.method === 'raw' && outBinds.length > 0) {
|
|
303
|
-
return {
|
|
304
|
-
response: outBinds,
|
|
305
|
-
};
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
if (obj.method === 'update') {
|
|
309
|
-
const modifiedRowsCount = obj.rowsAffected.length || obj.rowsAffected;
|
|
310
|
-
const updatedObjOutBinding = [];
|
|
311
|
-
const updatedOutBinds = [];
|
|
312
|
-
const updateOutBinds = (i) =>
|
|
313
|
-
function (value, index) {
|
|
314
|
-
const OutBindsOffset = index * modifiedRowsCount;
|
|
315
|
-
updatedOutBinds.push(outBinds[i + OutBindsOffset]);
|
|
316
|
-
};
|
|
317
|
-
|
|
318
|
-
for (let i = 0; i < modifiedRowsCount; i++) {
|
|
319
|
-
updatedObjOutBinding.push(obj.outBinding[0]);
|
|
320
|
-
each(obj.outBinding[0], updateOutBinds(i));
|
|
321
|
-
}
|
|
322
|
-
outBinds = updatedOutBinds;
|
|
323
|
-
obj.outBinding = updatedObjOutBinding;
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
if (!obj.returning && outBinds.length === 0) {
|
|
327
|
-
if (!connection.isTransaction) {
|
|
328
|
-
await connection.commitAsync();
|
|
329
|
-
}
|
|
330
|
-
return obj;
|
|
331
|
-
}
|
|
332
|
-
const rowIds = [];
|
|
333
|
-
let offset = 0;
|
|
334
|
-
|
|
335
|
-
for (let line = 0; line < obj.outBinding.length; line++) {
|
|
336
|
-
const ret = obj.outBinding[line];
|
|
337
|
-
|
|
338
|
-
offset =
|
|
339
|
-
offset +
|
|
340
|
-
(obj.outBinding[line - 1] ? obj.outBinding[line - 1].length : 0);
|
|
341
|
-
|
|
342
|
-
for (let index = 0; index < ret.length; index++) {
|
|
343
|
-
const out = ret[index];
|
|
344
|
-
|
|
345
|
-
await new Promise(function (bindResolver, bindRejecter) {
|
|
346
|
-
if (out instanceof BlobHelper) {
|
|
347
|
-
const blob = outBinds[index + offset];
|
|
348
|
-
if (out.returning) {
|
|
349
|
-
obj.response[line] = obj.response[line] || {};
|
|
350
|
-
obj.response[line][out.columnName] = out.value;
|
|
351
|
-
}
|
|
352
|
-
blob.on('error', function (err) {
|
|
353
|
-
bindRejecter(err);
|
|
354
|
-
});
|
|
355
|
-
blob.on('finish', function () {
|
|
356
|
-
bindResolver();
|
|
357
|
-
});
|
|
358
|
-
blob.write(out.value);
|
|
359
|
-
blob.end();
|
|
360
|
-
} else if (obj.outBinding[line][index] === 'ROWID') {
|
|
361
|
-
rowIds.push(outBinds[index + offset]);
|
|
362
|
-
bindResolver();
|
|
363
|
-
} else {
|
|
364
|
-
obj.response[line] = obj.response[line] || {};
|
|
365
|
-
obj.response[line][out] = outBinds[index + offset];
|
|
366
|
-
bindResolver();
|
|
367
|
-
}
|
|
368
|
-
});
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
if (connection.isTransaction) {
|
|
372
|
-
return obj;
|
|
373
|
-
}
|
|
374
|
-
await connection.commitAsync();
|
|
375
|
-
if (obj.returningSql) {
|
|
376
|
-
const response = await connection.executeAsync(
|
|
377
|
-
obj.returningSql(),
|
|
378
|
-
rowIds,
|
|
379
|
-
{ resultSet: true }
|
|
380
|
-
);
|
|
381
|
-
obj.response = response.rows;
|
|
382
|
-
}
|
|
383
|
-
return obj;
|
|
384
|
-
});
|
|
385
|
-
};
|
|
386
|
-
|
|
387
|
-
/**
|
|
388
|
-
* @param stream
|
|
389
|
-
* @param {'string' | 'buffer'} type
|
|
390
|
-
*/
|
|
391
|
-
function readStream(stream, type) {
|
|
392
|
-
return new Promise((resolve, reject) => {
|
|
393
|
-
let data = type === 'string' ? '' : Buffer.alloc(0);
|
|
394
|
-
|
|
395
|
-
stream.on('error', function (err) {
|
|
396
|
-
reject(err);
|
|
397
|
-
});
|
|
398
|
-
stream.on('data', function (chunk) {
|
|
399
|
-
if (type === 'string') {
|
|
400
|
-
data += chunk;
|
|
401
|
-
} else {
|
|
402
|
-
data = Buffer.concat([data, chunk]);
|
|
403
|
-
}
|
|
404
|
-
});
|
|
405
|
-
stream.on('end', function () {
|
|
406
|
-
resolve(data);
|
|
407
|
-
});
|
|
408
|
-
});
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
// Process the response as returned from the query.
|
|
412
|
-
Client_Oracledb.prototype.processResponse = function (obj, runner) {
|
|
413
|
-
let response = obj.response;
|
|
414
|
-
const method = obj.method;
|
|
415
|
-
if (obj.output) {
|
|
416
|
-
return obj.output.call(runner, response);
|
|
417
|
-
}
|
|
418
|
-
switch (method) {
|
|
419
|
-
case 'select':
|
|
420
|
-
case 'pluck':
|
|
421
|
-
case 'first':
|
|
422
|
-
if (obj.method === 'pluck') {
|
|
423
|
-
response = map(response, obj.pluck);
|
|
424
|
-
}
|
|
425
|
-
return obj.method === 'first' ? response[0] : response;
|
|
426
|
-
case 'insert':
|
|
427
|
-
case 'del':
|
|
428
|
-
case 'update':
|
|
429
|
-
case 'counter':
|
|
430
|
-
if (obj.returning && !isEmpty(obj.returning)) {
|
|
431
|
-
if (obj.returning.length === 1 && obj.returning[0] !== '*') {
|
|
432
|
-
return flatten(map(response, values));
|
|
433
|
-
}
|
|
434
|
-
return response;
|
|
435
|
-
} else if (obj.rowsAffected !== undefined) {
|
|
436
|
-
return obj.rowsAffected;
|
|
437
|
-
} else {
|
|
438
|
-
return 1;
|
|
439
|
-
}
|
|
440
|
-
default:
|
|
441
|
-
return response;
|
|
442
|
-
}
|
|
443
|
-
};
|
|
444
|
-
|
|
445
|
-
const lobProcessing = function (stream) {
|
|
446
|
-
const oracledb = require('oracledb');
|
|
447
|
-
|
|
448
|
-
/**
|
|
449
|
-
* @type 'string' | 'buffer'
|
|
450
|
-
*/
|
|
451
|
-
let type;
|
|
452
|
-
|
|
453
|
-
if (stream.type) {
|
|
454
|
-
// v1.2-v4
|
|
455
|
-
if (stream.type === oracledb.BLOB) {
|
|
456
|
-
type = 'buffer';
|
|
457
|
-
} else if (stream.type === oracledb.CLOB) {
|
|
458
|
-
type = 'string';
|
|
459
|
-
}
|
|
460
|
-
} else if (stream.iLob) {
|
|
461
|
-
// v1
|
|
462
|
-
if (stream.iLob.type === oracledb.CLOB) {
|
|
463
|
-
type = 'string';
|
|
464
|
-
} else if (stream.iLob.type === oracledb.BLOB) {
|
|
465
|
-
type = 'buffer';
|
|
466
|
-
}
|
|
467
|
-
} else {
|
|
468
|
-
throw new Error('Unrecognized oracledb lob stream type');
|
|
469
|
-
}
|
|
470
|
-
if (type === 'string') {
|
|
471
|
-
stream.setEncoding('utf-8');
|
|
472
|
-
}
|
|
473
|
-
return readStream(stream, type);
|
|
474
|
-
};
|
|
475
|
-
|
|
476
|
-
class Oracledb_Formatter extends Oracle_Formatter {
|
|
477
|
-
// Checks whether a value is a function... if it is, we compile it
|
|
478
|
-
// otherwise we check whether it's a raw
|
|
479
|
-
parameter(value) {
|
|
480
|
-
if (typeof value === 'function') {
|
|
481
|
-
return this.outputQuery(this.compileCallback(value), true);
|
|
482
|
-
} else if (value instanceof BlobHelper) {
|
|
483
|
-
return 'EMPTY_BLOB()';
|
|
484
|
-
}
|
|
485
|
-
return this.unwrapRaw(value, true) || '?';
|
|
486
|
-
}
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
module.exports = Client_Oracledb;
|
|
1
|
+
// Oracledb Client
|
|
2
|
+
// -------
|
|
3
|
+
const each = require('lodash/each');
|
|
4
|
+
const flatten = require('lodash/flatten');
|
|
5
|
+
const isEmpty = require('lodash/isEmpty');
|
|
6
|
+
const map = require('lodash/map');
|
|
7
|
+
const values = require('lodash/values');
|
|
8
|
+
const QueryCompiler = require('./query/compiler');
|
|
9
|
+
const ColumnCompiler = require('./schema/columncompiler');
|
|
10
|
+
const { BlobHelper, ReturningHelper, isConnectionError } = require('./utils');
|
|
11
|
+
const stream = require('stream');
|
|
12
|
+
const { promisify, inherits } = require('util');
|
|
13
|
+
const Transaction = require('./transaction');
|
|
14
|
+
const Client_Oracle = require('../oracle');
|
|
15
|
+
const Oracle_Formatter = require('../oracle/formatter');
|
|
16
|
+
const { isString } = require('../../util/is');
|
|
17
|
+
|
|
18
|
+
function Client_Oracledb() {
|
|
19
|
+
Client_Oracle.apply(this, arguments);
|
|
20
|
+
// Node.js only have 4 background threads by default, oracledb needs one by connection
|
|
21
|
+
if (this.driver) {
|
|
22
|
+
process.env.UV_THREADPOOL_SIZE = process.env.UV_THREADPOOL_SIZE || 1;
|
|
23
|
+
process.env.UV_THREADPOOL_SIZE =
|
|
24
|
+
parseInt(process.env.UV_THREADPOOL_SIZE) + this.driver.poolMax;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
inherits(Client_Oracledb, Client_Oracle);
|
|
28
|
+
|
|
29
|
+
Client_Oracledb.prototype.driverName = 'oracledb';
|
|
30
|
+
|
|
31
|
+
Client_Oracledb.prototype._driver = function () {
|
|
32
|
+
const client = this;
|
|
33
|
+
const oracledb = require('oracledb');
|
|
34
|
+
client.fetchAsString = [];
|
|
35
|
+
if (this.config.fetchAsString && Array.isArray(this.config.fetchAsString)) {
|
|
36
|
+
this.config.fetchAsString.forEach(function (type) {
|
|
37
|
+
if (!isString(type)) return;
|
|
38
|
+
type = type.toUpperCase();
|
|
39
|
+
if (oracledb[type]) {
|
|
40
|
+
if (
|
|
41
|
+
type !== 'NUMBER' &&
|
|
42
|
+
type !== 'DATE' &&
|
|
43
|
+
type !== 'CLOB' &&
|
|
44
|
+
type !== 'BUFFER'
|
|
45
|
+
) {
|
|
46
|
+
this.logger.warn(
|
|
47
|
+
'Only "date", "number", "clob" and "buffer" are supported for fetchAsString'
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
client.fetchAsString.push(oracledb[type]);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
return oracledb;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
Client_Oracledb.prototype.queryCompiler = function () {
|
|
58
|
+
return new QueryCompiler(this, ...arguments);
|
|
59
|
+
};
|
|
60
|
+
Client_Oracledb.prototype.columnCompiler = function () {
|
|
61
|
+
return new ColumnCompiler(this, ...arguments);
|
|
62
|
+
};
|
|
63
|
+
Client_Oracledb.prototype.formatter = function () {
|
|
64
|
+
return new Oracledb_Formatter(this, ...arguments);
|
|
65
|
+
};
|
|
66
|
+
Client_Oracledb.prototype.transaction = function () {
|
|
67
|
+
return new Transaction(this, ...arguments);
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
Client_Oracledb.prototype.prepBindings = function (bindings) {
|
|
71
|
+
return map(bindings, (value) => {
|
|
72
|
+
if (value instanceof BlobHelper && this.driver) {
|
|
73
|
+
return { type: this.driver.BLOB, dir: this.driver.BIND_OUT };
|
|
74
|
+
// Returning helper always use ROWID as string
|
|
75
|
+
} else if (value instanceof ReturningHelper && this.driver) {
|
|
76
|
+
return { type: this.driver.STRING, dir: this.driver.BIND_OUT };
|
|
77
|
+
} else if (typeof value === 'boolean') {
|
|
78
|
+
return value ? 1 : 0;
|
|
79
|
+
}
|
|
80
|
+
return value;
|
|
81
|
+
});
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
function resolveConnectString(connectionSettings) {
|
|
85
|
+
if (connectionSettings.connectString) {
|
|
86
|
+
return connectionSettings.connectString;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (!connectionSettings.port) {
|
|
90
|
+
return connectionSettings.host + '/' + connectionSettings.database;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return (
|
|
94
|
+
connectionSettings.host +
|
|
95
|
+
':' +
|
|
96
|
+
connectionSettings.port +
|
|
97
|
+
'/' +
|
|
98
|
+
connectionSettings.database
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Get a raw connection, called by the `pool` whenever a new
|
|
103
|
+
// connection needs to be added to the pool.
|
|
104
|
+
Client_Oracledb.prototype.acquireRawConnection = function () {
|
|
105
|
+
const client = this;
|
|
106
|
+
const asyncConnection = new Promise(function (resolver, rejecter) {
|
|
107
|
+
// If external authentication don't have to worry about username/password and
|
|
108
|
+
// if not need to set the username and password
|
|
109
|
+
const oracleDbConfig = client.connectionSettings.externalAuth
|
|
110
|
+
? { externalAuth: client.connectionSettings.externalAuth }
|
|
111
|
+
: {
|
|
112
|
+
user: client.connectionSettings.user,
|
|
113
|
+
password: client.connectionSettings.password,
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
// In the case of external authentication connection string will be given
|
|
117
|
+
oracleDbConfig.connectString = resolveConnectString(
|
|
118
|
+
client.connectionSettings
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
if (client.connectionSettings.prefetchRowCount) {
|
|
122
|
+
oracleDbConfig.prefetchRows = client.connectionSettings.prefetchRowCount;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (client.connectionSettings.stmtCacheSize !== undefined) {
|
|
126
|
+
oracleDbConfig.stmtCacheSize = client.connectionSettings.stmtCacheSize;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
client.driver.fetchAsString = client.fetchAsString;
|
|
130
|
+
|
|
131
|
+
client.driver.getConnection(oracleDbConfig, function (err, connection) {
|
|
132
|
+
if (err) {
|
|
133
|
+
return rejecter(err);
|
|
134
|
+
}
|
|
135
|
+
connection.commitAsync = function () {
|
|
136
|
+
return new Promise((commitResolve, commitReject) => {
|
|
137
|
+
this.commit(function (err) {
|
|
138
|
+
if (err) {
|
|
139
|
+
return commitReject(err);
|
|
140
|
+
}
|
|
141
|
+
commitResolve();
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
};
|
|
145
|
+
connection.rollbackAsync = function () {
|
|
146
|
+
return new Promise((rollbackResolve, rollbackReject) => {
|
|
147
|
+
this.rollback(function (err) {
|
|
148
|
+
if (err) {
|
|
149
|
+
return rollbackReject(err);
|
|
150
|
+
}
|
|
151
|
+
rollbackResolve();
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
};
|
|
155
|
+
const fetchAsync = promisify(function (sql, bindParams, options, cb) {
|
|
156
|
+
options = options || {};
|
|
157
|
+
options.outFormat =
|
|
158
|
+
client.driver.OUT_FORMAT_OBJECT || client.driver.OBJECT;
|
|
159
|
+
if (!options.outFormat) {
|
|
160
|
+
throw new Error('not found oracledb.outFormat constants');
|
|
161
|
+
}
|
|
162
|
+
if (options.resultSet) {
|
|
163
|
+
connection.execute(
|
|
164
|
+
sql,
|
|
165
|
+
bindParams || [],
|
|
166
|
+
options,
|
|
167
|
+
function (err, result) {
|
|
168
|
+
if (err) {
|
|
169
|
+
if (isConnectionError(err)) {
|
|
170
|
+
connection.close().catch(function (err) {});
|
|
171
|
+
connection.__knex__disposed = err;
|
|
172
|
+
}
|
|
173
|
+
return cb(err);
|
|
174
|
+
}
|
|
175
|
+
const fetchResult = { rows: [], resultSet: result.resultSet };
|
|
176
|
+
const numRows = 100;
|
|
177
|
+
const fetchRowsFromRS = function (
|
|
178
|
+
connection,
|
|
179
|
+
resultSet,
|
|
180
|
+
numRows
|
|
181
|
+
) {
|
|
182
|
+
resultSet.getRows(numRows, function (err, rows) {
|
|
183
|
+
if (err) {
|
|
184
|
+
if (isConnectionError(err)) {
|
|
185
|
+
connection.close().catch(function (err) {});
|
|
186
|
+
connection.__knex__disposed = err;
|
|
187
|
+
}
|
|
188
|
+
resultSet.close(function () {
|
|
189
|
+
return cb(err);
|
|
190
|
+
});
|
|
191
|
+
} else if (rows.length === 0) {
|
|
192
|
+
return cb(null, fetchResult);
|
|
193
|
+
} else if (rows.length > 0) {
|
|
194
|
+
if (rows.length === numRows) {
|
|
195
|
+
fetchResult.rows = fetchResult.rows.concat(rows);
|
|
196
|
+
fetchRowsFromRS(connection, resultSet, numRows);
|
|
197
|
+
} else {
|
|
198
|
+
fetchResult.rows = fetchResult.rows.concat(rows);
|
|
199
|
+
return cb(null, fetchResult);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
};
|
|
204
|
+
fetchRowsFromRS(connection, result.resultSet, numRows);
|
|
205
|
+
}
|
|
206
|
+
);
|
|
207
|
+
} else {
|
|
208
|
+
connection.execute(
|
|
209
|
+
sql,
|
|
210
|
+
bindParams || [],
|
|
211
|
+
options,
|
|
212
|
+
function (err, result) {
|
|
213
|
+
if (err) {
|
|
214
|
+
// dispose the connection on connection error
|
|
215
|
+
if (isConnectionError(err)) {
|
|
216
|
+
connection.close().catch(function (err) {});
|
|
217
|
+
connection.__knex__disposed = err;
|
|
218
|
+
}
|
|
219
|
+
return cb(err);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
return cb(null, result);
|
|
223
|
+
}
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
connection.executeAsync = function (sql, bindParams, options) {
|
|
228
|
+
// Read all lob
|
|
229
|
+
return fetchAsync(sql, bindParams, options).then(async (results) => {
|
|
230
|
+
const closeResultSet = () => {
|
|
231
|
+
return results.resultSet
|
|
232
|
+
? promisify(results.resultSet.close).call(results.resultSet)
|
|
233
|
+
: Promise.resolve();
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
// Collect LOBs to read
|
|
237
|
+
const lobs = [];
|
|
238
|
+
if (results.rows) {
|
|
239
|
+
if (Array.isArray(results.rows)) {
|
|
240
|
+
for (let i = 0; i < results.rows.length; i++) {
|
|
241
|
+
// Iterate through the rows
|
|
242
|
+
const row = results.rows[i];
|
|
243
|
+
for (const column in row) {
|
|
244
|
+
if (row[column] instanceof stream.Readable) {
|
|
245
|
+
lobs.push({ index: i, key: column, stream: row[column] });
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
try {
|
|
253
|
+
for (const lob of lobs) {
|
|
254
|
+
// todo should be fetchAsString/fetchAsBuffer polyfill only
|
|
255
|
+
results.rows[lob.index][lob.key] = await lobProcessing(
|
|
256
|
+
lob.stream
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
} catch (e) {
|
|
260
|
+
await closeResultSet().catch(() => {});
|
|
261
|
+
|
|
262
|
+
throw e;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
await closeResultSet();
|
|
266
|
+
|
|
267
|
+
return results;
|
|
268
|
+
});
|
|
269
|
+
};
|
|
270
|
+
resolver(connection);
|
|
271
|
+
});
|
|
272
|
+
});
|
|
273
|
+
return asyncConnection;
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
// Used to explicitly close a connection, called internally by the pool
|
|
277
|
+
// when a connection times out or the pool is shutdown.
|
|
278
|
+
Client_Oracledb.prototype.destroyRawConnection = function (connection) {
|
|
279
|
+
return connection.release();
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
// Runs the query on the specified connection, providing the bindings
|
|
283
|
+
// and any other necessary prep work.
|
|
284
|
+
Client_Oracledb.prototype._query = function (connection, obj) {
|
|
285
|
+
if (!obj.sql) throw new Error('The query is empty');
|
|
286
|
+
|
|
287
|
+
const options = { autoCommit: false };
|
|
288
|
+
if (obj.method === 'select') {
|
|
289
|
+
options.resultSet = true;
|
|
290
|
+
}
|
|
291
|
+
return connection
|
|
292
|
+
.executeAsync(obj.sql, obj.bindings, options)
|
|
293
|
+
.then(async function (response) {
|
|
294
|
+
// Flatten outBinds
|
|
295
|
+
let outBinds = flatten(response.outBinds);
|
|
296
|
+
obj.response = response.rows || [];
|
|
297
|
+
obj.rowsAffected = response.rows
|
|
298
|
+
? response.rows.rowsAffected
|
|
299
|
+
: response.rowsAffected;
|
|
300
|
+
|
|
301
|
+
//added for outBind parameter
|
|
302
|
+
if (obj.method === 'raw' && outBinds.length > 0) {
|
|
303
|
+
return {
|
|
304
|
+
response: outBinds,
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
if (obj.method === 'update') {
|
|
309
|
+
const modifiedRowsCount = obj.rowsAffected.length || obj.rowsAffected;
|
|
310
|
+
const updatedObjOutBinding = [];
|
|
311
|
+
const updatedOutBinds = [];
|
|
312
|
+
const updateOutBinds = (i) =>
|
|
313
|
+
function (value, index) {
|
|
314
|
+
const OutBindsOffset = index * modifiedRowsCount;
|
|
315
|
+
updatedOutBinds.push(outBinds[i + OutBindsOffset]);
|
|
316
|
+
};
|
|
317
|
+
|
|
318
|
+
for (let i = 0; i < modifiedRowsCount; i++) {
|
|
319
|
+
updatedObjOutBinding.push(obj.outBinding[0]);
|
|
320
|
+
each(obj.outBinding[0], updateOutBinds(i));
|
|
321
|
+
}
|
|
322
|
+
outBinds = updatedOutBinds;
|
|
323
|
+
obj.outBinding = updatedObjOutBinding;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
if (!obj.returning && outBinds.length === 0) {
|
|
327
|
+
if (!connection.isTransaction) {
|
|
328
|
+
await connection.commitAsync();
|
|
329
|
+
}
|
|
330
|
+
return obj;
|
|
331
|
+
}
|
|
332
|
+
const rowIds = [];
|
|
333
|
+
let offset = 0;
|
|
334
|
+
|
|
335
|
+
for (let line = 0; line < obj.outBinding.length; line++) {
|
|
336
|
+
const ret = obj.outBinding[line];
|
|
337
|
+
|
|
338
|
+
offset =
|
|
339
|
+
offset +
|
|
340
|
+
(obj.outBinding[line - 1] ? obj.outBinding[line - 1].length : 0);
|
|
341
|
+
|
|
342
|
+
for (let index = 0; index < ret.length; index++) {
|
|
343
|
+
const out = ret[index];
|
|
344
|
+
|
|
345
|
+
await new Promise(function (bindResolver, bindRejecter) {
|
|
346
|
+
if (out instanceof BlobHelper) {
|
|
347
|
+
const blob = outBinds[index + offset];
|
|
348
|
+
if (out.returning) {
|
|
349
|
+
obj.response[line] = obj.response[line] || {};
|
|
350
|
+
obj.response[line][out.columnName] = out.value;
|
|
351
|
+
}
|
|
352
|
+
blob.on('error', function (err) {
|
|
353
|
+
bindRejecter(err);
|
|
354
|
+
});
|
|
355
|
+
blob.on('finish', function () {
|
|
356
|
+
bindResolver();
|
|
357
|
+
});
|
|
358
|
+
blob.write(out.value);
|
|
359
|
+
blob.end();
|
|
360
|
+
} else if (obj.outBinding[line][index] === 'ROWID') {
|
|
361
|
+
rowIds.push(outBinds[index + offset]);
|
|
362
|
+
bindResolver();
|
|
363
|
+
} else {
|
|
364
|
+
obj.response[line] = obj.response[line] || {};
|
|
365
|
+
obj.response[line][out] = outBinds[index + offset];
|
|
366
|
+
bindResolver();
|
|
367
|
+
}
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
if (connection.isTransaction) {
|
|
372
|
+
return obj;
|
|
373
|
+
}
|
|
374
|
+
await connection.commitAsync();
|
|
375
|
+
if (obj.returningSql) {
|
|
376
|
+
const response = await connection.executeAsync(
|
|
377
|
+
obj.returningSql(),
|
|
378
|
+
rowIds,
|
|
379
|
+
{ resultSet: true }
|
|
380
|
+
);
|
|
381
|
+
obj.response = response.rows;
|
|
382
|
+
}
|
|
383
|
+
return obj;
|
|
384
|
+
});
|
|
385
|
+
};
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* @param stream
|
|
389
|
+
* @param {'string' | 'buffer'} type
|
|
390
|
+
*/
|
|
391
|
+
function readStream(stream, type) {
|
|
392
|
+
return new Promise((resolve, reject) => {
|
|
393
|
+
let data = type === 'string' ? '' : Buffer.alloc(0);
|
|
394
|
+
|
|
395
|
+
stream.on('error', function (err) {
|
|
396
|
+
reject(err);
|
|
397
|
+
});
|
|
398
|
+
stream.on('data', function (chunk) {
|
|
399
|
+
if (type === 'string') {
|
|
400
|
+
data += chunk;
|
|
401
|
+
} else {
|
|
402
|
+
data = Buffer.concat([data, chunk]);
|
|
403
|
+
}
|
|
404
|
+
});
|
|
405
|
+
stream.on('end', function () {
|
|
406
|
+
resolve(data);
|
|
407
|
+
});
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// Process the response as returned from the query.
|
|
412
|
+
Client_Oracledb.prototype.processResponse = function (obj, runner) {
|
|
413
|
+
let response = obj.response;
|
|
414
|
+
const method = obj.method;
|
|
415
|
+
if (obj.output) {
|
|
416
|
+
return obj.output.call(runner, response);
|
|
417
|
+
}
|
|
418
|
+
switch (method) {
|
|
419
|
+
case 'select':
|
|
420
|
+
case 'pluck':
|
|
421
|
+
case 'first':
|
|
422
|
+
if (obj.method === 'pluck') {
|
|
423
|
+
response = map(response, obj.pluck);
|
|
424
|
+
}
|
|
425
|
+
return obj.method === 'first' ? response[0] : response;
|
|
426
|
+
case 'insert':
|
|
427
|
+
case 'del':
|
|
428
|
+
case 'update':
|
|
429
|
+
case 'counter':
|
|
430
|
+
if (obj.returning && !isEmpty(obj.returning)) {
|
|
431
|
+
if (obj.returning.length === 1 && obj.returning[0] !== '*') {
|
|
432
|
+
return flatten(map(response, values));
|
|
433
|
+
}
|
|
434
|
+
return response;
|
|
435
|
+
} else if (obj.rowsAffected !== undefined) {
|
|
436
|
+
return obj.rowsAffected;
|
|
437
|
+
} else {
|
|
438
|
+
return 1;
|
|
439
|
+
}
|
|
440
|
+
default:
|
|
441
|
+
return response;
|
|
442
|
+
}
|
|
443
|
+
};
|
|
444
|
+
|
|
445
|
+
const lobProcessing = function (stream) {
|
|
446
|
+
const oracledb = require('oracledb');
|
|
447
|
+
|
|
448
|
+
/**
|
|
449
|
+
* @type 'string' | 'buffer'
|
|
450
|
+
*/
|
|
451
|
+
let type;
|
|
452
|
+
|
|
453
|
+
if (stream.type) {
|
|
454
|
+
// v1.2-v4
|
|
455
|
+
if (stream.type === oracledb.BLOB) {
|
|
456
|
+
type = 'buffer';
|
|
457
|
+
} else if (stream.type === oracledb.CLOB) {
|
|
458
|
+
type = 'string';
|
|
459
|
+
}
|
|
460
|
+
} else if (stream.iLob) {
|
|
461
|
+
// v1
|
|
462
|
+
if (stream.iLob.type === oracledb.CLOB) {
|
|
463
|
+
type = 'string';
|
|
464
|
+
} else if (stream.iLob.type === oracledb.BLOB) {
|
|
465
|
+
type = 'buffer';
|
|
466
|
+
}
|
|
467
|
+
} else {
|
|
468
|
+
throw new Error('Unrecognized oracledb lob stream type');
|
|
469
|
+
}
|
|
470
|
+
if (type === 'string') {
|
|
471
|
+
stream.setEncoding('utf-8');
|
|
472
|
+
}
|
|
473
|
+
return readStream(stream, type);
|
|
474
|
+
};
|
|
475
|
+
|
|
476
|
+
class Oracledb_Formatter extends Oracle_Formatter {
|
|
477
|
+
// Checks whether a value is a function... if it is, we compile it
|
|
478
|
+
// otherwise we check whether it's a raw
|
|
479
|
+
parameter(value) {
|
|
480
|
+
if (typeof value === 'function') {
|
|
481
|
+
return this.outputQuery(this.compileCallback(value), true);
|
|
482
|
+
} else if (value instanceof BlobHelper) {
|
|
483
|
+
return 'EMPTY_BLOB()';
|
|
484
|
+
}
|
|
485
|
+
return this.unwrapRaw(value, true) || '?';
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
module.exports = Client_Oracledb;
|