web_plsql 1.2.0 → 1.3.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/README.md +103 -8
- package/dist/chunk-DQk6qfdC.mjs +18 -0
- package/dist/frontend/assets/main-C8GKnEhz.js +147 -0
- package/dist/frontend/assets/main-C8GKnEhz.js.br +0 -0
- package/dist/frontend/assets/main-C8GKnEhz.js.gz +0 -0
- package/dist/frontend/assets/main-bU4x_yEW.css +1 -0
- package/dist/frontend/assets/main-bU4x_yEW.css.br +0 -0
- package/dist/frontend/assets/main-bU4x_yEW.css.gz +0 -0
- package/{src/admin → dist/frontend}/index.html +12 -25
- package/dist/frontend/index.html.br +0 -0
- package/dist/frontend/index.html.gz +0 -0
- package/dist/index.d.mts +646 -0
- package/dist/index.mjs +3559 -0
- package/dist/index.mjs.map +1 -0
- package/dist/oracledb-mock-Dn8aHtd7.mjs +68 -0
- package/dist/oracledb-mock-Dn8aHtd7.mjs.map +1 -0
- package/examples/config-apex.js +1 -1
- package/examples/config-docker.js +1 -2
- package/package.json +48 -32
- package/examples/config-native.js +0 -68
- package/src/admin/client/charts.ts +0 -598
- package/src/admin/client/main.js +0 -3
- package/src/admin/client/tailwind.css +0 -41
- package/src/admin/js/api.ts +0 -170
- package/src/admin/js/app.ts +0 -614
- package/src/admin/js/eslint.config.js +0 -74
- package/src/admin/js/schemas.ts +0 -215
- package/src/admin/js/templates/config.ts +0 -147
- package/src/admin/js/templates/errorRow.ts +0 -21
- package/src/admin/js/templates/index.ts +0 -4
- package/src/admin/js/templates/poolCard.ts +0 -61
- package/src/admin/js/templates/traceRow.ts +0 -24
- package/src/admin/js/tsconfig.json +0 -24
- package/src/admin/js/types.ts +0 -336
- package/src/admin/js/ui/components.ts +0 -44
- package/src/admin/js/ui/table.ts +0 -173
- package/src/admin/js/ui/theme.ts +0 -93
- package/src/admin/js/ui/views.ts +0 -427
- package/src/admin/js/util/format.ts +0 -46
- package/src/admin/js/util/metrics.ts +0 -24
- package/src/admin/lib/chart.bundle.css +0 -1
- package/src/admin/lib/chart.bundle.js +0 -146
- package/src/admin/style.css +0 -1437
- package/src/bin/load-test.js +0 -202
- package/src/handler/handlerAdmin.js +0 -293
- package/src/handler/handlerLogger.js +0 -21
- package/src/handler/handlerUpload.js +0 -26
- package/src/handler/plsql/cgi.js +0 -131
- package/src/handler/plsql/errorPage.js +0 -113
- package/src/handler/plsql/handlerPlSql.js +0 -90
- package/src/handler/plsql/owaPageStream.js +0 -93
- package/src/handler/plsql/parsePage.js +0 -213
- package/src/handler/plsql/procedure.js +0 -426
- package/src/handler/plsql/procedureError.js +0 -40
- package/src/handler/plsql/procedureNamed.js +0 -282
- package/src/handler/plsql/procedureSanitize.js +0 -286
- package/src/handler/plsql/procedureVariable.js +0 -56
- package/src/handler/plsql/request.js +0 -124
- package/src/handler/plsql/requestError.js +0 -23
- package/src/handler/plsql/sendResponse.js +0 -174
- package/src/handler/plsql/stream.js +0 -28
- package/src/handler/plsql/upload.js +0 -109
- package/src/index.js +0 -19
- package/src/server/adminContext.js +0 -23
- package/src/server/config.js +0 -57
- package/src/server/connections.js +0 -40
- package/src/server/server.js +0 -304
- package/src/types.js +0 -150
- package/src/util/cache.js +0 -123
- package/src/util/errorToString.js +0 -24
- package/src/util/file.js +0 -91
- package/src/util/html.js +0 -53
- package/src/util/jsonLogger.js +0 -47
- package/src/util/oracle.js +0 -80
- package/src/util/shutdown.js +0 -44
- package/src/util/statsManager.js +0 -368
- package/src/util/trace.js +0 -326
- package/src/util/traceManager.js +0 -68
- package/src/util/type.js +0 -6
- package/src/util/util.js +0 -66
- package/src/version.js +0 -5
- package/types/admin/js/schemas.d.ts +0 -384
- package/types/admin/js/types.d.ts +0 -312
- package/types/handler/handlerAdmin.d.ts +0 -79
- package/types/handler/handlerLogger.d.ts +0 -2
- package/types/handler/handlerUpload.d.ts +0 -7
- package/types/handler/plsql/cgi.d.ts +0 -4
- package/types/handler/plsql/errorPage.d.ts +0 -11
- package/types/handler/plsql/handlerPlSql.d.ts +0 -13
- package/types/handler/plsql/owaPageStream.d.ts +0 -28
- package/types/handler/plsql/parsePage.d.ts +0 -3
- package/types/handler/plsql/procedure.d.ts +0 -13
- package/types/handler/plsql/procedureError.d.ts +0 -23
- package/types/handler/plsql/procedureNamed.d.ts +0 -14
- package/types/handler/plsql/procedureSanitize.d.ts +0 -11
- package/types/handler/plsql/procedureVariable.d.ts +0 -10
- package/types/handler/plsql/request.d.ts +0 -9
- package/types/handler/plsql/requestError.d.ts +0 -8
- package/types/handler/plsql/sendResponse.d.ts +0 -6
- package/types/handler/plsql/upload.d.ts +0 -5
- package/types/index.d.ts +0 -10
- package/types/server/adminContext.d.ts +0 -17
- package/types/server/config.d.ts +0 -2
- package/types/server/server.d.ts +0 -57
- package/types/types.d.ts +0 -328
- package/types/util/cache.d.ts +0 -69
- package/types/util/errorToString.d.ts +0 -1
- package/types/util/file.d.ts +0 -6
- package/types/util/html.d.ts +0 -3
- package/types/util/jsonLogger.d.ts +0 -45
- package/types/util/oracle.d.ts +0 -5
- package/types/util/shutdown.d.ts +0 -2
- package/types/util/statsManager.d.ts +0 -395
- package/types/util/trace.d.ts +0 -22
- package/types/util/traceManager.d.ts +0 -35
- package/types/util/type.d.ts +0 -1
- package/types/util/util.d.ts +0 -3
- package/types/version.d.ts +0 -1
- /package/{src/admin/favicon.svg → dist/frontend/assets/favicon-mQAM4tVu.svg} +0 -0
|
@@ -1,426 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Invoke the Oracle procedure and return the raw content of the page
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import debugModule from 'debug';
|
|
6
|
-
const debug = debugModule('webplsql:procedure');
|
|
7
|
-
|
|
8
|
-
import oracledb from 'oracledb';
|
|
9
|
-
import stream from 'node:stream';
|
|
10
|
-
import z from 'zod';
|
|
11
|
-
|
|
12
|
-
import {uploadFile} from './upload.js';
|
|
13
|
-
import {getProcedureVariable} from './procedureVariable.js';
|
|
14
|
-
import {getProcedureNamed} from './procedureNamed.js';
|
|
15
|
-
import {parsePage} from './parsePage.js';
|
|
16
|
-
import {sendResponse} from './sendResponse.js';
|
|
17
|
-
import {ProcedureError} from './procedureError.js';
|
|
18
|
-
import {RequestError} from './requestError.js';
|
|
19
|
-
import {inspect, getBlock} from '../../util/trace.js';
|
|
20
|
-
import {errorToString} from '../../util/errorToString.js';
|
|
21
|
-
import {sanitizeProcName} from './procedureSanitize.js';
|
|
22
|
-
import {OWAPageStream} from './owaPageStream.js';
|
|
23
|
-
import {traceManager} from '../../util/traceManager.js';
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* @typedef {import('../../admin/js/types.js').TraceEntry} TraceEntry
|
|
27
|
-
*/
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* @typedef {import('express').Request} Request
|
|
31
|
-
* @typedef {import('express').Response} Response
|
|
32
|
-
* @typedef {import('oracledb').Connection} Connection
|
|
33
|
-
* @typedef {import('oracledb').Result<unknown>} Result
|
|
34
|
-
* @typedef {import('../../types.js').argObjType} argObjType
|
|
35
|
-
* @typedef {import('../../types.js').fileUploadType} fileUploadType
|
|
36
|
-
* @typedef {import('../../types.js').environmentType} environmentType
|
|
37
|
-
* @typedef {import('../../types.js').configPlSqlHandlerType} configPlSqlHandlerType
|
|
38
|
-
* @typedef {import('../../types.js').BindParameterConfig} BindParameterConfig
|
|
39
|
-
* @typedef {import('../../util/cache.js').Cache<string>} ProcedureNameCache
|
|
40
|
-
* @typedef {import('../../util/cache.js').Cache<import('./procedureNamed.js').argsType>} ArgumentCache
|
|
41
|
-
*/
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Get the procedure and arguments to execute
|
|
45
|
-
* @param {Request} req - The req object represents the HTTP request. (only used for debugging)
|
|
46
|
-
* @param {string} procName - The procedure to execute
|
|
47
|
-
* @param {argObjType} argObj - The arguments to pass to the procedure
|
|
48
|
-
* @param {configPlSqlHandlerType} options - The options for the middleware
|
|
49
|
-
* @param {Connection} databaseConnection - The database connection
|
|
50
|
-
* @param {ProcedureNameCache} procedureNameCache - The procedure name cache.
|
|
51
|
-
* @param {ArgumentCache} argumentCache - The argument cache.
|
|
52
|
-
* @returns {Promise<{sql: string; bind: BindParameterConfig; resolvedName?: string}>} - The SQL statement and bindings for the procedure to execute
|
|
53
|
-
*/
|
|
54
|
-
const getProcedure = async (req, procName, argObj, options, databaseConnection, procedureNameCache, argumentCache) => {
|
|
55
|
-
// path alias
|
|
56
|
-
if (options.pathAlias?.toLowerCase() === procName.toLowerCase()) {
|
|
57
|
-
/* v8 ignore start */
|
|
58
|
-
debug(`getProcedure: path alias "${options.pathAlias}" redirects to "${options.pathAliasProcedure}"`);
|
|
59
|
-
/* v8 ignore stop */
|
|
60
|
-
return {
|
|
61
|
-
sql: `${options.pathAliasProcedure}(p_path=>:p_path)`,
|
|
62
|
-
bind: {
|
|
63
|
-
p_path: {dir: oracledb.BIND_IN, type: oracledb.STRING, val: procName},
|
|
64
|
-
},
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// check if we use variable arguments
|
|
69
|
-
const useVariableArguments = procName.startsWith('!');
|
|
70
|
-
|
|
71
|
-
// sanitize procedure name
|
|
72
|
-
const rawName = useVariableArguments ? procName.substring(1) : procName;
|
|
73
|
-
const sanitizedProcName = await sanitizeProcName(rawName, databaseConnection, options, procedureNameCache);
|
|
74
|
-
|
|
75
|
-
// run procedure
|
|
76
|
-
if (useVariableArguments) {
|
|
77
|
-
return {
|
|
78
|
-
...getProcedureVariable(req, sanitizedProcName, argObj),
|
|
79
|
-
resolvedName: sanitizedProcName,
|
|
80
|
-
};
|
|
81
|
-
} else {
|
|
82
|
-
return {
|
|
83
|
-
...(await getProcedureNamed(req, sanitizedProcName, argObj, databaseConnection, argumentCache)),
|
|
84
|
-
resolvedName: sanitizedProcName,
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Prepare procedure
|
|
91
|
-
*
|
|
92
|
-
* NOTE:
|
|
93
|
-
* 1) dbms_session.modify_package_state(dbms_session.reinitialize) is used to ensure a stateless environment by resetting package state (dbms_session.reset_package)
|
|
94
|
-
*
|
|
95
|
-
* @param {environmentType} cgiObj - The cgi of the procedure to invoke.
|
|
96
|
-
* @param {Connection} databaseConnection - Database connection.
|
|
97
|
-
* @returns {Promise<void>} Promise resolving to void.
|
|
98
|
-
*/
|
|
99
|
-
const procedurePrepare = async (cgiObj, databaseConnection) => {
|
|
100
|
-
let sqlStatement = 'BEGIN dbms_session.modify_package_state(dbms_session.reinitialize); END;';
|
|
101
|
-
try {
|
|
102
|
-
await databaseConnection.execute(sqlStatement);
|
|
103
|
-
} catch (err) {
|
|
104
|
-
throw new ProcedureError(`procedurePrepare: error when preparing procedure\n${errorToString(err)}`, cgiObj, sqlStatement, {});
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// htbuf_len: reduce this limit based on your worst-case character size.
|
|
108
|
-
// For most character sets, this will be 2 bytes per character, so the limit would be 127.
|
|
109
|
-
// For UTF8 Unicode, it's 3 bytes per character, meaning the limit should be 85.
|
|
110
|
-
// For the newer AL32UTF8 Unicode, it's 4 bytes per character, and the limit should be 63.
|
|
111
|
-
sqlStatement = 'BEGIN owa.init_cgi_env(:cgicount, :cginames, :cgivalues); htp.init; htp.htbuf_len := 63; END;';
|
|
112
|
-
/** @type {BindParameterConfig} */
|
|
113
|
-
const bindParameter = {
|
|
114
|
-
cgicount: {dir: oracledb.BIND_IN, type: oracledb.NUMBER, val: Object.keys(cgiObj).length},
|
|
115
|
-
cginames: {dir: oracledb.BIND_IN, type: oracledb.STRING, val: Object.keys(cgiObj)},
|
|
116
|
-
cgivalues: {dir: oracledb.BIND_IN, type: oracledb.STRING, val: Object.values(cgiObj)},
|
|
117
|
-
};
|
|
118
|
-
try {
|
|
119
|
-
await databaseConnection.execute(sqlStatement, bindParameter);
|
|
120
|
-
} catch (err) {
|
|
121
|
-
throw new ProcedureError(`procedurePrepare: error when preparing procedure\n${errorToString(err)}`, cgiObj, sqlStatement, bindParameter);
|
|
122
|
-
}
|
|
123
|
-
};
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* Execute procedure
|
|
127
|
-
*
|
|
128
|
-
* @param {{sql: string; bind: BindParameterConfig}} para - The statement and binding to use when executing the procedure.
|
|
129
|
-
* @param {Connection} databaseConnection - Database connection.
|
|
130
|
-
* @returns {Promise<void>} Promise resolving to void.
|
|
131
|
-
*/
|
|
132
|
-
const procedureExecute = async (para, databaseConnection) => {
|
|
133
|
-
const sqlStatement = `BEGIN ${para.sql}; END;`;
|
|
134
|
-
|
|
135
|
-
try {
|
|
136
|
-
await databaseConnection.execute(sqlStatement, para.bind);
|
|
137
|
-
} catch (err) {
|
|
138
|
-
throw new ProcedureError(`procedureExecute: error when executing procedure:\n${sqlStatement}\n${errorToString(err)}`, {}, para.sql, para.bind);
|
|
139
|
-
}
|
|
140
|
-
};
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* Download files from procedure
|
|
144
|
-
*
|
|
145
|
-
* @param {oracledb.Lob} fileBlob - The blob eventually containing the file.
|
|
146
|
-
* @param {Connection} databaseConnection - Database connection.
|
|
147
|
-
* @returns {Promise<{fileType: string, fileSize: number, fileBlob: stream.Readable | null}>} Promise resolving to the result.
|
|
148
|
-
*/
|
|
149
|
-
const procedureDownloadFiles = async (fileBlob, databaseConnection) => {
|
|
150
|
-
/** @type {BindParameterConfig} */
|
|
151
|
-
const bindParameter = {
|
|
152
|
-
fileType: {dir: oracledb.BIND_OUT, type: oracledb.STRING},
|
|
153
|
-
fileSize: {dir: oracledb.BIND_OUT, type: oracledb.NUMBER},
|
|
154
|
-
fileBlob: {dir: oracledb.BIND_INOUT, type: oracledb.BLOB, val: fileBlob},
|
|
155
|
-
};
|
|
156
|
-
|
|
157
|
-
const sqlStatement = `
|
|
158
|
-
DECLARE
|
|
159
|
-
l_file_type VARCHAR2(32767) := '';
|
|
160
|
-
l_file_size INTEGER := 0;
|
|
161
|
-
BEGIN
|
|
162
|
-
IF (wpg_docload.is_file_download()) THEN
|
|
163
|
-
wpg_docload.get_download_file(l_file_type);
|
|
164
|
-
IF (l_file_type = 'B') THEN
|
|
165
|
-
wpg_docload.get_download_blob(:fileBlob);
|
|
166
|
-
l_file_size := dbms_lob.getlength(:fileBlob);
|
|
167
|
-
END IF;
|
|
168
|
-
END IF;
|
|
169
|
-
:fileType := l_file_type;
|
|
170
|
-
:fileSize := l_file_size;
|
|
171
|
-
END;
|
|
172
|
-
`;
|
|
173
|
-
|
|
174
|
-
/** @type {Result | null} */
|
|
175
|
-
let result = null;
|
|
176
|
-
try {
|
|
177
|
-
result = await databaseConnection.execute(sqlStatement, bindParameter);
|
|
178
|
-
} catch (err) {
|
|
179
|
-
/* v8 ignore start */
|
|
180
|
-
if (debug.enabled) {
|
|
181
|
-
debug(getBlock('procedureDownloadFiles: results', inspect(result)));
|
|
182
|
-
}
|
|
183
|
-
/* v8 ignore stop */
|
|
184
|
-
|
|
185
|
-
throw new ProcedureError(`procedureDownloadFiles: error when downloading files\n${errorToString(err)}`, {}, sqlStatement, bindParameter);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
return z
|
|
189
|
-
.object({
|
|
190
|
-
fileType: z
|
|
191
|
-
.string()
|
|
192
|
-
.nullable()
|
|
193
|
-
.transform((val) => val ?? ''),
|
|
194
|
-
fileSize: z
|
|
195
|
-
.number()
|
|
196
|
-
.nullable()
|
|
197
|
-
.transform((val) => val ?? 0),
|
|
198
|
-
fileBlob: z.instanceof(stream.Readable).nullable(),
|
|
199
|
-
})
|
|
200
|
-
.parse(result.outBinds);
|
|
201
|
-
};
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* Invoke the Oracle procedure and return the page content
|
|
205
|
-
*
|
|
206
|
-
* @param {Request} req - The req object represents the HTTP request.
|
|
207
|
-
* @param {Response} res - The res object represents the HTTP response that an Express app sends when it gets an HTTP request.
|
|
208
|
-
* @param {argObjType} argObj - - The arguments of the procedure to invoke.
|
|
209
|
-
* @param {environmentType} cgiObj - The cgi of the procedure to invoke.
|
|
210
|
-
* @param {fileUploadType[]} filesToUpload - Array of files to be uploaded
|
|
211
|
-
* @param {configPlSqlHandlerType} options - the options for the middleware.
|
|
212
|
-
* @param {Connection} databaseConnection - Database connection.
|
|
213
|
-
* @param {ProcedureNameCache} procedureNameCache - The procedure name cache.
|
|
214
|
-
* @param {ArgumentCache} argumentCache - The argument cache.
|
|
215
|
-
* @returns {Promise<void>} Promise resolving to the page content generated by the executed procedure
|
|
216
|
-
*/
|
|
217
|
-
export const invokeProcedure = async (req, res, argObj, cgiObj, filesToUpload, options, databaseConnection, procedureNameCache, argumentCache) => {
|
|
218
|
-
debug('invokeProcedure: begin');
|
|
219
|
-
|
|
220
|
-
const startTime = Date.now();
|
|
221
|
-
/** @type {TraceEntry | null} */
|
|
222
|
-
let traceData = null;
|
|
223
|
-
|
|
224
|
-
if (traceManager.isEnabled()) {
|
|
225
|
-
traceData = {
|
|
226
|
-
id: Math.random().toString(36).substring(2, 15),
|
|
227
|
-
timestamp: new Date().toISOString(),
|
|
228
|
-
source: cgiObj.REMOTE_ADDR ?? '',
|
|
229
|
-
url: req.originalUrl,
|
|
230
|
-
method: req.method,
|
|
231
|
-
status: 'pending',
|
|
232
|
-
duration: 0,
|
|
233
|
-
cgi: cgiObj,
|
|
234
|
-
headers: /** @type {Record<string, string>} */ (req.headers),
|
|
235
|
-
cookies: req.cookies,
|
|
236
|
-
uploads: filesToUpload.map((f) => ({
|
|
237
|
-
originalname: f.originalname,
|
|
238
|
-
mimetype: f.mimetype,
|
|
239
|
-
size: f.size,
|
|
240
|
-
})),
|
|
241
|
-
};
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
try {
|
|
245
|
-
// 1) upload files
|
|
246
|
-
debug(`invokeProcedure: upload "${filesToUpload.length}" files`);
|
|
247
|
-
if (filesToUpload.length > 0) {
|
|
248
|
-
if (typeof options.documentTable === 'string' && options.documentTable.length > 0) {
|
|
249
|
-
const {documentTable} = options;
|
|
250
|
-
|
|
251
|
-
await Promise.all(filesToUpload.map((file) => uploadFile(file, documentTable, databaseConnection)));
|
|
252
|
-
} else {
|
|
253
|
-
console.warn(`Unable to upload "${filesToUpload.length}" files because the option ""doctable" has not been defined`);
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
// 2) get procedure to execute and the arguments
|
|
258
|
-
|
|
259
|
-
debug('invokeProcedure: get procedure to execute and the arguments');
|
|
260
|
-
// Extract the raw procedure name from params
|
|
261
|
-
const rawProcName = Array.isArray(req.params.name) ? req.params.name[0] : req.params.name;
|
|
262
|
-
if (!rawProcName) {
|
|
263
|
-
throw new RequestError('No procedure name provided');
|
|
264
|
-
}
|
|
265
|
-
const para = await getProcedure(req, rawProcName, argObj, options, databaseConnection, procedureNameCache, argumentCache);
|
|
266
|
-
|
|
267
|
-
if (traceData) {
|
|
268
|
-
traceData.procedure = para.resolvedName;
|
|
269
|
-
traceData.parameters = para.bind;
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
// 3) prepare the session
|
|
273
|
-
|
|
274
|
-
debug('invokeProcedure: prepare the session');
|
|
275
|
-
await procedurePrepare(cgiObj, databaseConnection);
|
|
276
|
-
|
|
277
|
-
// 4) execute the procedure
|
|
278
|
-
|
|
279
|
-
debug('invokeProcedure: execute the session');
|
|
280
|
-
try {
|
|
281
|
-
await procedureExecute(para, databaseConnection);
|
|
282
|
-
} catch (err) {
|
|
283
|
-
// Invalidation Logic
|
|
284
|
-
if (err instanceof ProcedureError) {
|
|
285
|
-
const errorString = err.toString();
|
|
286
|
-
// Check for ORA-04068, ORA-04061, ORA-04065, ORA-06550
|
|
287
|
-
if (
|
|
288
|
-
errorString.includes('ORA-04068') ||
|
|
289
|
-
errorString.includes('ORA-04061') ||
|
|
290
|
-
errorString.includes('ORA-04065') ||
|
|
291
|
-
errorString.includes('ORA-06550')
|
|
292
|
-
) {
|
|
293
|
-
debug(`invokeProcedure: detected invalidation error (${errorString}). Clearing caches.`);
|
|
294
|
-
|
|
295
|
-
// Clear name resolution cache for the input name
|
|
296
|
-
if (rawProcName) {
|
|
297
|
-
procedureNameCache.delete(rawProcName);
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
// Clear argument cache for the resolved name
|
|
301
|
-
if (para.resolvedName) {
|
|
302
|
-
argumentCache.delete(para.resolvedName.toUpperCase());
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
throw err;
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
// 5) get the page returned from the procedure
|
|
310
|
-
debug('invokeProcedure: get the page returned from the procedure');
|
|
311
|
-
|
|
312
|
-
const streamInstance = new OWAPageStream(databaseConnection);
|
|
313
|
-
const lines = await streamInstance.fetchChunk();
|
|
314
|
-
|
|
315
|
-
/* v8 ignore start */
|
|
316
|
-
if (debug.enabled) {
|
|
317
|
-
debug(getBlock('data', lines.join('')));
|
|
318
|
-
}
|
|
319
|
-
/* v8 ignore stop */
|
|
320
|
-
|
|
321
|
-
// 6) download files
|
|
322
|
-
|
|
323
|
-
debug('invokeProcedure: download files');
|
|
324
|
-
const fileBlob = await databaseConnection.createLob(oracledb.BLOB);
|
|
325
|
-
|
|
326
|
-
try {
|
|
327
|
-
const fileDownload = await procedureDownloadFiles(fileBlob, databaseConnection);
|
|
328
|
-
/* v8 ignore start */
|
|
329
|
-
if (debug.enabled) {
|
|
330
|
-
debug(getBlock('fileDownload', inspect({fileType: fileDownload.fileType, fileSize: fileDownload.fileSize})));
|
|
331
|
-
}
|
|
332
|
-
/* v8 ignore stop */
|
|
333
|
-
|
|
334
|
-
// 7) parse the page
|
|
335
|
-
|
|
336
|
-
debug('invokeProcedure: parse the page');
|
|
337
|
-
// We parse the headers from the first chunk
|
|
338
|
-
const pageComponents = parsePage(lines.join(''));
|
|
339
|
-
|
|
340
|
-
// add "Server" header
|
|
341
|
-
pageComponents.head.server = cgiObj.SERVER_SOFTWARE ?? '';
|
|
342
|
-
|
|
343
|
-
// add file download information
|
|
344
|
-
if (fileDownload.fileType !== '' && fileDownload.fileSize > 0 && fileDownload.fileBlob !== null) {
|
|
345
|
-
pageComponents.file.fileType = fileDownload.fileType;
|
|
346
|
-
pageComponents.file.fileSize = fileDownload.fileSize;
|
|
347
|
-
pageComponents.file.fileBlob = fileDownload.fileBlob;
|
|
348
|
-
|
|
349
|
-
if (traceData) {
|
|
350
|
-
traceData.downloads = {
|
|
351
|
-
fileType: fileDownload.fileType,
|
|
352
|
-
fileSize: fileDownload.fileSize,
|
|
353
|
-
};
|
|
354
|
-
}
|
|
355
|
-
} else {
|
|
356
|
-
// For normal pages, we use the stream.
|
|
357
|
-
// Prepend the initial body (parsed by parsePage) to the stream
|
|
358
|
-
if (typeof pageComponents.body === 'string' && pageComponents.body.length > 0) {
|
|
359
|
-
streamInstance.addBody(pageComponents.body);
|
|
360
|
-
}
|
|
361
|
-
// Use the stream as the body
|
|
362
|
-
pageComponents.body = streamInstance;
|
|
363
|
-
|
|
364
|
-
if (traceData) {
|
|
365
|
-
// Buffer HTML if tracing enabled
|
|
366
|
-
let htmlBuffer = typeof pageComponents.body === 'string' ? pageComponents.body : lines.join('');
|
|
367
|
-
const MAX_HTML_SIZE = 1024 * 1024; // 1MB
|
|
368
|
-
|
|
369
|
-
const originalPush = streamInstance.push.bind(streamInstance);
|
|
370
|
-
streamInstance.push = (chunk) => {
|
|
371
|
-
if (chunk !== null && htmlBuffer.length < MAX_HTML_SIZE) {
|
|
372
|
-
const str = String(chunk);
|
|
373
|
-
htmlBuffer += str;
|
|
374
|
-
if (htmlBuffer.length > MAX_HTML_SIZE) {
|
|
375
|
-
htmlBuffer = htmlBuffer.substring(0, MAX_HTML_SIZE) + '... [truncated]';
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
return originalPush(chunk);
|
|
379
|
-
};
|
|
380
|
-
|
|
381
|
-
// Since we can't easily wait for the stream to finish here without blocking,
|
|
382
|
-
// we'll have to finalize traceData when the stream ends.
|
|
383
|
-
const currentTrace = traceData;
|
|
384
|
-
streamInstance.on('end', () => {
|
|
385
|
-
currentTrace.html = htmlBuffer;
|
|
386
|
-
currentTrace.status = 'success';
|
|
387
|
-
currentTrace.duration = Date.now() - startTime;
|
|
388
|
-
traceManager.addTrace(currentTrace);
|
|
389
|
-
});
|
|
390
|
-
streamInstance.on('error', (err) => {
|
|
391
|
-
currentTrace.status = 'fail';
|
|
392
|
-
currentTrace.error = err instanceof Error ? err.message : String(err);
|
|
393
|
-
currentTrace.duration = Date.now() - startTime;
|
|
394
|
-
traceManager.addTrace(currentTrace);
|
|
395
|
-
});
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
// 8) send the page to browser
|
|
400
|
-
|
|
401
|
-
debug('invokeProcedure: send the page to browser');
|
|
402
|
-
await sendResponse(req, res, pageComponents);
|
|
403
|
-
|
|
404
|
-
if (traceData?.downloads) {
|
|
405
|
-
traceData.status = 'success';
|
|
406
|
-
traceData.duration = Date.now() - startTime;
|
|
407
|
-
traceManager.addTrace(traceData);
|
|
408
|
-
}
|
|
409
|
-
} finally {
|
|
410
|
-
// 9) cleanup
|
|
411
|
-
|
|
412
|
-
debug('invokeProcedure: cleanup');
|
|
413
|
-
fileBlob.destroy();
|
|
414
|
-
}
|
|
415
|
-
} catch (err) {
|
|
416
|
-
if (traceData) {
|
|
417
|
-
traceData.status = err instanceof ProcedureError ? 'error' : 'fail';
|
|
418
|
-
traceData.error = err instanceof Error ? err.message : String(err);
|
|
419
|
-
traceData.duration = Date.now() - startTime;
|
|
420
|
-
traceManager.addTrace(traceData);
|
|
421
|
-
}
|
|
422
|
-
throw err;
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
debug('invokeProcedure: end');
|
|
426
|
-
};
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* RequestError
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* @typedef {import('../../types.js').environmentType} environmentType
|
|
7
|
-
* @typedef {import('../../types.js').BindParameterConfig} BindParameterConfig
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
export class ProcedureError extends Error {
|
|
11
|
-
/** @type {Date} */
|
|
12
|
-
timestamp;
|
|
13
|
-
/** @type {environmentType} */
|
|
14
|
-
environment;
|
|
15
|
-
/** @type {string} */
|
|
16
|
-
sql;
|
|
17
|
-
/** @type {BindParameterConfig} */
|
|
18
|
-
bind;
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* @param {string} message - The error message.
|
|
22
|
-
* @param {environmentType} environment - The environment.
|
|
23
|
-
* @param {string} sql - The SQL to execute.
|
|
24
|
-
* @param {BindParameterConfig} bind - The bind parameters.
|
|
25
|
-
*/
|
|
26
|
-
constructor(message, environment, sql, bind) {
|
|
27
|
-
super(message);
|
|
28
|
-
|
|
29
|
-
// Maintains proper stack trace for where our error was thrown (only available on V8)
|
|
30
|
-
if (Error.captureStackTrace) {
|
|
31
|
-
Error.captureStackTrace(this, ProcedureError);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// Custom debugging information
|
|
35
|
-
this.timestamp = new Date();
|
|
36
|
-
this.environment = environment;
|
|
37
|
-
this.sql = sql;
|
|
38
|
-
this.bind = bind;
|
|
39
|
-
}
|
|
40
|
-
}
|