oracledb 5.5.0 → 6.0.1
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 +1 -1875
- package/LICENSE.txt +8 -222
- package/NOTICE.txt +1 -1
- package/README.md +38 -30
- package/SECURITY.md +38 -0
- package/build/Release/oracledb-6.0.1-darwin-x64.node +0 -0
- package/build/Release/oracledb-6.0.1-darwin-x64.node-buildinfo.txt +1 -0
- package/build/Release/oracledb-6.0.1-js-buildinfo.txt +1 -0
- package/build/Release/oracledb-6.0.1-linux-arm64.node +0 -0
- package/build/Release/oracledb-6.0.1-linux-arm64.node-buildinfo.txt +1 -0
- package/build/Release/oracledb-6.0.1-linux-x64.node +0 -0
- package/build/Release/oracledb-6.0.1-linux-x64.node-buildinfo.txt +1 -0
- package/build/Release/oracledb-6.0.1-win32-x64.node +0 -0
- package/build/Release/oracledb-6.0.1-win32-x64.node-buildinfo.txt +1 -0
- package/examples/README.md +113 -0
- package/examples/dbconfig.js +100 -0
- package/examples/example.js +156 -0
- package/index.js +26 -0
- package/lib/aqDeqOptions.js +148 -8
- package/lib/aqEnqOptions.js +59 -7
- package/lib/aqMessage.js +118 -7
- package/lib/aqQueue.js +243 -53
- package/lib/connection.js +1326 -465
- package/lib/constants.js +203 -0
- package/lib/dbObject.js +346 -32
- package/lib/errors.js +785 -0
- package/lib/impl/aqDeqOptions.js +197 -0
- package/lib/impl/aqEnqOptions.js +89 -0
- package/lib/impl/aqMessage.js +134 -0
- package/lib/impl/aqQueue.js +81 -0
- package/lib/impl/connection.js +529 -0
- package/lib/impl/dbObject.js +159 -0
- package/lib/impl/index.js +59 -0
- package/lib/impl/lob.js +85 -0
- package/lib/impl/pool.js +195 -0
- package/lib/impl/resultset.js +223 -0
- package/lib/impl/sodaCollection.js +174 -0
- package/lib/impl/sodaDatabase.js +81 -0
- package/lib/impl/sodaDocCursor.js +63 -0
- package/lib/impl/sodaDocument.js +98 -0
- package/lib/impl/sodaOperation.js +109 -0
- package/lib/lob.js +157 -68
- package/lib/oracledb.js +1047 -345
- package/lib/pool.js +654 -465
- package/lib/poolStatistics.js +24 -9
- package/lib/queryStream.js +16 -8
- package/lib/resultset.js +291 -183
- package/lib/settings.js +191 -0
- package/lib/sodaCollection.js +214 -201
- package/lib/sodaDatabase.js +108 -71
- package/lib/sodaDocCursor.js +44 -32
- package/lib/sodaDocument.js +76 -14
- package/lib/sodaOperation.js +131 -118
- package/lib/thin/connection.js +1043 -0
- package/lib/thin/dbObject.js +630 -0
- package/lib/thin/index.js +40 -0
- package/lib/thin/lob.js +189 -0
- package/lib/thin/pool.js +481 -0
- package/lib/thin/protocol/buffer.js +1043 -0
- package/lib/thin/protocol/capabilities.js +121 -0
- package/lib/thin/protocol/constants.js +765 -0
- package/lib/thin/protocol/encryptDecrypt.js +185 -0
- package/lib/thin/protocol/messages/auth.js +349 -0
- package/lib/thin/protocol/messages/base.js +476 -0
- package/lib/thin/protocol/messages/commit.js +56 -0
- package/lib/thin/protocol/messages/dataType.js +391 -0
- package/lib/thin/protocol/messages/execute.js +312 -0
- package/lib/thin/protocol/messages/fetch.js +60 -0
- package/lib/thin/protocol/messages/index.js +53 -0
- package/lib/thin/protocol/messages/lobOp.js +201 -0
- package/lib/thin/protocol/messages/logOff.js +53 -0
- package/lib/thin/protocol/messages/ping.js +56 -0
- package/lib/thin/protocol/messages/protocol.js +78 -0
- package/lib/thin/protocol/messages/rollback.js +56 -0
- package/lib/thin/protocol/messages/sessionRelease.js +60 -0
- package/lib/thin/protocol/messages/withData.js +812 -0
- package/lib/thin/protocol/oson.js +661 -0
- package/lib/thin/protocol/packet.js +519 -0
- package/lib/thin/protocol/protocol.js +202 -0
- package/lib/thin/protocol/utils.js +89 -0
- package/lib/thin/resultSet.js +122 -0
- package/lib/thin/sqlnet/connStrategy.js +175 -0
- package/lib/thin/sqlnet/constants.js +199 -0
- package/lib/thin/sqlnet/ezConnectResolver.js +488 -0
- package/lib/thin/sqlnet/navNodes.js +870 -0
- package/lib/thin/sqlnet/networkSession.js +621 -0
- package/lib/thin/sqlnet/ntTcp.js +527 -0
- package/lib/thin/sqlnet/nvStrToNvPair.js +783 -0
- package/lib/thin/sqlnet/packet.js +405 -0
- package/lib/thin/sqlnet/paramParser.js +206 -0
- package/lib/thin/sqlnet/sessionAtts.js +160 -0
- package/lib/thin/statement.js +300 -0
- package/lib/thin/util.js +289 -0
- package/lib/transformer.js +252 -0
- package/lib/types.js +357 -0
- package/lib/util.js +196 -110
- package/lib/version.js +36 -0
- package/package/README.md +33 -30
- package/package/install.js +89 -64
- package/package/prunebinaries.js +60 -12
- package/package.json +3 -3
- package/build/Release/oracledb-5.5.0-darwin-x64.node +0 -0
- package/build/Release/oracledb-5.5.0-darwin-x64.node-buildinfo.txt +0 -1
- package/build/Release/oracledb-5.5.0-linux-x64.node +0 -0
- package/build/Release/oracledb-5.5.0-linux-x64.node-buildinfo.txt +0 -1
- package/build/Release/oracledb-5.5.0-win32-x64.node +0 -0
- package/build/Release/oracledb-5.5.0-win32-x64.node-buildinfo.txt +0 -1
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
// Copyright (c) 2022, 2023, Oracle and/or its affiliates.
|
|
2
|
+
|
|
3
|
+
//-----------------------------------------------------------------------------
|
|
4
|
+
//
|
|
5
|
+
// This software is dual-licensed to you under the Universal Permissive License
|
|
6
|
+
// (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
|
7
|
+
// 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose
|
|
8
|
+
// either license.
|
|
9
|
+
//
|
|
10
|
+
// If you elect to accept the software under the Apache License, Version 2.0,
|
|
11
|
+
// the following applies:
|
|
12
|
+
//
|
|
13
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
14
|
+
// you may not use this file except in compliance with the License.
|
|
15
|
+
// You may obtain a copy of the License at
|
|
16
|
+
//
|
|
17
|
+
// https://www.apache.org/licenses/LICENSE-2.0
|
|
18
|
+
//
|
|
19
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
20
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
21
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
22
|
+
// See the License for the specific language governing permissions and
|
|
23
|
+
// limitations under the License.
|
|
24
|
+
//
|
|
25
|
+
//-----------------------------------------------------------------------------
|
|
26
|
+
|
|
27
|
+
'use strict';
|
|
28
|
+
|
|
29
|
+
const crypto = require('crypto');
|
|
30
|
+
const path = require('path');
|
|
31
|
+
const constants = require("./constants.js");
|
|
32
|
+
const fs = require("fs");
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Generate UUID (Used for Connection ID)
|
|
36
|
+
* @returns Promise
|
|
37
|
+
*/
|
|
38
|
+
async function genuuid() {
|
|
39
|
+
return await new Promise((resolve, reject) => {
|
|
40
|
+
crypto.randomBytes(16, (err, buf) => {
|
|
41
|
+
if (err) {
|
|
42
|
+
reject(err);
|
|
43
|
+
} else {
|
|
44
|
+
resolve(buf);
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Network Session Attributes
|
|
52
|
+
*/
|
|
53
|
+
class SessionAtts {
|
|
54
|
+
|
|
55
|
+
constructor(uuid) {
|
|
56
|
+
this.largeSDU = false;
|
|
57
|
+
this.tdu = constants.NSPDFTDULN;
|
|
58
|
+
this.nt = {};
|
|
59
|
+
this.nt.tcpNoDelay = true;
|
|
60
|
+
this.uuid = uuid;
|
|
61
|
+
this.nt.sslServerDNMatch = true;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Update Session attributes with input Parameters
|
|
66
|
+
* @param {object} Params Input paramters
|
|
67
|
+
*/
|
|
68
|
+
setFrom(params) {
|
|
69
|
+
if (params) {
|
|
70
|
+
if (params.sdu > 0) {
|
|
71
|
+
this.sdu = parseInt(params.sdu);
|
|
72
|
+
}
|
|
73
|
+
if (typeof params.walletLocation === 'string') {
|
|
74
|
+
this.nt.walletFile = path.join(params.walletLocation, constants.PEM_WALLET_FILE_NAME);
|
|
75
|
+
}
|
|
76
|
+
if (typeof params.walletPassword === 'string') {
|
|
77
|
+
this.nt.walletPassword = params.walletPassword;
|
|
78
|
+
}
|
|
79
|
+
if (params.expireTime > 0) {
|
|
80
|
+
this.nt.expireTime = params.expireTime * 1000 * 60;
|
|
81
|
+
}
|
|
82
|
+
if (params.connectTimeout > 0) {
|
|
83
|
+
this.connectTimeout = params.connectTimeout * 1000;
|
|
84
|
+
}
|
|
85
|
+
if (params.transportConnectTimeout > 0) {
|
|
86
|
+
this.transportConnectTimeout = params.transportConnectTimeout * 1000;
|
|
87
|
+
}
|
|
88
|
+
if (params.recvTimeout > 0) {
|
|
89
|
+
this.recvTimeout = params.recvTimeout * 1000;
|
|
90
|
+
}
|
|
91
|
+
if (params.sendTimeout > 0) {
|
|
92
|
+
this.sendTimeout = params.sendTimeout * 1000;
|
|
93
|
+
}
|
|
94
|
+
if (typeof params.connectionIdPrefix === 'string') {
|
|
95
|
+
this.connectionIdPrefix = params.connectionIdPrefix;
|
|
96
|
+
}
|
|
97
|
+
if (typeof params.tcpNoDelay === 'boolean') {
|
|
98
|
+
this.nt.tcpNoDelay = params.tcpNoDelay;
|
|
99
|
+
}
|
|
100
|
+
if (typeof params.sslServerDNMatch === 'boolean') {
|
|
101
|
+
this.nt.sslServerDNMatch = params.sslServerDNMatch;
|
|
102
|
+
}
|
|
103
|
+
if (typeof params.sslServerCertDN === 'string') {
|
|
104
|
+
this.nt.sslServerCertDN = params.sslServerCertDN;
|
|
105
|
+
}
|
|
106
|
+
if (typeof params.enable === 'string' && params.enable.toUpperCase() == "BROKEN") {
|
|
107
|
+
this.nt.enabledDCD = true;
|
|
108
|
+
}
|
|
109
|
+
if (typeof params.httpsProxy === 'string') {
|
|
110
|
+
this.nt.httpsProxy = params.httpsProxy;
|
|
111
|
+
}
|
|
112
|
+
if (params.httpsProxyPort >= 0) {
|
|
113
|
+
this.nt.httpsProxyPort = parseInt(params.httpsProxyPort);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Read wallet
|
|
120
|
+
* @returns Promise
|
|
121
|
+
*/
|
|
122
|
+
readWalletFile() {
|
|
123
|
+
return new Promise((resolve, reject)=> {
|
|
124
|
+
fs.readFile(this.nt.walletFile, (err, data) => {
|
|
125
|
+
if (err) {
|
|
126
|
+
reject(err);
|
|
127
|
+
} else {
|
|
128
|
+
resolve(data);
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Prepare attributes for connection, Generate Connection ID and read Wallet file
|
|
136
|
+
*
|
|
137
|
+
*/
|
|
138
|
+
async prepare(protocol) {
|
|
139
|
+
if (!this.uuid) {
|
|
140
|
+
this.uuid = await genuuid();
|
|
141
|
+
this.uuid = this.uuid.toString('base64');
|
|
142
|
+
}
|
|
143
|
+
if (this.connectionIdPrefix) {
|
|
144
|
+
this.connectionId = this.connectionIdPrefix + this.uuid;
|
|
145
|
+
} else {
|
|
146
|
+
this.connectionId = this.uuid;
|
|
147
|
+
}
|
|
148
|
+
this.nt.connectionId = this.connectionId;
|
|
149
|
+
|
|
150
|
+
if (protocol && (protocol.toUpperCase() == "TCPS" && this.nt.walletFile)) {
|
|
151
|
+
this.nt.wallet = await this.readWalletFile();
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (!this.connectTimeout && !this.transportConnectTimeout)
|
|
155
|
+
this.transportConnectTimeout = 60 * 1000; /* Default to 60 secs */
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
module.exports = SessionAtts;
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
// Copyright (c) 2022, 2023, Oracle and/or its affiliates.
|
|
2
|
+
|
|
3
|
+
//-----------------------------------------------------------------------------
|
|
4
|
+
//
|
|
5
|
+
// This software is dual-licensed to you under the Universal Permissive License
|
|
6
|
+
// (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
|
7
|
+
// 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose
|
|
8
|
+
// either license.
|
|
9
|
+
//
|
|
10
|
+
// If you elect to accept the software under the Apache License, Version 2.0,
|
|
11
|
+
// the following applies:
|
|
12
|
+
//
|
|
13
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
14
|
+
// you may not use this file except in compliance with the License.
|
|
15
|
+
// You may obtain a copy of the License at
|
|
16
|
+
//
|
|
17
|
+
// https://www.apache.org/licenses/LICENSE-2.0
|
|
18
|
+
//
|
|
19
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
20
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
21
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
22
|
+
// See the License for the specific language governing permissions and
|
|
23
|
+
// limitations under the License.
|
|
24
|
+
//
|
|
25
|
+
//-----------------------------------------------------------------------------
|
|
26
|
+
|
|
27
|
+
'use strict';
|
|
28
|
+
|
|
29
|
+
const { Buffer } = require('buffer');
|
|
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
|
+
|
|
55
|
+
/**
|
|
56
|
+
* It is used to cache the metadata about bind information
|
|
57
|
+
* associated with the statement. This will determine if statement needs
|
|
58
|
+
* to use Execute or Re-Execute.
|
|
59
|
+
*/
|
|
60
|
+
class BindInfo {
|
|
61
|
+
constructor(name, isReturnBind = false) {
|
|
62
|
+
this.bindName = name;
|
|
63
|
+
this.isReturnBind = isReturnBind;
|
|
64
|
+
this.maxSize = 0;
|
|
65
|
+
this.numElements = 0;
|
|
66
|
+
this.maxArraySize = 0;
|
|
67
|
+
this.type = null;
|
|
68
|
+
this.isArray = false;
|
|
69
|
+
this.dir = constants.BIND_IN;
|
|
70
|
+
this.bindVar = null;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Encapsulates the SQL statement run on the connection.
|
|
76
|
+
* It has information like type of stmt, bind infrmation, cursor number, ...
|
|
77
|
+
*/
|
|
78
|
+
module.exports.BindInfo = BindInfo;
|
|
79
|
+
|
|
80
|
+
class Statement {
|
|
81
|
+
constructor() {
|
|
82
|
+
this.sql = "";
|
|
83
|
+
this.sqlBytes = [];
|
|
84
|
+
this.sqlLength = 0;
|
|
85
|
+
this.cursorId = 0;
|
|
86
|
+
this.requiresDefine = false;
|
|
87
|
+
this.isQuery = false;
|
|
88
|
+
this.isPlSql = false;
|
|
89
|
+
this.isDml = false;
|
|
90
|
+
this.isDdl = false;
|
|
91
|
+
this.isReturning = false;
|
|
92
|
+
this.bindInfoList = [];
|
|
93
|
+
this.queryVars = [];
|
|
94
|
+
this.bindInfoDict = new Map();
|
|
95
|
+
this.requiresFullExecute = false;
|
|
96
|
+
this.returnToCache = false;
|
|
97
|
+
this.numColumns = 0;
|
|
98
|
+
this.lastRowIndex;
|
|
99
|
+
this.lastRowid;
|
|
100
|
+
this.moreRowsToFetch = true;
|
|
101
|
+
this.inUse = false;
|
|
102
|
+
this.bufferRowIndex = 0;
|
|
103
|
+
this.bufferRowCount = 0;
|
|
104
|
+
this.statementType = constants.STMT_TYPE_UNKNOWN;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
//---------------------------------------------------------------------------
|
|
108
|
+
// _copy()
|
|
109
|
+
//
|
|
110
|
+
// Copying existing statement into new statement object required by drcp
|
|
111
|
+
//---------------------------------------------------------------------------
|
|
112
|
+
_copy() {
|
|
113
|
+
const copiedStatement = new Statement();
|
|
114
|
+
copiedStatement.sql = this.sql;
|
|
115
|
+
copiedStatement.sqlBytes = this.sqlBytes;
|
|
116
|
+
copiedStatement.sqlLength = this.sqlLength;
|
|
117
|
+
copiedStatement.isQuery = this.isQuery;
|
|
118
|
+
copiedStatement.isPlSql = this.isPlSql;
|
|
119
|
+
copiedStatement.isDml = this.isDml;
|
|
120
|
+
copiedStatement.isDdl = this.isDdl;
|
|
121
|
+
copiedStatement.isReturning = this.isReturning;
|
|
122
|
+
copiedStatement.bindInfoList = [];
|
|
123
|
+
for (const bindInfo of this.bindInfoList) {
|
|
124
|
+
const newBindInfo = new BindInfo(bindInfo.bindName, bindInfo.isReturnBind);
|
|
125
|
+
copiedStatement.bindInfoList.push(newBindInfo);
|
|
126
|
+
}
|
|
127
|
+
const bindInfoDict = copiedStatement.bindInfoDict = new Map();
|
|
128
|
+
for (const bindInfo of copiedStatement.bindInfoList) {
|
|
129
|
+
if (bindInfoDict.has(bindInfo.bindName)) {
|
|
130
|
+
bindInfoDict.get(bindInfo.bindName).push(bindInfo);
|
|
131
|
+
} else {
|
|
132
|
+
bindInfoDict.set(bindInfo.bindName, [bindInfo]);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
copiedStatement.returnToCache = false;
|
|
136
|
+
return copiedStatement;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
//---------------------------------------------------------------------------
|
|
140
|
+
// _determineStatementType(sql)
|
|
141
|
+
//
|
|
142
|
+
// Determine the type of the SQL statement by examining the first keyword
|
|
143
|
+
// found in the statement
|
|
144
|
+
//---------------------------------------------------------------------------
|
|
145
|
+
_determineStatementType(sql) {
|
|
146
|
+
sql = thinUtil.cleanSql(sql);
|
|
147
|
+
let tokens = sql.trim().trimStart('(').substring(0, 10).split(" ");
|
|
148
|
+
if (tokens.length > 0) {
|
|
149
|
+
const sqlKeyword = tokens[0].toUpperCase();
|
|
150
|
+
if (["DECLARE", "BEGIN", "CALL"].includes(sqlKeyword)) {
|
|
151
|
+
this.isPlSql = true;
|
|
152
|
+
if (sqlKeyword === 'DECLARE') {
|
|
153
|
+
this.statementType = constants.STMT_TYPE_DECLARE;
|
|
154
|
+
} else if (sqlKeyword === 'BEGIN') {
|
|
155
|
+
this.statementType = constants.STMT_TYPE_BEGIN;
|
|
156
|
+
} else if (sqlKeyword === 'CALL') {
|
|
157
|
+
this.statementType = constants.STMT_TYPE_CALL;
|
|
158
|
+
}
|
|
159
|
+
} else if (["SELECT", "WITH"].includes(sqlKeyword)) {
|
|
160
|
+
this.isQuery = true;
|
|
161
|
+
if (sqlKeyword === "SELECT") {
|
|
162
|
+
this.statementType = constants.STMT_TYPE_SELECT;
|
|
163
|
+
}
|
|
164
|
+
} else if (["INSERT", "UPDATE", "DELETE", "MERGE"].includes(sqlKeyword)) {
|
|
165
|
+
this.isDml = true;
|
|
166
|
+
if (sqlKeyword === 'INSERT') {
|
|
167
|
+
this.statementType = constants.STMT_TYPE_INSERT;
|
|
168
|
+
} else if (sqlKeyword === 'UPDATE') {
|
|
169
|
+
this.statementType = constants.STMT_TYPE_UPDATE;
|
|
170
|
+
} else if (sqlKeyword === 'DELETE') {
|
|
171
|
+
this.statementType = constants.STMT_TYPE_DELETE;
|
|
172
|
+
} else if (sqlKeyword === 'MERGE') {
|
|
173
|
+
this.statementType = constants.STMT_TYPE_MERGE;
|
|
174
|
+
}
|
|
175
|
+
} else if (["CREATE", "ALTER", "DROP", "TRUNCATE"].includes(sqlKeyword)) {
|
|
176
|
+
this.isDdl = true;
|
|
177
|
+
if (sqlKeyword === 'CREATE') {
|
|
178
|
+
this.statementType = constants.STMT_TYPE_CREATE;
|
|
179
|
+
} else if (sqlKeyword === 'ALTER') {
|
|
180
|
+
this.statementType = constants.STMT_TYPE_ALTER;
|
|
181
|
+
} else if (sqlKeyword === 'DROP') {
|
|
182
|
+
this.statementType = constants.STMT_TYPE_DROP;
|
|
183
|
+
}
|
|
184
|
+
} else if (sqlKeyword === 'COMMIT') {
|
|
185
|
+
this.statementType = constants.STMT_TYPE_COMMIT;
|
|
186
|
+
} else if (sqlKeyword === 'ROLLBACK') {
|
|
187
|
+
this.statementType = constants.STMT_TYPE_ROLLBACK;
|
|
188
|
+
} else if (sqlKeyword === 'MERGE') {
|
|
189
|
+
this.statementType = constants.STMT_TYPE_MERGE;
|
|
190
|
+
} else {
|
|
191
|
+
this.statementType = constants.STMT_TYPE_UNKNOWN;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
//---------------------------------------------------------------------------
|
|
197
|
+
// prepare(sql)
|
|
198
|
+
//
|
|
199
|
+
// Prepare the SQL for execution by determining the list of bind names
|
|
200
|
+
// that are found within it. The length of the SQL text is also calculated
|
|
201
|
+
// at this time.
|
|
202
|
+
//---------------------------------------------------------------------------
|
|
203
|
+
_prepare(sql) {
|
|
204
|
+
this.sql = sql;
|
|
205
|
+
this.sqlBytes = Buffer.from(this.sql, 'utf8');
|
|
206
|
+
this.sqlLength = this.sqlBytes.length;
|
|
207
|
+
// replace literals with a specific literal
|
|
208
|
+
sql = sql.replace(CONSTANT_STRING_PATTERN, "'S'");
|
|
209
|
+
sql = sql.replace(SINGLE_LINE_COMMENT_PATTERN, "");
|
|
210
|
+
sql = sql.replace(MULTI_LINE_COMMENT_PATTERN, "");
|
|
211
|
+
this._determineStatementType(sql);
|
|
212
|
+
let returningSql;
|
|
213
|
+
if (this.isQuery || this.isDml || this.isPlSql) {
|
|
214
|
+
let inputSql = sql;
|
|
215
|
+
if (this.isDml) {
|
|
216
|
+
/*
|
|
217
|
+
* get starting index after DML_RETURNING_KEY from begining of sql and starting index
|
|
218
|
+
* after DML_RETURNING_INTO_KEY from the end of sql
|
|
219
|
+
*/
|
|
220
|
+
let result;
|
|
221
|
+
let intoKey = -1;
|
|
222
|
+
const retKey = sql.search(DML_RETURNING_KEY);
|
|
223
|
+
let intoRegex = DML_RETURNING_INTO_KEY;
|
|
224
|
+
// simulate lastInfdexOf with intoRegex input
|
|
225
|
+
while ((result = intoRegex.exec(sql.slice(retKey))) != null) {
|
|
226
|
+
intoKey = result.index;
|
|
227
|
+
intoRegex.lastIndex = result.index + 1;
|
|
228
|
+
}
|
|
229
|
+
if (retKey > -1 && intoKey > -1) {
|
|
230
|
+
intoKey = retKey + intoKey;
|
|
231
|
+
inputSql = sql.slice(0, intoKey);
|
|
232
|
+
returningSql = sql.slice(intoKey);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
this._addBinds(inputSql, false);
|
|
236
|
+
if (returningSql) {
|
|
237
|
+
this.isReturning = true;
|
|
238
|
+
this._addBinds(returningSql, true);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
//---------------------------------------------------------------------------
|
|
244
|
+
// _addBinds(sql)
|
|
245
|
+
//
|
|
246
|
+
// Add bind information to the statement by examining the passed SQL for
|
|
247
|
+
// bind variable names.
|
|
248
|
+
//---------------------------------------------------------------------------
|
|
249
|
+
_addBinds(sql, isReturnBind) {
|
|
250
|
+
const regexMatchArray = [...sql.matchAll(BIND_PATTERN)];
|
|
251
|
+
let name;
|
|
252
|
+
regexMatchArray.forEach(element => {
|
|
253
|
+
if (element[0].startsWith('"') && element[0].endsWith('"')) {
|
|
254
|
+
name = element[0].substring(1, element[0].length - 1);
|
|
255
|
+
} else {
|
|
256
|
+
name = element[0].trim().toUpperCase();
|
|
257
|
+
}
|
|
258
|
+
if (this.isPlSql && this.bindInfoDict.has(name)) {
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
let info = new BindInfo(name, isReturnBind);
|
|
262
|
+
this.bindInfoList.push(info);
|
|
263
|
+
|
|
264
|
+
if (this.bindInfoDict.has(info.bindName)) {
|
|
265
|
+
this.bindInfoDict.get(info.bindName).push(info);
|
|
266
|
+
} else {
|
|
267
|
+
this.bindInfoDict.set(info.bindName, [info]);
|
|
268
|
+
}
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
//---------------------------------------------------------------------------
|
|
273
|
+
// _setVariable(sql)
|
|
274
|
+
//
|
|
275
|
+
// Set the variable on the bind information and copy across metadata that
|
|
276
|
+
// will be used for binding. If the bind metadata has changed, mark the
|
|
277
|
+
// statement as requiring a full execute. In addition, binding a REF
|
|
278
|
+
// cursor also requires a full execute.
|
|
279
|
+
//---------------------------------------------------------------------------
|
|
280
|
+
_setVariable(bindInfo, variable) {
|
|
281
|
+
if (variable.maxSize !== bindInfo.maxSize
|
|
282
|
+
|| variable.dir !== bindInfo.dir
|
|
283
|
+
|| variable.isArray !== bindInfo.isArray
|
|
284
|
+
|| variable.values.length > bindInfo.numElements
|
|
285
|
+
|| variable.type != bindInfo.type
|
|
286
|
+
|| variable.maxArraySize != bindInfo.maxArraySize) {
|
|
287
|
+
bindInfo.isArray = variable.isArray;
|
|
288
|
+
bindInfo.numElements = variable.values.length;
|
|
289
|
+
bindInfo.maxSize = variable.maxSize;
|
|
290
|
+
bindInfo.type = variable.type;
|
|
291
|
+
bindInfo.dir = variable.dir;
|
|
292
|
+
bindInfo.maxArraySize = variable.maxArraySize;
|
|
293
|
+
this.requiresFullExecute = true;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
bindInfo.bindVar = variable;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
module.exports.Statement = Statement;
|