oracledb 6.1.0 → 6.2.0
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/README.md +2 -2
- package/build/Release/oracledb-6.2.0-darwin-x64.node +0 -0
- package/build/Release/oracledb-6.2.0-darwin-x64.node-buildinfo.txt +1 -0
- package/build/Release/oracledb-6.2.0-js-buildinfo.txt +1 -0
- package/build/Release/oracledb-6.2.0-linux-arm64.node +0 -0
- package/build/Release/oracledb-6.2.0-linux-arm64.node-buildinfo.txt +1 -0
- package/build/Release/oracledb-6.2.0-linux-x64.node +0 -0
- package/build/Release/oracledb-6.2.0-linux-x64.node-buildinfo.txt +1 -0
- package/build/Release/oracledb-6.2.0-win32-x64.node +0 -0
- package/build/Release/oracledb-6.2.0-win32-x64.node-buildinfo.txt +1 -0
- package/examples/dbconfig.js +7 -14
- package/lib/connection.js +1 -1
- package/lib/dbObject.js +9 -0
- package/lib/errors.js +7 -7
- package/lib/oracledb.js +11 -6
- package/lib/sodaCollection.js +11 -0
- package/lib/sodaOperation.js +16 -0
- package/lib/thin/connection.js +138 -153
- package/lib/thin/dbObject.js +4 -1
- package/lib/thin/protocol/buffer.js +64 -63
- package/lib/thin/protocol/messages/base.js +7 -0
- package/lib/thin/protocol/messages/withData.js +9 -4
- package/lib/thin/protocol/oson.js +13 -10
- package/lib/thin/protocol/packet.js +6 -5
- package/lib/thin/protocol/utils.js +1 -1
- package/lib/thin/sqlnet/ezConnectResolver.js +10 -43
- package/lib/thin/sqlnet/navNodes.js +2 -2
- package/lib/thin/sqlnet/networkSession.js +13 -19
- package/lib/thin/sqlnet/packet.js +1 -1
- package/lib/thin/statement.js +345 -113
- package/lib/thin/util.js +20 -82
- package/lib/util.js +4 -0
- package/lib/version.js +1 -1
- package/package.json +1 -1
- package/build/Release/oracledb-6.1.0-darwin-x64.node +0 -0
- package/build/Release/oracledb-6.1.0-darwin-x64.node-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.1.0-js-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.1.0-linux-arm64.node +0 -0
- package/build/Release/oracledb-6.1.0-linux-arm64.node-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.1.0-linux-x64.node +0 -0
- package/build/Release/oracledb-6.1.0-linux-x64.node-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.1.0-win32-x64.node +0 -0
- package/build/Release/oracledb-6.1.0-win32-x64.node-buildinfo.txt +0 -1
package/lib/thin/statement.js
CHANGED
|
@@ -28,29 +28,6 @@
|
|
|
28
28
|
|
|
29
29
|
const { Buffer } = require('buffer');
|
|
30
30
|
const constants = require('../constants');
|
|
31
|
-
const thinUtil = require("./util.js");
|
|
32
|
-
|
|
33
|
-
/* eslint-disable no-useless-escape */
|
|
34
|
-
// Rules for named binds:
|
|
35
|
-
// 1. Quoted and non-quoted bind names are allowed.
|
|
36
|
-
// 2. Quoted binds can contain any characters.
|
|
37
|
-
// 3. Non-quoted binds must begin with an alphabet character.
|
|
38
|
-
// 4. Non-quoted binds can only contain alphanumeric characters, the underscore,
|
|
39
|
-
// the dollar sign and the pound sign.
|
|
40
|
-
// 5. Non-quoted binds cannot be Oracle Database Reserved Names
|
|
41
|
-
// (Server handles this case and returns an appropriate error)
|
|
42
|
-
const BIND_PATTERN = /(?<=:)\s*((?:".*?")|(?:[\p{L}][\p{L}\p{Nd}_\$#]*)|\p{Nd}+)/gu;
|
|
43
|
-
|
|
44
|
-
// pattern used for detecting a DML returning clause; bind variables in the
|
|
45
|
-
// first group are input variables; bind variables in the second group are
|
|
46
|
-
// output only variables
|
|
47
|
-
// assumes expressions/variables are seperated by delimiters space and comma
|
|
48
|
-
const DML_RETURNING_KEY = /(?<=\bRETURN(?:ING)?\b)/si;
|
|
49
|
-
const DML_RETURNING_INTO_KEY = /(?<=\bINTO\b)/gsi;
|
|
50
|
-
|
|
51
|
-
const SINGLE_LINE_COMMENT_PATTERN = /--.*/g;
|
|
52
|
-
const MULTI_LINE_COMMENT_PATTERN = /\/\*.*?\*\//sg;
|
|
53
|
-
const CONSTANT_STRING_PATTERN = /'.*?'/sg;
|
|
54
31
|
|
|
55
32
|
/**
|
|
56
33
|
* It is used to cache the metadata about bind information
|
|
@@ -77,6 +54,286 @@ class BindInfo {
|
|
|
77
54
|
*/
|
|
78
55
|
module.exports.BindInfo = BindInfo;
|
|
79
56
|
|
|
57
|
+
class Parser {
|
|
58
|
+
constructor() {
|
|
59
|
+
this.returningKeywordFound = false;
|
|
60
|
+
this.pos = 0;
|
|
61
|
+
this.maxPos = 0;
|
|
62
|
+
this.sqlData = "";
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Bind variables are identified as follows:
|
|
67
|
+
* - Quoted and non-quoted bind names are allowed.
|
|
68
|
+
* - Quoted bind names can contain any characters.
|
|
69
|
+
* - Non-quoted bind names must begin with an alphabetic character.
|
|
70
|
+
* - Non-quoted bind names can only contain alphanumeric characters, the
|
|
71
|
+
* underscore, the dollar sign and the pound sign.
|
|
72
|
+
* - Non-quoted bind names cannot be Oracle Database Reserved Names (this
|
|
73
|
+
* is left to the server to detect and return an appropriate error).
|
|
74
|
+
*/
|
|
75
|
+
_parseBindName(stmt) {
|
|
76
|
+
let quotedName = false;
|
|
77
|
+
let inBind = false;
|
|
78
|
+
let digitsOnly = false;
|
|
79
|
+
let startPos = 0;
|
|
80
|
+
let pos = this.pos + 1;
|
|
81
|
+
let bindName;
|
|
82
|
+
let ch;
|
|
83
|
+
|
|
84
|
+
while (pos <= this.maxPos) {
|
|
85
|
+
ch = this.sqlData[pos];
|
|
86
|
+
if (!inBind) {
|
|
87
|
+
if (/\p{space}/u.test(ch)) {
|
|
88
|
+
pos += 1;
|
|
89
|
+
continue;
|
|
90
|
+
} else if (ch === '"') {
|
|
91
|
+
quotedName = true;
|
|
92
|
+
} else if (/\p{N}/u.test(ch)) {
|
|
93
|
+
digitsOnly = true;
|
|
94
|
+
} else if (!/\p{Alpha}/u.test(ch)) {
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
inBind = true;
|
|
98
|
+
startPos = pos;
|
|
99
|
+
} else if (digitsOnly && !(/\p{N}/u.test(ch))) {
|
|
100
|
+
this.pos = pos - 1;
|
|
101
|
+
break;
|
|
102
|
+
} else if (quotedName && ch === '"') {
|
|
103
|
+
this.pos = pos;
|
|
104
|
+
break;
|
|
105
|
+
} else if (!digitsOnly && !quotedName
|
|
106
|
+
&& !(/[\p{L}\p{N}]/u.test(ch))
|
|
107
|
+
&& !['$', '_', '#'].includes(ch)) {
|
|
108
|
+
this.pos = pos - 1;
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
pos += 1;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (inBind) {
|
|
115
|
+
if (quotedName) {
|
|
116
|
+
bindName = stmt.sql.substring(startPos + 1, pos);
|
|
117
|
+
} else if (digitsOnly) {
|
|
118
|
+
bindName = stmt.sql.substring(startPos, pos);
|
|
119
|
+
} else {
|
|
120
|
+
bindName = stmt.sql.substring(startPos, pos).toUpperCase();
|
|
121
|
+
}
|
|
122
|
+
stmt._addBind(bindName);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Multiple line comments consist of the characters /* followed by all
|
|
128
|
+
* characters up until * followed by /. This method is called when the first
|
|
129
|
+
* slash is detected and checks for the subsequent asterisk. If found,
|
|
130
|
+
* the comment is traversed and the current position is updated; otherwise,
|
|
131
|
+
* the current position is left untouched.
|
|
132
|
+
*/
|
|
133
|
+
_parseMultiLineComment() {
|
|
134
|
+
let inComment = false;
|
|
135
|
+
let exitingComment = false;
|
|
136
|
+
let pos = this.pos + 1;
|
|
137
|
+
let ch;
|
|
138
|
+
while (pos <= this.maxPos) {
|
|
139
|
+
ch = this.sqlData[pos];
|
|
140
|
+
if (!inComment) {
|
|
141
|
+
if (ch !== '*') {
|
|
142
|
+
break;
|
|
143
|
+
}
|
|
144
|
+
inComment = true;
|
|
145
|
+
} else if (!exitingComment && ch === '*') {
|
|
146
|
+
exitingComment = true;
|
|
147
|
+
} else if (exitingComment) {
|
|
148
|
+
if (ch === '/') {
|
|
149
|
+
this.pos = pos;
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
152
|
+
exitingComment = false;
|
|
153
|
+
}
|
|
154
|
+
pos += 1;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/** Parses a q-string which consists of the characters "q" and a single
|
|
159
|
+
* quote followed by a start separator, any text that does not contain the
|
|
160
|
+
* end seprator and the end separator and ending quote. The following are
|
|
161
|
+
* examples that demonstrate this:
|
|
162
|
+
* - q'[...]'
|
|
163
|
+
* - q'{...}'
|
|
164
|
+
* - q'<...>'
|
|
165
|
+
* - q'(...)'
|
|
166
|
+
* - q'?...?' (where ? is any character)
|
|
167
|
+
*/
|
|
168
|
+
_parseQstring() {
|
|
169
|
+
let exitingQstring = false;
|
|
170
|
+
let inQstring = false;
|
|
171
|
+
let sep;
|
|
172
|
+
let ch;
|
|
173
|
+
|
|
174
|
+
this.pos += 1;
|
|
175
|
+
|
|
176
|
+
while (this.pos <= this.maxPos) {
|
|
177
|
+
ch = this.sqlData[this.pos];
|
|
178
|
+
if (!inQstring) {
|
|
179
|
+
if (ch === '[') {
|
|
180
|
+
sep = ']';
|
|
181
|
+
} else if (ch === '{') {
|
|
182
|
+
sep = '}';
|
|
183
|
+
} else if (ch === '(') {
|
|
184
|
+
sep = ')';
|
|
185
|
+
} else if (ch === '<') {
|
|
186
|
+
sep = '>';
|
|
187
|
+
} else {
|
|
188
|
+
sep = ch;
|
|
189
|
+
}
|
|
190
|
+
inQstring = true;
|
|
191
|
+
} else if (!exitingQstring && ch === sep) {
|
|
192
|
+
exitingQstring = true;
|
|
193
|
+
} else if (exitingQstring) {
|
|
194
|
+
if (ch === "'") {
|
|
195
|
+
break;
|
|
196
|
+
} else if (ch !== sep) {
|
|
197
|
+
exitingQstring = false;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
this.pos += 1;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Parses a quoted string with the given separator. All characters until
|
|
206
|
+
* the separate is detected are discarded.
|
|
207
|
+
*/
|
|
208
|
+
_parseQuotedString(sep) {
|
|
209
|
+
let ch;
|
|
210
|
+
this.pos += 1;
|
|
211
|
+
while (this.pos <= this.maxPos) {
|
|
212
|
+
ch = this.sqlData[this.pos];
|
|
213
|
+
if (ch === sep) {
|
|
214
|
+
break;
|
|
215
|
+
}
|
|
216
|
+
this.pos += 1;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Single line comments consist of two dashes and all characters up to the
|
|
222
|
+
* next line break. This method is called when the first dash is detected
|
|
223
|
+
* and checks for the subsequent dash. If found, the single line comment
|
|
224
|
+
* is traversed and the current position is updated; otherwise, the
|
|
225
|
+
* current position is left untouched.
|
|
226
|
+
*/
|
|
227
|
+
_parseSingleLineComment() {
|
|
228
|
+
let inComment = false;
|
|
229
|
+
let pos = this.pos + 1;
|
|
230
|
+
let ch;
|
|
231
|
+
|
|
232
|
+
while (pos <= this.maxPos) {
|
|
233
|
+
ch = this.sqlData[pos];
|
|
234
|
+
if (!inComment) {
|
|
235
|
+
if (ch !== '-') {
|
|
236
|
+
break;
|
|
237
|
+
}
|
|
238
|
+
inComment = true;
|
|
239
|
+
} else if (ch === '\n') {
|
|
240
|
+
this.pos = pos;
|
|
241
|
+
break;
|
|
242
|
+
}
|
|
243
|
+
pos += 1;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Parses the SQL stored in the statement in order to determine the
|
|
249
|
+
* keyword that identifies the type of SQL being executed as well as a
|
|
250
|
+
* list of bind variable names. A check is also made for DML returning
|
|
251
|
+
* statements since the bind variables following the "INTO" keyword are
|
|
252
|
+
* treated differently from other bind variables.
|
|
253
|
+
*/
|
|
254
|
+
parse(stmt) {
|
|
255
|
+
let initialKeywordFound = false;
|
|
256
|
+
let lastWasString = false;
|
|
257
|
+
let ch, lastCh = '', alphaStartCh = '';
|
|
258
|
+
let alphaStartPos = 0, alphaLen;
|
|
259
|
+
let isAlpha, lastWasAlpha = false;
|
|
260
|
+
let keyword;
|
|
261
|
+
|
|
262
|
+
// initialization
|
|
263
|
+
this.pos = 0;
|
|
264
|
+
this.maxPos = stmt.sql.length - 1;
|
|
265
|
+
this.sqlData = stmt.sql;
|
|
266
|
+
|
|
267
|
+
// scan all the characters in the string
|
|
268
|
+
while (this.pos <= this.maxPos) {
|
|
269
|
+
ch = this.sqlData[this.pos];
|
|
270
|
+
// look for certain keywords (initial keyword and the ones for
|
|
271
|
+
// detecting DML returning statements
|
|
272
|
+
isAlpha = /\p{L}/u.test(ch);
|
|
273
|
+
if (isAlpha && !lastWasAlpha) {
|
|
274
|
+
alphaStartPos = this.pos;
|
|
275
|
+
alphaStartCh = ch;
|
|
276
|
+
} else if (!isAlpha && lastWasAlpha) {
|
|
277
|
+
alphaLen = this.pos - alphaStartPos;
|
|
278
|
+
if (!initialKeywordFound) {
|
|
279
|
+
keyword = stmt.sql.substring(alphaStartPos, this.pos).toUpperCase();
|
|
280
|
+
stmt._determineStatementType(keyword);
|
|
281
|
+
initialKeywordFound = true;
|
|
282
|
+
if (stmt.isDdl) {
|
|
283
|
+
break;
|
|
284
|
+
}
|
|
285
|
+
} else if (stmt.isDml && !this.returningKeywordFound
|
|
286
|
+
&& (alphaLen === 9 || alphaLen === 6)
|
|
287
|
+
&& ['r', 'R'].includes(alphaStartCh)) {
|
|
288
|
+
keyword = stmt.sql.substring(alphaStartPos, this.pos).toUpperCase();
|
|
289
|
+
if (['RETURNING', 'RETURN'].includes(keyword)) {
|
|
290
|
+
this.returningKeywordFound = true;
|
|
291
|
+
}
|
|
292
|
+
} else if (this.returningKeywordFound && alphaLen === 4
|
|
293
|
+
&& ['i', 'I'].includes(alphaStartCh)) {
|
|
294
|
+
keyword = stmt.sql.substring(alphaStartPos, this.pos).toUpperCase();
|
|
295
|
+
if (keyword === 'INTO') {
|
|
296
|
+
stmt.isReturning = true;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// need to keep track of whether the last token parsed was a string
|
|
302
|
+
// (excluding whitespace) as if the last token parsed was a string
|
|
303
|
+
// a following colon is not a bind variable but a part of the JSON
|
|
304
|
+
// constant syntax
|
|
305
|
+
if (ch === "'") {
|
|
306
|
+
lastWasString = true;
|
|
307
|
+
if (['q', 'Q'].includes(lastCh)) {
|
|
308
|
+
this._parseQstring();
|
|
309
|
+
} else {
|
|
310
|
+
this._parseQuotedString(ch);
|
|
311
|
+
}
|
|
312
|
+
} else if (!(/\p{space}/u.test(ch))) {
|
|
313
|
+
if (ch === '-') {
|
|
314
|
+
this._parseSingleLineComment();
|
|
315
|
+
} else if (ch === '/') {
|
|
316
|
+
this._parseMultiLineComment();
|
|
317
|
+
} else if (ch === '"') {
|
|
318
|
+
this._parseQuotedString(ch);
|
|
319
|
+
} else if (ch === ':' && !lastWasString) {
|
|
320
|
+
this._parseBindName(stmt);
|
|
321
|
+
}
|
|
322
|
+
lastWasString = false;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
this.pos += 1;
|
|
326
|
+
lastWasAlpha = isAlpha;
|
|
327
|
+
lastCh = ch;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// if only a single word is found in sql, e.g. in case of commit/rollback
|
|
331
|
+
if (!initialKeywordFound) {
|
|
332
|
+
stmt._determineStatementType(stmt.sql.toUpperCase());
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
80
337
|
class Statement {
|
|
81
338
|
constructor() {
|
|
82
339
|
this.sql = "";
|
|
@@ -143,54 +400,72 @@ class Statement {
|
|
|
143
400
|
// Determine the type of the SQL statement by examining the first keyword
|
|
144
401
|
// found in the statement
|
|
145
402
|
//---------------------------------------------------------------------------
|
|
146
|
-
_determineStatementType(
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
if (tokens.length > 0) {
|
|
150
|
-
const sqlKeyword = tokens[0].toUpperCase();
|
|
151
|
-
if (["DECLARE", "BEGIN", "CALL"].includes(sqlKeyword)) {
|
|
403
|
+
_determineStatementType(sqlKeyword) {
|
|
404
|
+
switch (sqlKeyword) {
|
|
405
|
+
case 'DECLARE':
|
|
152
406
|
this.isPlSql = true;
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
407
|
+
this.statementType = constants.STMT_TYPE_DECLARE;
|
|
408
|
+
break;
|
|
409
|
+
case 'CALL':
|
|
410
|
+
this.isPlSql = true;
|
|
411
|
+
this.statementType = constants.STMT_TYPE_CALL;
|
|
412
|
+
break;
|
|
413
|
+
case 'BEGIN':
|
|
414
|
+
this.isPlSql = true;
|
|
415
|
+
this.statementType = constants.STMT_TYPE_BEGIN;
|
|
416
|
+
break;
|
|
417
|
+
case 'SELECT':
|
|
161
418
|
this.isQuery = true;
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
419
|
+
this.statementType = constants.STMT_TYPE_SELECT;
|
|
420
|
+
break;
|
|
421
|
+
case 'WITH':
|
|
422
|
+
this.isQuery = true;
|
|
423
|
+
break;
|
|
424
|
+
case 'INSERT':
|
|
166
425
|
this.isDml = true;
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
426
|
+
this.statementType = constants.STMT_TYPE_INSERT;
|
|
427
|
+
break;
|
|
428
|
+
case 'UPDATE':
|
|
429
|
+
this.isDml = true;
|
|
430
|
+
this.statementType = constants.STMT_TYPE_UPDATE;
|
|
431
|
+
break;
|
|
432
|
+
case 'DELETE':
|
|
433
|
+
this.isDml = true;
|
|
434
|
+
this.statementType = constants.STMT_TYPE_DELETE;
|
|
435
|
+
break;
|
|
436
|
+
case 'MERGE':
|
|
437
|
+
this.isDml = true;
|
|
438
|
+
this.statementType = constants.STMT_TYPE_MERGE;
|
|
439
|
+
break;
|
|
440
|
+
case 'ALTER':
|
|
177
441
|
this.isDdl = true;
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
442
|
+
this.statementType = constants.STMT_TYPE_ALTER;
|
|
443
|
+
break;
|
|
444
|
+
case 'CREATE':
|
|
445
|
+
this.isDdl = true;
|
|
446
|
+
this.statementType = constants.STMT_TYPE_CREATE;
|
|
447
|
+
break;
|
|
448
|
+
case 'DROP':
|
|
449
|
+
this.isDdl = true;
|
|
450
|
+
this.statementType = constants.STMT_TYPE_DROP;
|
|
451
|
+
break;
|
|
452
|
+
case 'ANALYZE':
|
|
453
|
+
case 'AUDIT':
|
|
454
|
+
case 'COMMENT':
|
|
455
|
+
case 'GRANT':
|
|
456
|
+
case 'REVOKE':
|
|
457
|
+
case 'TRUNCATE':
|
|
458
|
+
this.isDdl = true;
|
|
459
|
+
break;
|
|
460
|
+
case 'COMMIT':
|
|
186
461
|
this.statementType = constants.STMT_TYPE_COMMIT;
|
|
187
|
-
|
|
462
|
+
break;
|
|
463
|
+
case 'ROLLBACK':
|
|
188
464
|
this.statementType = constants.STMT_TYPE_ROLLBACK;
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
} else {
|
|
465
|
+
break;
|
|
466
|
+
default:
|
|
192
467
|
this.statementType = constants.STMT_TYPE_UNKNOWN;
|
|
193
|
-
|
|
468
|
+
break;
|
|
194
469
|
}
|
|
195
470
|
}
|
|
196
471
|
|
|
@@ -205,40 +480,8 @@ class Statement {
|
|
|
205
480
|
this.sql = sql;
|
|
206
481
|
this.sqlBytes = Buffer.from(this.sql, 'utf8');
|
|
207
482
|
this.sqlLength = this.sqlBytes.length;
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
sql = sql.replace(SINGLE_LINE_COMMENT_PATTERN, "");
|
|
211
|
-
sql = sql.replace(MULTI_LINE_COMMENT_PATTERN, "");
|
|
212
|
-
this._determineStatementType(sql);
|
|
213
|
-
let returningSql;
|
|
214
|
-
if (this.isQuery || this.isDml || this.isPlSql) {
|
|
215
|
-
let inputSql = sql;
|
|
216
|
-
if (this.isDml) {
|
|
217
|
-
/*
|
|
218
|
-
* get starting index after DML_RETURNING_KEY from begining of sql and starting index
|
|
219
|
-
* after DML_RETURNING_INTO_KEY from the end of sql
|
|
220
|
-
*/
|
|
221
|
-
let result;
|
|
222
|
-
let intoKey = -1;
|
|
223
|
-
const retKey = sql.search(DML_RETURNING_KEY);
|
|
224
|
-
const intoRegex = DML_RETURNING_INTO_KEY;
|
|
225
|
-
// simulate lastInfdexOf with intoRegex input
|
|
226
|
-
while ((result = intoRegex.exec(sql.slice(retKey))) != null) {
|
|
227
|
-
intoKey = result.index;
|
|
228
|
-
intoRegex.lastIndex = result.index + 1;
|
|
229
|
-
}
|
|
230
|
-
if (retKey > -1 && intoKey > -1) {
|
|
231
|
-
intoKey = retKey + intoKey;
|
|
232
|
-
inputSql = sql.slice(0, intoKey);
|
|
233
|
-
returningSql = sql.slice(intoKey);
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
this._addBinds(inputSql, false);
|
|
237
|
-
if (returningSql) {
|
|
238
|
-
this.isReturning = true;
|
|
239
|
-
this._addBinds(returningSql, true);
|
|
240
|
-
}
|
|
241
|
-
}
|
|
483
|
+
const parser = new Parser();
|
|
484
|
+
parser.parse(this);
|
|
242
485
|
}
|
|
243
486
|
|
|
244
487
|
//---------------------------------------------------------------------------
|
|
@@ -247,27 +490,16 @@ class Statement {
|
|
|
247
490
|
// Add bind information to the statement by examining the passed SQL for
|
|
248
491
|
// bind variable names.
|
|
249
492
|
//---------------------------------------------------------------------------
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
regexMatchArray.forEach(element => {
|
|
254
|
-
if (element[0].startsWith('"') && element[0].endsWith('"')) {
|
|
255
|
-
name = element[0].substring(1, element[0].length - 1);
|
|
256
|
-
} else {
|
|
257
|
-
name = element[0].trim().toUpperCase();
|
|
258
|
-
}
|
|
259
|
-
if (this.isPlSql && this.bindInfoDict.has(name)) {
|
|
260
|
-
return;
|
|
261
|
-
}
|
|
262
|
-
const info = new BindInfo(name, isReturnBind);
|
|
493
|
+
_addBind(name) {
|
|
494
|
+
if (!this.isPlSql || !this.bindInfoDict.has(name)) {
|
|
495
|
+
const info = new BindInfo(name, this.isReturning);
|
|
263
496
|
this.bindInfoList.push(info);
|
|
264
|
-
|
|
265
497
|
if (this.bindInfoDict.has(info.bindName)) {
|
|
266
498
|
this.bindInfoDict.get(info.bindName).push(info);
|
|
267
499
|
} else {
|
|
268
500
|
this.bindInfoDict.set(info.bindName, [info]);
|
|
269
501
|
}
|
|
270
|
-
}
|
|
502
|
+
}
|
|
271
503
|
}
|
|
272
504
|
|
|
273
505
|
//---------------------------------------------------------------------------
|
package/lib/thin/util.js
CHANGED
|
@@ -63,99 +63,41 @@ function getMetadataMany(vars) {
|
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
//---------------------------------------------------------------------------
|
|
66
|
-
//
|
|
66
|
+
// getOutBindValues(sql)
|
|
67
67
|
//
|
|
68
|
-
//
|
|
68
|
+
// Return the values for the out binds at the given position (row).
|
|
69
69
|
//---------------------------------------------------------------------------
|
|
70
|
-
function
|
|
70
|
+
function getOutBindValues(bindVars, pos) {
|
|
71
71
|
const bindByPos = (bindVars[0].name === undefined);
|
|
72
|
-
|
|
73
|
-
if (bindByPos) {
|
|
74
|
-
outBinds = [];
|
|
75
|
-
} else {
|
|
76
|
-
outBinds = {};
|
|
77
|
-
}
|
|
72
|
+
const outBindValues = (bindByPos) ? [] : {};
|
|
78
73
|
for (let i = 0; i < bindVars.length; i++) {
|
|
79
|
-
if (bindVars[i].dir === constants.BIND_IN)
|
|
80
|
-
continue;
|
|
81
74
|
if (bindByPos) {
|
|
82
|
-
|
|
75
|
+
outBindValues.push(bindVars[i].values[pos]);
|
|
83
76
|
} else {
|
|
84
|
-
|
|
77
|
+
outBindValues[bindVars[i].name] = bindVars[i].values[pos];
|
|
85
78
|
}
|
|
86
79
|
}
|
|
87
|
-
return
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
//---------------------------------------------------------------------------
|
|
91
|
-
// getExecuteManyOutBinds(sql)
|
|
92
|
-
//
|
|
93
|
-
// Get the outBinds for the sql when doing an executeMany call
|
|
94
|
-
//---------------------------------------------------------------------------
|
|
95
|
-
function getExecuteManyOutBinds(bindVars, numIters) {
|
|
96
|
-
const numOutBinds = getNumOutBinds(bindVars);
|
|
97
|
-
if (numOutBinds === 0) {
|
|
98
|
-
return;
|
|
99
|
-
}
|
|
100
|
-
const outBinds = new Array(numIters).fill(null);
|
|
101
|
-
for (let i = 0; i < numIters; i++) {
|
|
102
|
-
outBinds[i] = getOutBinds(bindVars, i);
|
|
103
|
-
}
|
|
104
|
-
return outBinds;
|
|
80
|
+
return outBindValues;
|
|
105
81
|
}
|
|
106
82
|
|
|
107
83
|
//---------------------------------------------------------------------------
|
|
108
|
-
//
|
|
84
|
+
// getOutBinds()
|
|
109
85
|
//
|
|
110
|
-
//
|
|
86
|
+
// Return the out binds for the given statement.
|
|
111
87
|
//---------------------------------------------------------------------------
|
|
112
|
-
function
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
88
|
+
function getOutBinds(statement, numIters, executeManyFlag) {
|
|
89
|
+
const bindVars = statement.bindInfoList.map(i => i.bindVar);
|
|
90
|
+
const outBinds = bindVars.filter(v => v.dir !== constants.BIND_IN);
|
|
91
|
+
if (outBinds.length > 0) {
|
|
92
|
+
if (executeManyFlag) {
|
|
93
|
+
const outBindValues = new Array(numIters);
|
|
94
|
+
for (let i = 0; i < numIters; i++) {
|
|
95
|
+
outBindValues[i] = getOutBindValues(outBinds, i);
|
|
96
|
+
}
|
|
97
|
+
return outBindValues;
|
|
117
98
|
}
|
|
99
|
+
return getOutBindValues(outBinds, 0);
|
|
118
100
|
}
|
|
119
|
-
return numOutBinds;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
//---------------------------------------------------------------------------
|
|
123
|
-
// getExecuteOutBinds(sql)
|
|
124
|
-
//
|
|
125
|
-
// Get the outBinds for the sql when doing an execute call
|
|
126
|
-
//---------------------------------------------------------------------------
|
|
127
|
-
function getExecuteOutBinds(bindVars) {
|
|
128
|
-
const numOutBinds = getNumOutBinds(bindVars);
|
|
129
|
-
if (numOutBinds === 0) {
|
|
130
|
-
return;
|
|
131
|
-
}
|
|
132
|
-
return getOutBinds(bindVars, 0);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
//---------------------------------------------------------------------------
|
|
136
|
-
// cleanSql(sql)
|
|
137
|
-
//
|
|
138
|
-
// Sanitize the sql to remove comment and redundant information
|
|
139
|
-
//---------------------------------------------------------------------------
|
|
140
|
-
function cleanSql(sql) {
|
|
141
|
-
sql = sql.trim();
|
|
142
|
-
sql = sql.replace(/\--.*(\n|$)/g, ""); // eslint-disable-line
|
|
143
|
-
sql = sql.replace(/\/\\*[\S\n ]+\\*\//g, "");
|
|
144
|
-
sql = sql.replace(/\s+/g, " ");
|
|
145
|
-
return sql;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
//---------------------------------------------------------------------------
|
|
149
|
-
// getOutBinds(sql)
|
|
150
|
-
//
|
|
151
|
-
// Get the bind variables from the bindInfoList of the statement object
|
|
152
|
-
//---------------------------------------------------------------------------
|
|
153
|
-
function getBindVars(statement) {
|
|
154
|
-
const bindVars = [];
|
|
155
|
-
for (const bindInfo of statement.bindInfoList) {
|
|
156
|
-
bindVars.push(bindInfo.bindVar);
|
|
157
|
-
}
|
|
158
|
-
return bindVars;
|
|
159
101
|
}
|
|
160
102
|
|
|
161
103
|
//---------------------------------------------------------------------------
|
|
@@ -298,12 +240,8 @@ function checkCredentials(params) {
|
|
|
298
240
|
|
|
299
241
|
module.exports = {
|
|
300
242
|
getMetadataMany,
|
|
301
|
-
cleanSql,
|
|
302
243
|
CLIENT_INFO,
|
|
303
|
-
getExecuteOutBinds,
|
|
304
|
-
getExecuteManyOutBinds,
|
|
305
244
|
getOutBinds,
|
|
306
|
-
getBindVars,
|
|
307
245
|
checkProxyUserValidity,
|
|
308
246
|
checkCredentials
|
|
309
247
|
};
|
package/lib/util.js
CHANGED
|
@@ -47,6 +47,9 @@ const RELEASE_DIR = 'build/Release';
|
|
|
47
47
|
// The default node-oracledb add-on binary filename for this Node.js
|
|
48
48
|
const BINARY_FILE = 'oracledb-' + PACKAGE_JSON_VERSION + '-' + process.platform + '-' + process.arch + '.node';
|
|
49
49
|
|
|
50
|
+
// The node-oracledb binary filename when it is built from source
|
|
51
|
+
const BUILD_FILE = 'oracledb.node';
|
|
52
|
+
|
|
50
53
|
// Staging directory used by maintainers building the npm package
|
|
51
54
|
const STAGING_DIR = 'package/Staging';
|
|
52
55
|
|
|
@@ -320,6 +323,7 @@ function addTypeProperties(obj, attrName) {
|
|
|
320
323
|
// define exports
|
|
321
324
|
module.exports = {
|
|
322
325
|
BINARY_FILE,
|
|
326
|
+
BUILD_FILE,
|
|
323
327
|
PACKAGE_JSON_VERSION,
|
|
324
328
|
RELEASE_DIR,
|
|
325
329
|
STAGING_DIR,
|
package/lib/version.js
CHANGED
package/package.json
CHANGED
|
Binary file
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
oracledb-6.1.0-darwin-x64.node v18.17.1 98df02823e1fc31b0e57044cd1fb2358dfc620ed 20785f251426f274f4216369b9259908a103384d Mon, 21 Aug 2023 05:58:15 GMT
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
98df02823e1fc31b0e57044cd1fb2358dfc620ed
|
|
Binary file
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
oracledb-6.1.0-linux-arm64.node v18.15.0 98df02823e1fc31b0e57044cd1fb2358dfc620ed 20785f251426f274f4216369b9259908a103384d Mon, 21 Aug 2023 07:05:34 GMT
|