oracledb 6.0.3 → 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/examples/example.js +0 -1
- package/lib/aqQueue.js +40 -26
- package/lib/connection.js +16 -4
- package/lib/dbObject.js +9 -0
- package/lib/errors.js +17 -13
- package/lib/impl/connection.js +9 -0
- package/lib/impl/resultset.js +7 -4
- package/lib/oracledb.js +26 -18
- package/lib/pool.js +7 -1
- package/lib/sodaCollection.js +12 -1
- package/lib/sodaOperation.js +16 -0
- package/lib/thin/connection.js +229 -182
- package/lib/thin/dbObject.js +4 -1
- package/lib/thin/pool.js +153 -68
- package/lib/thin/protocol/buffer.js +83 -64
- package/lib/thin/protocol/constants.js +3 -14
- package/lib/thin/protocol/encryptDecrypt.js +17 -17
- package/lib/thin/protocol/messages/auth.js +21 -23
- package/lib/thin/protocol/messages/base.js +29 -45
- package/lib/thin/protocol/messages/connectionCookie.js +76 -0
- package/lib/thin/protocol/messages/dataType.js +13 -9
- package/lib/thin/protocol/messages/execute.js +7 -7
- package/lib/thin/protocol/messages/index.js +2 -0
- package/lib/thin/protocol/messages/protocol.js +31 -20
- package/lib/thin/protocol/messages/withData.js +58 -47
- package/lib/thin/protocol/oson.js +17 -14
- package/lib/thin/protocol/packet.js +36 -14
- package/lib/thin/protocol/utils.js +2 -2
- package/lib/thin/resultSet.js +6 -6
- package/lib/thin/sqlnet/connStrategy.js +130 -5
- package/lib/thin/sqlnet/constants.js +2 -0
- package/lib/thin/sqlnet/ezConnectResolver.js +29 -61
- package/lib/thin/sqlnet/navNodes.js +34 -27
- package/lib/thin/sqlnet/networkSession.js +46 -47
- package/lib/thin/sqlnet/ntTcp.js +30 -14
- package/lib/thin/sqlnet/nvStrToNvPair.js +16 -16
- package/lib/thin/sqlnet/packet.js +10 -3
- package/lib/thin/sqlnet/paramParser.js +9 -9
- package/lib/thin/sqlnet/sessionAtts.js +4 -0
- package/lib/thin/statement.js +345 -113
- package/lib/thin/util.js +23 -86
- package/lib/transformer.js +3 -1
- package/lib/util.js +4 -13
- package/lib/version.js +2 -2
- package/package.json +1 -1
- package/build/Release/oracledb-6.0.3-darwin-x64.node +0 -0
- package/build/Release/oracledb-6.0.3-darwin-x64.node-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.0.3-js-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.0.3-linux-arm64.node +0 -0
- package/build/Release/oracledb-6.0.3-linux-arm64.node-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.0.3-linux-x64.node +0 -0
- package/build/Release/oracledb-6.0.3-linux-x64.node-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.0.3-win32-x64.node +0 -0
- package/build/Release/oracledb-6.0.3-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
|
-
let 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
|
-
let 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
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
if (bindByPos) {
|
|
74
|
-
outBinds = [];
|
|
75
|
-
} else {
|
|
76
|
-
outBinds = {};
|
|
77
|
-
}
|
|
70
|
+
function getOutBindValues(bindVars, pos) {
|
|
71
|
+
const bindByPos = (bindVars[0].name === undefined);
|
|
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
|
-
let numOutBinds = getNumOutBinds(bindVars);
|
|
97
|
-
if (numOutBinds === 0) {
|
|
98
|
-
return;
|
|
99
|
-
}
|
|
100
|
-
let 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
|
-
let 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
|
-
let bindVars = [];
|
|
155
|
-
for (const bindInfo of statement.bindInfoList) {
|
|
156
|
-
bindVars.push(bindInfo.bindVar);
|
|
157
|
-
}
|
|
158
|
-
return bindVars;
|
|
159
101
|
}
|
|
160
102
|
|
|
161
103
|
//---------------------------------------------------------------------------
|
|
@@ -167,8 +109,7 @@ function checkProxyUserValidity(userName) {
|
|
|
167
109
|
let schemaUser = '', proxyUser = '';
|
|
168
110
|
let quoteFound = false, openSquareBracketFound = false;
|
|
169
111
|
let lastQuoteFoundIndex = 0;
|
|
170
|
-
|
|
171
|
-
let result = {
|
|
112
|
+
const result = {
|
|
172
113
|
status : -1,
|
|
173
114
|
proxyUser : '',
|
|
174
115
|
schemaUser : ''
|
|
@@ -219,7 +160,7 @@ function checkProxyUserValidity(userName) {
|
|
|
219
160
|
// extract schema user
|
|
220
161
|
index = index + 1;
|
|
221
162
|
quoteFound = false;
|
|
222
|
-
schemaUserStartIndex = index;
|
|
163
|
+
const schemaUserStartIndex = index;
|
|
223
164
|
lastQuoteFoundIndex = 0;
|
|
224
165
|
while (index < userNameLength) {
|
|
225
166
|
// check for double quotes
|
|
@@ -299,12 +240,8 @@ function checkCredentials(params) {
|
|
|
299
240
|
|
|
300
241
|
module.exports = {
|
|
301
242
|
getMetadataMany,
|
|
302
|
-
cleanSql,
|
|
303
243
|
CLIENT_INFO,
|
|
304
|
-
getExecuteOutBinds,
|
|
305
|
-
getExecuteManyOutBinds,
|
|
306
244
|
getOutBinds,
|
|
307
|
-
getBindVars,
|
|
308
245
|
checkProxyUserValidity,
|
|
309
246
|
checkCredentials
|
|
310
247
|
};
|