Skip to content

Commit be408fa

Browse files
committed
Recognize IFILE parameter in tnsnames.ora to read multiple custom network cofniguration files
1 parent d25150c commit be408fa

File tree

2 files changed

+90
-50
lines changed

2 files changed

+90
-50
lines changed

doc/src/release_notes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ node-oracledb `v6.6.0 <https://github.com/oracle/node-oracledb/compare/v6.5.1...
1313
Thin Mode Changes
1414
+++++++++++++++++
1515

16+
#) Added support to use IFILE parameter to embed custom
17+
network configuration files in the main tnsnames.ora file.
18+
1619
#) Fixed bug which throws a ``TypeError: objType.attributes is not iterable``
1720
error when :ref:`DbObject Class <dbobjectclass>` instance contains an
1821
attribute of type ``SYS.XMLTYPE``.

lib/thin/sqlnet/paramParser.js

Lines changed: 87 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ const process = require('process');
3232
const readline = require('readline');
3333
const errors = require("../../errors.js");
3434

35+
const MAX_IFILE_DEPTH = 4;
3536
/**
3637
* Returns File path of the tnsnames.ora if it exists.
3738
*/
@@ -59,23 +60,42 @@ function tnsnamesFilePath(configDir) {
5960
}
6061
}
6162

62-
let prevmtime = 0;
63-
6463
class NLParamParser {
64+
65+
constructor() {
66+
this.waiters = [];
67+
this.readInProgress = false;
68+
}
6569
/**
6670
* Reads the given file line by line and stores the
6771
* network service names mapped to connect descriptors in the hashtable.
6872
* @param {string} file_path
6973
* @returns {Promise}
7074
*/
7175
async initializeNlpa(file_path) {
72-
const stat = fs.statSync(file_path);
73-
74-
if (!(stat.mtime - prevmtime)) {
75-
/* File has been read */
76+
if (this.readInProgress) {
77+
await new Promise((resolve) => {
78+
this.waiters.push(resolve);
79+
});
80+
}
81+
if (!this.checkModfTime()) {
82+
/* No File has been modified */
7683
return this.ht;
7784
}
85+
this.ht = new Map();
86+
this.modTime = new Map(); //stores modified time of each IFile
87+
this.readInProgress = true;
88+
await this.start(file_path, 0); //start with 0 depth (tnsnames.ora)
89+
return this.ht;
90+
}
91+
92+
async start(file_path, depth) {
7893

94+
if (depth > MAX_IFILE_DEPTH)
95+
return; //ignore after max depth
96+
const stat = fs.statSync(file_path);
97+
// store file path and its modified time.
98+
this.modTime.set(file_path, stat.mtime);
7999
// Creating a readable stream from file
80100
// readline module reads line by line
81101
// but from a readable stream only.
@@ -84,52 +104,49 @@ class NLParamParser {
84104
output: process.stdout,
85105
terminal: false
86106
});
87-
this.ht = new Map();
88-
89-
const start = async () =>{
90-
let nvElem = "";
91-
for await (let line of file) {
92-
if (line.length == 0) { // ignore empty lines
93-
continue;
94-
} else if (line[0] == '#') { // comment line
107+
let nvElem = "";
108+
for await (let line of file) {
109+
if (line.length == 0) { // ignore empty lines
110+
continue;
111+
} else if (line[0] == '#') { // comment line
112+
continue;
113+
} else if ((line[0] == ' ') || // continued input on new line
114+
(line[0] == '\t') ||
115+
(line[0] == ')') ||
116+
(line[0] == '(')) {
117+
line = line.replace(/\s+/g, '');
118+
line = this.checkNLPforComments(line);
119+
if (line.length == 0)
95120
continue;
96-
} else if ((line[0] == ' ') || // continued input on new line
97-
(line[0] == '\t') ||
98-
(line[0] == ')') ||
99-
(line[0] == '(')) {
100-
line = line.replace(/\s+/g, '');
101-
line = this.checkNLPforComments(line);
102-
if (line.length == 0)
103-
continue;
104-
else {
105-
nvElem = nvElem + line;
106-
}
121+
else {
122+
nvElem = nvElem + line;
123+
}
107124

108-
} else { // new NV Element starting here
109-
if (nvElem.length == 0) {
125+
} else { // new NV Element starting here
126+
if (nvElem.length == 0) {
110127

111-
line = this.checkNLPforComments(line);
112-
nvElem = nvElem + line;
128+
line = this.checkNLPforComments(line);
129+
nvElem = nvElem + line;
113130

114-
} else if (nvElem.length != 0) {
115-
this.addNLPListElement(nvElem); // Add Parameter to Hashtable
116-
nvElem = ""; // Clear first, before storing current line
131+
} else if (nvElem.length != 0) {
132+
await this.addNLPListElement(nvElem, depth); // Add Parameter to Hashtable
133+
nvElem = ""; // Clear first, before storing current line
117134

118-
line = this.checkNLPforComments(line);
119-
nvElem = nvElem + line;
120-
}
135+
line = this.checkNLPforComments(line);
136+
nvElem = nvElem + line;
121137
}
122138
}
123-
if (nvElem.length != 0) { // at eof, still one more parameter to read
124-
this.addNLPListElement(nvElem);
125-
nvElem = ""; // clear nvElem buffer after added
126-
}
127-
prevmtime = stat.mtime;
128-
return this.ht;
129-
};
130-
return await start();
139+
}
140+
if (nvElem.length != 0) { // at eof, still one more parameter to read
141+
await this.addNLPListElement(nvElem, depth);
142+
nvElem = ""; // clear nvElem buffer after added
143+
}
144+
this.readInProgress = false;
145+
let waiter;
146+
while ((waiter = this.waiters.pop())) {
147+
waiter();
148+
}
131149
}
132-
133150
/**
134151
* Given a string, this method looks if the '#' character is present.
135152
* If true, the line is truncated from that point onwards until the end
@@ -155,11 +172,28 @@ class NLParamParser {
155172
}
156173
return str1.join('');
157174
}
175+
// check if any of the IFiles has been changed
176+
checkModfTime() {
177+
if (this.modTime) {
178+
for (const [key, value] of this.modTime) {
179+
if (fs.existsSync(key)) {
180+
const stat = fs.statSync(key);
181+
if ((stat.mtime - value > 0)) {
182+
return true;
183+
}
184+
} else
185+
return true;
186+
}
187+
} else {
188+
return true;
189+
}
190+
return false;
191+
}
158192
/**
159193
* adds name value pairs from the input buffer into the hash table.
160194
* @param {string} ibuf
161195
*/
162-
addNLPListElement(ibuf) {
196+
async addNLPListElement(ibuf, depth) {
163197
const res = ibuf.split(/\r?\n/).filter(element => element);
164198
for (let i = 0; i < res.length; i++) {
165199
if (res[i].charAt(0) != '(') {
@@ -169,14 +203,17 @@ class NLParamParser {
169203
const name = nvp.name;
170204
const uname = name.toUpperCase();
171205
nvp.name = uname;
172-
const unames = uname.split(","); //multiple aliases (alias1, alias2, alias3)
173-
for (let i = 0; i < unames.length; i++) {
174-
this.ht.set(unames[i], nvp);
206+
// support for ifile
207+
if (uname == 'IFILE') {
208+
await this.start(nvp.atom, depth + 1);
209+
} else {
210+
const unames = uname.split(","); //multiple aliases (alias1, alias2, alias3)
211+
for (let i = 0; i < unames.length; i++) {
212+
this.ht.set(unames[i], nvp);
213+
}
175214
}
176215
}
177216
}
178-
179-
180217
toString() {
181218
let out = "";
182219
this.ht.forEach((value) => {

0 commit comments

Comments
 (0)