whatap 0.5.12 → 0.5.13
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/lib/core/agent.js
CHANGED
|
@@ -32,7 +32,9 @@ var Interceptor = require('./interceptor').Interceptor,
|
|
|
32
32
|
ScheduleObserver = require('../observers/schedule-observer').ScheduleObserver,
|
|
33
33
|
// GRpcObserver = require('../observers/grpc-observer').GRpcObserver,
|
|
34
34
|
ApolloObserver = require('../observers/apollo-server-observer').ApolloServerObserver,
|
|
35
|
-
PrismaObserver = require('../observers/prisma-observer').PrismaObserver
|
|
35
|
+
PrismaObserver = require('../observers/prisma-observer').PrismaObserver,
|
|
36
|
+
OracleObserver = require('../observers/oracle-observer').OracleObserver;
|
|
37
|
+
|
|
36
38
|
|
|
37
39
|
|
|
38
40
|
var Configuration = require('./../conf/configure'),
|
|
@@ -279,6 +281,7 @@ NodeAgent.prototype.loadObserves = function() {
|
|
|
279
281
|
// observes.push(GRpcObserver);
|
|
280
282
|
observes.push(ApolloObserver);
|
|
281
283
|
observes.push(PrismaObserver);
|
|
284
|
+
observes.push(OracleObserver);
|
|
282
285
|
|
|
283
286
|
var packageToObserve = {};
|
|
284
287
|
observes.forEach(function(observeObj) {
|
|
@@ -513,6 +513,7 @@ HttpObserver.prototype.__endTransaction = function(error, ctx, req, res) {
|
|
|
513
513
|
if(wtx.malloc < 0) { wtx.malloc = 0; }
|
|
514
514
|
wtx.originUrl = ctx.originUrl;
|
|
515
515
|
|
|
516
|
+
wtx.cipher = HashUtil.hash(ParamSecurity.key);
|
|
516
517
|
wtx.seq = ctx.txid;
|
|
517
518
|
wtx.sqlCount = ctx.sql_count;
|
|
518
519
|
wtx.sqlTime = ctx.sql_time;
|
|
@@ -0,0 +1,656 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2023 the WHATAP project authors. All rights reserved.
|
|
3
|
+
* Use of this source code is governed by a license that
|
|
4
|
+
* can be found in the LICENSE file.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
var TraceContextManager = require('../trace/trace-context-manager'),
|
|
8
|
+
ParsedSql = require('../trace/parsed-sql'),
|
|
9
|
+
SqlStepX = require('../step/sql-stepx'),
|
|
10
|
+
DBCStep = require('../step/dbc-step'),
|
|
11
|
+
ResultSetStep = require('../step/resultset-step'),
|
|
12
|
+
DataTextAgent = require('../data/datatext-agent'),
|
|
13
|
+
StatSql = require('../stat/stat-sql'),
|
|
14
|
+
MeterSql = require('../counter/meter/meter-sql'),
|
|
15
|
+
conf = require('../conf/configure'),
|
|
16
|
+
IntKeyMap = require('../util/intkey-map'),
|
|
17
|
+
EscapeLiteralSQL = require('../util/escape-literal-sql'),
|
|
18
|
+
HashUtil = require('../util/hashutil'),
|
|
19
|
+
StatError = require('../stat/stat-error'),
|
|
20
|
+
TextTypes = require('../lang/text-types'),
|
|
21
|
+
ParamSecurity = require('../util/paramsecurity'),
|
|
22
|
+
Logger = require('../logger'),
|
|
23
|
+
DateUtil = require('../util/dateutil'),
|
|
24
|
+
Buffer = require('buffer').Buffer,
|
|
25
|
+
TraceSQL = require('../trace/trace-sql');
|
|
26
|
+
var shimmer = require('../core/shimmer');
|
|
27
|
+
|
|
28
|
+
// Store connection info for reuse
|
|
29
|
+
var connectionAttributes = new WeakMap();
|
|
30
|
+
var poolAttributes = new WeakMap();
|
|
31
|
+
|
|
32
|
+
var OracleObserver = function (agent) {
|
|
33
|
+
this.agent = agent;
|
|
34
|
+
this.packages = ['oracledb'];
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
// 쿼리 파라미터를 바이트 배열로 변환
|
|
38
|
+
var toParamBytes = function (p, crc) {
|
|
39
|
+
if (p == null || p.length === 0) {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
try {
|
|
43
|
+
return ParamSecurity.encrypt(Buffer.from(p, 'utf8'), crc);
|
|
44
|
+
} catch (e) {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
var errorDelegate = function (ctx, step) {
|
|
50
|
+
return function (obj, args) {
|
|
51
|
+
if (ctx == null) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (step == null) {
|
|
56
|
+
var laststep = ctx.profile.getLastSteps(1);
|
|
57
|
+
if (laststep == null || laststep.length === 0) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
step = laststep[0];
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
MeterSql.add(step.dbc, step.elapsed, true);
|
|
64
|
+
StatSql.addSqlTime(ctx.service_hash, step.dbc, step.hash, step.elapsed, true, 0);
|
|
65
|
+
|
|
66
|
+
try {
|
|
67
|
+
var errorCode = args[0].errorNum || args[0].code || 'ORA-00000';
|
|
68
|
+
var errorMsg = args[0].message || 'Oracle error';
|
|
69
|
+
|
|
70
|
+
if (conf._is_trace_ignore_err_cls_contains === true && errorCode.toString().indexOf(conf.trace_ignore_err_cls_contains) < 0) {
|
|
71
|
+
step.error = StatError.addError('oracle-' + errorCode, errorMsg, ctx.service_hash, TextTypes.SQL, step.hash);
|
|
72
|
+
if (ctx.error.isZero()) {
|
|
73
|
+
ctx.error = step.error;
|
|
74
|
+
}
|
|
75
|
+
} else if (conf._is_trace_ignore_err_msg_contains === true && errorMsg.indexOf(conf.trace_ignore_err_msg_contains) < 0) {
|
|
76
|
+
step.error = StatError.addError('oracle-' + errorCode, errorMsg, ctx.service_hash, TextTypes.SQL, step.hash);
|
|
77
|
+
if (ctx.error.isZero()) {
|
|
78
|
+
ctx.error = step.error;
|
|
79
|
+
}
|
|
80
|
+
} else if (conf._is_trace_ignore_err_cls_contains === false && conf._is_trace_ignore_err_msg_contains === false) {
|
|
81
|
+
step.error = StatError.addError('oracle-' + errorCode, errorMsg, ctx.service_hash, TextTypes.SQL, step.hash);
|
|
82
|
+
if (ctx.error.isZero()) {
|
|
83
|
+
ctx.error = step.error;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (conf.trace_sql_error_stack && conf.trace_sql_error_depth) {
|
|
88
|
+
var traceDepth = conf.trace_sql_error_depth;
|
|
89
|
+
if (args[0].stack) {
|
|
90
|
+
var errorStack = args[0].stack.split("\n");
|
|
91
|
+
if (errorStack.length > traceDepth) {
|
|
92
|
+
errorStack = errorStack.slice(0, traceDepth + 1);
|
|
93
|
+
}
|
|
94
|
+
ctx.error_message = errorStack.join("\n");
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
} catch (e) {
|
|
98
|
+
Logger.printError('WHATAP-110', 'OracleObserver error delegate exception', e, false);
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
// 커넥션 풀 관리 함수
|
|
104
|
+
OracleObserver.prototype._wrapPoolOrConnection = function (obj, dbc) {
|
|
105
|
+
var self = this;
|
|
106
|
+
|
|
107
|
+
if (obj.__whatap_observed) {
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
obj.__whatap_observed = true;
|
|
111
|
+
|
|
112
|
+
// execute 메소드 래핑
|
|
113
|
+
if (obj.execute && typeof obj.execute === 'function') {
|
|
114
|
+
shimmer.wrap(obj, 'execute', function (original) {
|
|
115
|
+
return function () {
|
|
116
|
+
var ctx = TraceContextManager.getCurrentContext();
|
|
117
|
+
var args = Array.from(arguments);
|
|
118
|
+
|
|
119
|
+
if (ctx == null || args.length === 0) {
|
|
120
|
+
return original.apply(this, args);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
var sql = args[0];
|
|
124
|
+
if (sql == null) {
|
|
125
|
+
return original.apply(this, args);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// DBC 단계 생성
|
|
129
|
+
var dbc_hash = HashUtil.hashFromString(dbc);
|
|
130
|
+
|
|
131
|
+
// SQL 단계 생성
|
|
132
|
+
var sql_step = new SqlStepX();
|
|
133
|
+
sql_step.start_time = ctx.getElapsedTime();
|
|
134
|
+
ctx.profile.push(sql_step);
|
|
135
|
+
|
|
136
|
+
ctx.footprint('Oracle Query Start');
|
|
137
|
+
ctx.sql_count++;
|
|
138
|
+
|
|
139
|
+
var psql = null;
|
|
140
|
+
if (typeof sql === 'string' && sql.length > 0) {
|
|
141
|
+
try {
|
|
142
|
+
psql = escapeLiteral(sql);
|
|
143
|
+
} catch (e) {
|
|
144
|
+
Logger.printError('WHATAP-111', 'OracleObserver escapeliteral error', e, false);
|
|
145
|
+
}
|
|
146
|
+
} else {
|
|
147
|
+
sql = '';
|
|
148
|
+
psql = escapeLiteral(sql);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (psql != null) {
|
|
152
|
+
sql_step.hash = psql.sql;
|
|
153
|
+
// sql_step.crud = psql.type.charCodeAt(0);
|
|
154
|
+
}
|
|
155
|
+
sql_step.dbc = dbc_hash;
|
|
156
|
+
|
|
157
|
+
var els = new EscapeLiteralSQL(sql);
|
|
158
|
+
els.process();
|
|
159
|
+
|
|
160
|
+
ctx.active_sqlhash = sql_step.hash;
|
|
161
|
+
ctx.active_dbc = sql_step.dbc;
|
|
162
|
+
//ctx.active_crud = sql_step.crud;
|
|
163
|
+
|
|
164
|
+
// 파라미터 처리
|
|
165
|
+
if (conf.profile_sql_param_enabled) {
|
|
166
|
+
var params = args.length > 1 ? args[1] : undefined;
|
|
167
|
+
if (params) {
|
|
168
|
+
sql_step.setTrue(1);
|
|
169
|
+
var crc = {value: 0};
|
|
170
|
+
sql_step.p1 = toParamBytes(psql.param, crc);
|
|
171
|
+
|
|
172
|
+
if (params != undefined) {
|
|
173
|
+
try {
|
|
174
|
+
// Oracle 파라미터는 객체 형태일 수 있음
|
|
175
|
+
let paramStr = '';
|
|
176
|
+
if (typeof params === 'object' && !Array.isArray(params)) {
|
|
177
|
+
paramStr = Object.entries(params).map(([key, value]) => {
|
|
178
|
+
if (typeof value === 'string') {
|
|
179
|
+
return `${key}='${value}'`;
|
|
180
|
+
}
|
|
181
|
+
return `${key}=${value}`;
|
|
182
|
+
}).join(', ');
|
|
183
|
+
} else if (Array.isArray(params)) {
|
|
184
|
+
paramStr = params.map((param) => {
|
|
185
|
+
if (typeof param === 'string') {
|
|
186
|
+
return `'${param}'`;
|
|
187
|
+
}
|
|
188
|
+
return param;
|
|
189
|
+
}).join(', ');
|
|
190
|
+
} else {
|
|
191
|
+
paramStr = String(params);
|
|
192
|
+
}
|
|
193
|
+
sql_step.p2 = toParamBytes(paramStr, crc);
|
|
194
|
+
} catch (e) {
|
|
195
|
+
Logger.printError('WHATAP-112', 'Oracle param processing error', e, false);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
sql_step.pcrc = crc.value;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Check if the last argument is a callback
|
|
203
|
+
var hasCallback = false;
|
|
204
|
+
var callbackIndex = -1;
|
|
205
|
+
|
|
206
|
+
if (args.length > 0 && typeof args[args.length - 1] === 'function') {
|
|
207
|
+
hasCallback = true;
|
|
208
|
+
callbackIndex = args.length - 1;
|
|
209
|
+
|
|
210
|
+
// Wrap callback to capture result
|
|
211
|
+
var originalCallback = args[callbackIndex];
|
|
212
|
+
args[callbackIndex] = function wrappedCallback(err, result) {
|
|
213
|
+
if (ctx == null) {
|
|
214
|
+
return originalCallback.apply(this, arguments);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
TraceContextManager.resume(ctx._id);
|
|
218
|
+
|
|
219
|
+
sql_step.elapsed = ctx.getElapsedTime() - sql_step.start_time;
|
|
220
|
+
ctx.sql_time += sql_step.elapsed;
|
|
221
|
+
|
|
222
|
+
if (err) {
|
|
223
|
+
errorDelegate(ctx, sql_step)(null, [err]);
|
|
224
|
+
ctx.footprint('Oracle Query Error');
|
|
225
|
+
} else {
|
|
226
|
+
ctx.footprint('Oracle Query Done');
|
|
227
|
+
|
|
228
|
+
// Process result for SELECT queries
|
|
229
|
+
if (result && result.rows && Array.isArray(result.rows) && psql != null && psql.type === 'S') {
|
|
230
|
+
var result_step = new ResultSetStep();
|
|
231
|
+
result_step.start_time = ctx.getElapsedTime();
|
|
232
|
+
result_step.elapsed = 0;
|
|
233
|
+
result_step.fetch = result.rows.length;
|
|
234
|
+
result_step.sqlhash = psql.sql;
|
|
235
|
+
result_step.dbc = dbc_hash;
|
|
236
|
+
ctx.profile.push(result_step);
|
|
237
|
+
|
|
238
|
+
ctx.rs_count = ctx.rs_count ? ctx.rs_count + result.rows.length : result.rows.length;
|
|
239
|
+
ctx.rs_time = ctx.rs_time ? ctx.rs_time + sql_step.elapsed : sql_step.elapsed;
|
|
240
|
+
|
|
241
|
+
MeterSql.addFetch(result_step.dbc, result_step.fetch, 0);
|
|
242
|
+
StatSql.addFetch(result_step.dbc, result_step.sqlhash, result_step.fetch, 0);
|
|
243
|
+
|
|
244
|
+
TraceSQL.isTooManyRecords(sql_step, result_step.fetch, ctx);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Process affectedRows for UPDATE/INSERT/DELETE
|
|
248
|
+
if (result != null && psql != null && (psql.type === 'U' || psql.type === 'I' || psql.type === 'D')) {
|
|
249
|
+
if (result.rowsAffected !== undefined) {
|
|
250
|
+
sql_step.updated = result.rowsAffected || 0;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
MeterSql.add(dbc_hash, sql_step.elapsed, !!err);
|
|
256
|
+
StatSql.addSqlTime(ctx.service_hash, sql_step.dbc,
|
|
257
|
+
sql_step.hash, sql_step.elapsed, !!err, 0);
|
|
258
|
+
|
|
259
|
+
return originalCallback.apply(this, arguments);
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
try {
|
|
264
|
+
// Handle promise-based execution
|
|
265
|
+
if (!hasCallback) {
|
|
266
|
+
return original.apply(this, args)
|
|
267
|
+
.then(function (result) {
|
|
268
|
+
// 성공 처리
|
|
269
|
+
if (ctx == null) {
|
|
270
|
+
return result;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
TraceContextManager.resume(ctx._id);
|
|
274
|
+
|
|
275
|
+
sql_step.elapsed = ctx.getElapsedTime() - sql_step.start_time;
|
|
276
|
+
ctx.sql_time += sql_step.elapsed;
|
|
277
|
+
|
|
278
|
+
TraceSQL.isSlowSQL(ctx);
|
|
279
|
+
|
|
280
|
+
ctx.footprint('Oracle Query Done');
|
|
281
|
+
|
|
282
|
+
MeterSql.add(dbc_hash, sql_step.elapsed, false);
|
|
283
|
+
StatSql.addSqlTime(ctx.service_hash, sql_step.dbc,
|
|
284
|
+
sql_step.hash, sql_step.elapsed, false, 0);
|
|
285
|
+
|
|
286
|
+
if (result && result.rows && Array.isArray(result.rows) && psql != null && psql.type === 'S') {
|
|
287
|
+
var result_step = new ResultSetStep();
|
|
288
|
+
result_step.start_time = ctx.getElapsedTime();
|
|
289
|
+
result_step.elapsed = 0;
|
|
290
|
+
result_step.fetch = result.rows.length;
|
|
291
|
+
result_step.sqlhash = psql.sql;
|
|
292
|
+
result_step.dbc = dbc_hash;
|
|
293
|
+
ctx.profile.push(result_step);
|
|
294
|
+
|
|
295
|
+
ctx.rs_count = ctx.rs_count ? ctx.rs_count + result.rows.length : result.rows.length;
|
|
296
|
+
ctx.rs_time = ctx.rs_time ? ctx.rs_time + sql_step.elapsed : sql_step.elapsed;
|
|
297
|
+
|
|
298
|
+
MeterSql.addFetch(result_step.dbc, result_step.fetch, 0);
|
|
299
|
+
StatSql.addFetch(result_step.dbc, result_step.sqlhash, result_step.fetch, 0);
|
|
300
|
+
|
|
301
|
+
TraceSQL.isTooManyRecords(sql_step, result_step.fetch, ctx);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
if (result != null && psql != null && (psql.type === 'U' || psql.type === 'I' || psql.type === 'D')) {
|
|
305
|
+
if (result.rowsAffected !== undefined) {
|
|
306
|
+
sql_step.updated = result.rowsAffected || 0;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
return result;
|
|
311
|
+
})
|
|
312
|
+
.catch(function (error) {
|
|
313
|
+
if (ctx == null) {
|
|
314
|
+
throw error;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
TraceContextManager.resume(ctx._id);
|
|
318
|
+
errorDelegate(ctx, sql_step)(null, [error]);
|
|
319
|
+
|
|
320
|
+
sql_step.elapsed = ctx.getElapsedTime() - sql_step.start_time;
|
|
321
|
+
ctx.sql_time += sql_step.elapsed;
|
|
322
|
+
|
|
323
|
+
ctx.footprint('Oracle Query Error');
|
|
324
|
+
|
|
325
|
+
MeterSql.add(dbc_hash, sql_step.elapsed, true);
|
|
326
|
+
StatSql.addSqlTime(ctx.service_hash, sql_step.dbc,
|
|
327
|
+
sql_step.hash, sql_step.elapsed, true, 0);
|
|
328
|
+
|
|
329
|
+
throw error;
|
|
330
|
+
});
|
|
331
|
+
} else {
|
|
332
|
+
return original.apply(this, args);
|
|
333
|
+
}
|
|
334
|
+
} catch (err) {
|
|
335
|
+
if (ctx != null) {
|
|
336
|
+
errorDelegate(ctx, sql_step)(null, [err]);
|
|
337
|
+
sql_step.elapsed = ctx.getElapsedTime() - sql_step.start_time;
|
|
338
|
+
ctx.sql_time += sql_step.elapsed;
|
|
339
|
+
ctx.footprint('Oracle Query Error');
|
|
340
|
+
|
|
341
|
+
MeterSql.add(dbc_hash, sql_step.elapsed, true);
|
|
342
|
+
StatSql.addSqlTime(ctx.service_hash, sql_step.dbc,
|
|
343
|
+
sql_step.hash, sql_step.elapsed, true, 0);
|
|
344
|
+
}
|
|
345
|
+
throw err;
|
|
346
|
+
}
|
|
347
|
+
};
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
};
|
|
351
|
+
|
|
352
|
+
OracleObserver.prototype.inject = function (mod, moduleName) {
|
|
353
|
+
if (mod.__whatap_observe__) {
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
mod.__whatap_observe__ = true;
|
|
357
|
+
Logger.initPrint("OracleObserver");
|
|
358
|
+
|
|
359
|
+
var self = this;
|
|
360
|
+
|
|
361
|
+
if (conf.sql_enabled === false) {
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
shimmer.wrap(mod, 'getConnection', function (original) {
|
|
366
|
+
return function () {
|
|
367
|
+
var args = Array.from(arguments);
|
|
368
|
+
var connectionInfo = args[0] || {};
|
|
369
|
+
var ctx = TraceContextManager.getCurrentContext();
|
|
370
|
+
|
|
371
|
+
var connectInfo = connectionInfo.connectString || connectionInfo.connectionString || '';
|
|
372
|
+
var user = connectionInfo.user || '';
|
|
373
|
+
var dbc = 'oracle://' + user + '@' + connectInfo;
|
|
374
|
+
var dbc_hash = HashUtil.hashFromString(dbc);
|
|
375
|
+
|
|
376
|
+
DataTextAgent.DBC.add(dbc_hash, dbc);
|
|
377
|
+
DataTextAgent.METHOD.add(dbc_hash, dbc);
|
|
378
|
+
DataTextAgent.ERROR.add(dbc_hash, dbc);
|
|
379
|
+
|
|
380
|
+
var dbc_step = null;
|
|
381
|
+
|
|
382
|
+
if (ctx) {
|
|
383
|
+
dbc_step = new DBCStep();
|
|
384
|
+
dbc_step.start_time = ctx.getElapsedTime();
|
|
385
|
+
dbc_step.hash = dbc_hash;
|
|
386
|
+
|
|
387
|
+
ctx.footprint('Oracle Connecting Start');
|
|
388
|
+
ctx.db_opening = true;
|
|
389
|
+
ctx.profile.push(dbc_step);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
if (arguments.length > 0 && typeof arguments[arguments.length - 1] === 'function') {
|
|
393
|
+
var callbackIndex = arguments.length - 1;
|
|
394
|
+
var originalCallback = arguments[callbackIndex];
|
|
395
|
+
|
|
396
|
+
arguments[callbackIndex] = function wrappedCallback(err, connection) {
|
|
397
|
+
if (ctx) {
|
|
398
|
+
TraceContextManager.resume(ctx._id);
|
|
399
|
+
|
|
400
|
+
if (err) {
|
|
401
|
+
ctx.footprint('Oracle Connecting Error');
|
|
402
|
+
if (dbc_step) {
|
|
403
|
+
dbc_step.error = StatError.addError('oracle-' + (err.errorNum || 'ERROR'),
|
|
404
|
+
err.message || 'Oracle connection error', ctx.service_hash);
|
|
405
|
+
}
|
|
406
|
+
} else {
|
|
407
|
+
ctx.footprint('Oracle Connecting Done');
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
ctx.db_opening = false;
|
|
411
|
+
|
|
412
|
+
if (dbc_step) {
|
|
413
|
+
dbc_step.elapsed = ctx.getElapsedTime() - dbc_step.start_time;
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
if (connection) {
|
|
418
|
+
connectionAttributes.set(connection, connectionInfo);
|
|
419
|
+
self._wrapPoolOrConnection(connection, dbc);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
return originalCallback.apply(this, arguments);
|
|
423
|
+
};
|
|
424
|
+
|
|
425
|
+
return original.apply(this, arguments);
|
|
426
|
+
} else {
|
|
427
|
+
return original.apply(this, args)
|
|
428
|
+
.then(function (connection) {
|
|
429
|
+
if (ctx) {
|
|
430
|
+
TraceContextManager.resume(ctx._id);
|
|
431
|
+
ctx.footprint('Oracle Connecting Done');
|
|
432
|
+
ctx.db_opening = false;
|
|
433
|
+
|
|
434
|
+
if (dbc_step) {
|
|
435
|
+
dbc_step.elapsed = ctx.getElapsedTime() - dbc_step.start_time;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
if (connection) {
|
|
440
|
+
connectionAttributes.set(connection, connectionInfo);
|
|
441
|
+
self._wrapPoolOrConnection(connection, dbc);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
return connection;
|
|
445
|
+
})
|
|
446
|
+
.catch(function (err) {
|
|
447
|
+
if (ctx) {
|
|
448
|
+
TraceContextManager.resume(ctx._id);
|
|
449
|
+
ctx.footprint('Oracle Connecting Error');
|
|
450
|
+
ctx.db_opening = false;
|
|
451
|
+
|
|
452
|
+
if (dbc_step) {
|
|
453
|
+
dbc_step.error = StatError.addError('oracle-' + (err.errorNum || 'ERROR'),
|
|
454
|
+
err.message || 'Oracle connection error', ctx.service_hash);
|
|
455
|
+
dbc_step.elapsed = ctx.getElapsedTime() - dbc_step.start_time;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
throw err;
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
};
|
|
463
|
+
});
|
|
464
|
+
|
|
465
|
+
shimmer.wrap(mod, 'createPool', function (original) {
|
|
466
|
+
return function () {
|
|
467
|
+
var args = Array.from(arguments);
|
|
468
|
+
var poolAttrs = args[0] || {};
|
|
469
|
+
|
|
470
|
+
// Handle callback-style
|
|
471
|
+
if (args.length > 0 && typeof args[args.length - 1] === 'function') {
|
|
472
|
+
var callbackIndex = args.length - 1;
|
|
473
|
+
var originalCallback = args[callbackIndex];
|
|
474
|
+
|
|
475
|
+
args[callbackIndex] = function wrappedCallback(err, pool) {
|
|
476
|
+
if (pool) {
|
|
477
|
+
poolAttributes.set(pool, poolAttrs);
|
|
478
|
+
// Wrap Pool's getConnection method after pool is created
|
|
479
|
+
shimmer.wrap(pool, 'getConnection', function(originalGetConn) {
|
|
480
|
+
return self._wrapPoolGetConnection(originalGetConn, poolAttrs);
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
return originalCallback.apply(this, arguments);
|
|
485
|
+
};
|
|
486
|
+
|
|
487
|
+
return original.apply(this, args);
|
|
488
|
+
} else {
|
|
489
|
+
return original.apply(this, args)
|
|
490
|
+
.then(function(pool) {
|
|
491
|
+
if (pool) {
|
|
492
|
+
poolAttributes.set(pool, poolAttrs);
|
|
493
|
+
shimmer.wrap(pool, 'getConnection', function(originalGetConn) {
|
|
494
|
+
return self._wrapPoolGetConnection(originalGetConn, poolAttrs);
|
|
495
|
+
});
|
|
496
|
+
}
|
|
497
|
+
return pool;
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
};
|
|
501
|
+
});
|
|
502
|
+
|
|
503
|
+
if (mod.Pool && mod.Pool.prototype) {
|
|
504
|
+
shimmer.wrap(mod.Pool.prototype, 'getConnection', function(original) {
|
|
505
|
+
return self._wrapPoolGetConnection(original);
|
|
506
|
+
});
|
|
507
|
+
}
|
|
508
|
+
};
|
|
509
|
+
|
|
510
|
+
OracleObserver.prototype._wrapPoolGetConnection = function(originalGetConn, poolAttrs) {
|
|
511
|
+
var self = this;
|
|
512
|
+
|
|
513
|
+
return function wrappedGetConnection() {
|
|
514
|
+
var args = Array.from(arguments);
|
|
515
|
+
var ctx = TraceContextManager.getCurrentContext();
|
|
516
|
+
|
|
517
|
+
var poolInfo = poolAttrs || poolAttributes.get(this) || {};
|
|
518
|
+
var connectInfo = poolInfo.connectString || poolInfo.connectionString || '';
|
|
519
|
+
var user = poolInfo.user || '';
|
|
520
|
+
var dbc = 'oracle://' + user + '@' + connectInfo;
|
|
521
|
+
var dbc_hash = HashUtil.hashFromString(dbc);
|
|
522
|
+
|
|
523
|
+
DataTextAgent.DBC.add(dbc_hash, dbc);
|
|
524
|
+
DataTextAgent.METHOD.add(dbc_hash, dbc);
|
|
525
|
+
DataTextAgent.ERROR.add(dbc_hash, dbc);
|
|
526
|
+
|
|
527
|
+
var dbc_step = null;
|
|
528
|
+
|
|
529
|
+
if (ctx) {
|
|
530
|
+
dbc_step = new DBCStep();
|
|
531
|
+
dbc_step.start_time = ctx.getElapsedTime();
|
|
532
|
+
dbc_step.hash = dbc_hash;
|
|
533
|
+
|
|
534
|
+
ctx.footprint('Oracle Pool Connection Start');
|
|
535
|
+
ctx.db_opening = true;
|
|
536
|
+
ctx.profile.push(dbc_step);
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
if (args.length > 0 && typeof args[args.length - 1] === 'function') {
|
|
540
|
+
var callbackIndex = args.length - 1;
|
|
541
|
+
var originalCallback = args[callbackIndex];
|
|
542
|
+
|
|
543
|
+
args[callbackIndex] = function(err, connection) {
|
|
544
|
+
if (ctx) {
|
|
545
|
+
TraceContextManager.resume(ctx._id);
|
|
546
|
+
|
|
547
|
+
if (err) {
|
|
548
|
+
ctx.footprint('Oracle Pool Connection Error');
|
|
549
|
+
if (dbc_step) {
|
|
550
|
+
dbc_step.error = StatError.addError('oracle-' + (err.errorNum || 'ERROR'),
|
|
551
|
+
err.message || 'Oracle connection error', ctx.service_hash);
|
|
552
|
+
}
|
|
553
|
+
} else {
|
|
554
|
+
ctx.footprint('Oracle Pool Connection Done');
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
ctx.db_opening = false;
|
|
558
|
+
|
|
559
|
+
if (dbc_step) {
|
|
560
|
+
dbc_step.elapsed = ctx.getElapsedTime() - dbc_step.start_time;
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
if (connection) {
|
|
565
|
+
connectionAttributes.set(connection, poolInfo);
|
|
566
|
+
self._wrapPoolOrConnection(connection, dbc);
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
return originalCallback.apply(this, arguments);
|
|
570
|
+
};
|
|
571
|
+
|
|
572
|
+
return originalGetConn.apply(this, args);
|
|
573
|
+
} else {
|
|
574
|
+
return originalGetConn.apply(this, args)
|
|
575
|
+
.then(function(connection) {
|
|
576
|
+
if (ctx) {
|
|
577
|
+
TraceContextManager.resume(ctx._id);
|
|
578
|
+
ctx.footprint('Oracle Pool Connection Done');
|
|
579
|
+
ctx.db_opening = false;
|
|
580
|
+
|
|
581
|
+
if (dbc_step) {
|
|
582
|
+
dbc_step.elapsed = ctx.getElapsedTime() - dbc_step.start_time;
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
if (connection) {
|
|
587
|
+
connectionAttributes.set(connection, poolInfo);
|
|
588
|
+
self._wrapPoolOrConnection(connection, dbc);
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
return connection;
|
|
592
|
+
})
|
|
593
|
+
.catch(function(err) {
|
|
594
|
+
if (ctx) {
|
|
595
|
+
TraceContextManager.resume(ctx._id);
|
|
596
|
+
ctx.footprint('Oracle Pool Connection Error');
|
|
597
|
+
ctx.db_opening = false;
|
|
598
|
+
|
|
599
|
+
if (dbc_step) {
|
|
600
|
+
dbc_step.error = StatError.addError('oracle-' + (err.errorNum || 'ERROR'),
|
|
601
|
+
err.message || 'Oracle connection error', ctx.service_hash);
|
|
602
|
+
dbc_step.elapsed = ctx.getElapsedTime() - dbc_step.start_time;
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
throw err;
|
|
607
|
+
});
|
|
608
|
+
}
|
|
609
|
+
};
|
|
610
|
+
};
|
|
611
|
+
|
|
612
|
+
var checkedSql = new IntKeyMap(2000).setMax(2000);
|
|
613
|
+
var nonLiteSql = new IntKeyMap(5000).setMax(5000);
|
|
614
|
+
var date = DateUtil.yyyymmdd();
|
|
615
|
+
|
|
616
|
+
function escapeLiteral(sql) {
|
|
617
|
+
if (sql == null) {
|
|
618
|
+
sql = '';
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
if (date !== DateUtil.yyyymmdd()) {
|
|
622
|
+
checkedSql.clear();
|
|
623
|
+
nonLiteSql.clear();
|
|
624
|
+
date = DateUtil.yyyymmdd();
|
|
625
|
+
Logger.print('WHATAP-SQL-CLEAR', 'OracleObserver CLEAR SQL Cache', false);
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
var sqlHash = HashUtil.hashFromString(sql);
|
|
629
|
+
var psql = nonLiteSql.get(sqlHash);
|
|
630
|
+
|
|
631
|
+
if (psql != null) {
|
|
632
|
+
return psql;
|
|
633
|
+
}
|
|
634
|
+
psql = checkedSql.get(sqlHash);
|
|
635
|
+
|
|
636
|
+
if (psql != null) {
|
|
637
|
+
return psql;
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
var els = new EscapeLiteralSQL(sql);
|
|
641
|
+
els.process();
|
|
642
|
+
|
|
643
|
+
var hash = HashUtil.hashFromString(els.getParsedSql());
|
|
644
|
+
DataTextAgent.SQL.add(hash, els.getParsedSql());
|
|
645
|
+
|
|
646
|
+
if (hash === sqlHash) {
|
|
647
|
+
psql = new ParsedSql(els.sqlType, hash, null);
|
|
648
|
+
nonLiteSql.put(sqlHash, psql);
|
|
649
|
+
} else {
|
|
650
|
+
psql = new ParsedSql(els.sqlType, hash, els.getParameter());
|
|
651
|
+
checkedSql.put(sqlHash, psql);
|
|
652
|
+
}
|
|
653
|
+
return psql;
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
exports.OracleObserver = OracleObserver;
|
|
@@ -365,8 +365,8 @@ PrismaObserver.prototype.hookUseMiddleware = function(prismaInstance) {
|
|
|
365
365
|
ctx.footprint(`Prisma ${modelName}.${action} Start`);
|
|
366
366
|
ctx.sql_count = (ctx.sql_count || 0) + 1;
|
|
367
367
|
|
|
368
|
-
//
|
|
369
|
-
const queryInfo = `Prisma ${
|
|
368
|
+
// Prisma 쿼리 정보 직접 사용 (SQL 변환 없이)
|
|
369
|
+
const queryInfo = `Prisma ${modelName}.${action}`;
|
|
370
370
|
const queryHash = HashUtil.hashFromString(queryInfo);
|
|
371
371
|
|
|
372
372
|
DataTextAgent.SQL.add(queryHash, queryInfo);
|
|
@@ -388,6 +388,7 @@ PrismaObserver.prototype.hookUseMiddleware = function(prismaInstance) {
|
|
|
388
388
|
try {
|
|
389
389
|
result = await next(params);
|
|
390
390
|
|
|
391
|
+
// Raw 쿼리 처리
|
|
391
392
|
if (action === "queryRaw" || action === "executeRaw" || action === "queryRawUnsafe" || action === "executeRawUnsafe") {
|
|
392
393
|
// SQL 문자열 추출
|
|
393
394
|
let sqlString = "";
|
|
@@ -408,10 +409,6 @@ PrismaObserver.prototype.hookUseMiddleware = function(prismaInstance) {
|
|
|
408
409
|
var psql = escapeLiteral(sqlString);
|
|
409
410
|
if (psql != null) {
|
|
410
411
|
sql_step.hash = psql.sql;
|
|
411
|
-
// CRUD 타입 설정 (S: Select, U: Update 등)
|
|
412
|
-
// if (psql.type) {
|
|
413
|
-
// sql_step.crud = psql.type.charCodeAt(0);
|
|
414
|
-
// }
|
|
415
412
|
}
|
|
416
413
|
|
|
417
414
|
// 추가 SQL 정보 처리
|
|
@@ -451,9 +448,8 @@ PrismaObserver.prototype.hookUseMiddleware = function(prismaInstance) {
|
|
|
451
448
|
recordCount = 1;
|
|
452
449
|
}
|
|
453
450
|
|
|
454
|
-
if
|
|
455
|
-
|
|
456
|
-
const sqlHashToUse = psql ? psql.sql : queryHash;
|
|
451
|
+
if(psql && psql.sql){
|
|
452
|
+
const sqlHashToUse = psql.sql;
|
|
457
453
|
|
|
458
454
|
var result_step = new ResultSetStep();
|
|
459
455
|
result_step.start_time = ctx.getElapsedTime();
|
|
@@ -484,23 +480,21 @@ PrismaObserver.prototype.hookUseMiddleware = function(prismaInstance) {
|
|
|
484
480
|
recordCount = 1;
|
|
485
481
|
}
|
|
486
482
|
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
ctx.profile.push(result_step);
|
|
483
|
+
var result_step = new ResultSetStep();
|
|
484
|
+
result_step.start_time = ctx.getElapsedTime();
|
|
485
|
+
result_step.elapsed = 0;
|
|
486
|
+
result_step.fetch = recordCount;
|
|
487
|
+
result_step.sqlhash = queryHash;
|
|
488
|
+
result_step.dbc = dbc_hash;
|
|
489
|
+
ctx.profile.push(result_step);
|
|
495
490
|
|
|
496
|
-
|
|
497
|
-
|
|
491
|
+
ctx.rs_count = ctx.rs_count ? ctx.rs_count + recordCount : recordCount;
|
|
492
|
+
ctx.rs_time = ctx.rs_time ? ctx.rs_time + sql_step.elapsed : sql_step.elapsed;
|
|
498
493
|
|
|
499
|
-
|
|
500
|
-
|
|
494
|
+
MeterSql.addFetch(result_step.dbc, result_step.fetch, 0);
|
|
495
|
+
StatSql.addFetch(result_step.dbc, result_step.sqlhash, result_step.fetch, 0);
|
|
501
496
|
|
|
502
|
-
|
|
503
|
-
}
|
|
497
|
+
TraceSQL.isTooManyRecords(sql_step, result_step.fetch, ctx);
|
|
504
498
|
}
|
|
505
499
|
|
|
506
500
|
// 수정된 레코드 수 처리 (create, update, delete 등)
|
|
@@ -512,252 +506,9 @@ PrismaObserver.prototype.hookUseMiddleware = function(prismaInstance) {
|
|
|
512
506
|
}
|
|
513
507
|
}
|
|
514
508
|
|
|
515
|
-
//
|
|
516
|
-
if (
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
try {
|
|
520
|
-
// 모델 메서드를 SQL 스타일로 변환
|
|
521
|
-
let sqlStyleQuery = "";
|
|
522
|
-
|
|
523
|
-
// 액션에 따라 SQL 명령 결정
|
|
524
|
-
if (action.startsWith('find')) {
|
|
525
|
-
sqlStyleQuery = "SELECT ";
|
|
526
|
-
|
|
527
|
-
// select 필드가 있는 경우 해당 필드 사용
|
|
528
|
-
if (params.args && params.args.select) {
|
|
529
|
-
const fields = Object.keys(params.args.select)
|
|
530
|
-
.filter(key => params.args.select[key] === true);
|
|
531
|
-
|
|
532
|
-
if (fields.length > 0) {
|
|
533
|
-
sqlStyleQuery += fields.join(", ");
|
|
534
|
-
} else {
|
|
535
|
-
sqlStyleQuery += "*";
|
|
536
|
-
}
|
|
537
|
-
} else {
|
|
538
|
-
sqlStyleQuery += "*";
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
sqlStyleQuery += ` FROM ${modelName}`;
|
|
542
|
-
|
|
543
|
-
// where 조건 추가
|
|
544
|
-
if (params.args && params.args.where) {
|
|
545
|
-
const conditions = [];
|
|
546
|
-
for (const [key, value] of Object.entries(params.args.where)) {
|
|
547
|
-
if (typeof value === 'object' && value !== null) {
|
|
548
|
-
// 복합 조건(contains, startsWith 등)
|
|
549
|
-
for (const [op, val] of Object.entries(value)) {
|
|
550
|
-
let sqlOp = "";
|
|
551
|
-
|
|
552
|
-
// Prisma 연산자를 SQL 연산자로 변환
|
|
553
|
-
switch (op) {
|
|
554
|
-
case 'equals': sqlOp = '='; break;
|
|
555
|
-
case 'not': sqlOp = '!='; break;
|
|
556
|
-
case 'in': sqlOp = 'IN'; break;
|
|
557
|
-
case 'notIn': sqlOp = 'NOT IN'; break;
|
|
558
|
-
case 'lt': sqlOp = '<'; break;
|
|
559
|
-
case 'lte': sqlOp = '<='; break;
|
|
560
|
-
case 'gt': sqlOp = '>'; break;
|
|
561
|
-
case 'gte': sqlOp = '>='; break;
|
|
562
|
-
case 'contains': sqlOp = 'LIKE'; break;
|
|
563
|
-
case 'startsWith': sqlOp = 'LIKE'; break;
|
|
564
|
-
case 'endsWith': sqlOp = 'LIKE'; break;
|
|
565
|
-
default: sqlOp = op;
|
|
566
|
-
}
|
|
567
|
-
|
|
568
|
-
let sqlVal = val;
|
|
569
|
-
if (op === 'contains') {
|
|
570
|
-
sqlVal = `'%${val}%'`;
|
|
571
|
-
} else if (op === 'startsWith') {
|
|
572
|
-
sqlVal = `'${val}%'`;
|
|
573
|
-
} else if (op === 'endsWith') {
|
|
574
|
-
sqlVal = `'%${val}'`;
|
|
575
|
-
} else if (typeof val === 'string') {
|
|
576
|
-
sqlVal = `'${val}'`;
|
|
577
|
-
} else if (Array.isArray(val)) {
|
|
578
|
-
sqlVal = `(${val.map(v => typeof v === 'string' ? `'${v}'` : v).join(', ')})`;
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
conditions.push(`${key} ${sqlOp} ${sqlVal}`);
|
|
582
|
-
}
|
|
583
|
-
} else {
|
|
584
|
-
// 단순 조건
|
|
585
|
-
let formattedValue = typeof value === 'string' ? `'${value}'` : value;
|
|
586
|
-
conditions.push(`${key} = ${formattedValue}`);
|
|
587
|
-
}
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
if (conditions.length > 0) {
|
|
591
|
-
sqlStyleQuery += ` WHERE ${conditions.join(' AND ')}`;
|
|
592
|
-
}
|
|
593
|
-
}
|
|
594
|
-
|
|
595
|
-
// 정렬 조건 추가
|
|
596
|
-
if (params.args && params.args.orderBy) {
|
|
597
|
-
const orderClauses = [];
|
|
598
|
-
|
|
599
|
-
if (Array.isArray(params.args.orderBy)) {
|
|
600
|
-
for (const item of params.args.orderBy) {
|
|
601
|
-
for (const [field, dir] of Object.entries(item)) {
|
|
602
|
-
orderClauses.push(`${field} ${dir}`);
|
|
603
|
-
}
|
|
604
|
-
}
|
|
605
|
-
} else {
|
|
606
|
-
for (const [field, dir] of Object.entries(params.args.orderBy)) {
|
|
607
|
-
orderClauses.push(`${field} ${dir}`);
|
|
608
|
-
}
|
|
609
|
-
}
|
|
610
|
-
|
|
611
|
-
if (orderClauses.length > 0) {
|
|
612
|
-
sqlStyleQuery += ` ORDER BY ${orderClauses.join(', ')}`;
|
|
613
|
-
}
|
|
614
|
-
}
|
|
615
|
-
|
|
616
|
-
// 페이징 정보 추가
|
|
617
|
-
if (params.args) {
|
|
618
|
-
if (params.args.skip !== undefined) {
|
|
619
|
-
sqlStyleQuery += ` OFFSET ${params.args.skip}`;
|
|
620
|
-
}
|
|
621
|
-
|
|
622
|
-
if (params.args.take !== undefined) {
|
|
623
|
-
sqlStyleQuery += ` LIMIT ${params.args.take}`;
|
|
624
|
-
}
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
} else if (action.startsWith('create')) {
|
|
628
|
-
sqlStyleQuery = `INSERT INTO ${modelName}`;
|
|
629
|
-
|
|
630
|
-
if (params.args && params.args.data) {
|
|
631
|
-
const columns = [];
|
|
632
|
-
const values = [];
|
|
633
|
-
|
|
634
|
-
for (const [key, val] of Object.entries(params.args.data)) {
|
|
635
|
-
columns.push(key);
|
|
636
|
-
if (typeof val === 'string') {
|
|
637
|
-
values.push(`'${val}'`);
|
|
638
|
-
} else if (val === null) {
|
|
639
|
-
values.push('NULL');
|
|
640
|
-
} else if (typeof val === 'object') {
|
|
641
|
-
values.push(`'${JSON.stringify(val)}'`);
|
|
642
|
-
} else {
|
|
643
|
-
values.push(val);
|
|
644
|
-
}
|
|
645
|
-
}
|
|
646
|
-
|
|
647
|
-
sqlStyleQuery += ` (${columns.join(', ')}) VALUES (${values.join(', ')})`;
|
|
648
|
-
}
|
|
649
|
-
|
|
650
|
-
} else if (action.startsWith('update')) {
|
|
651
|
-
sqlStyleQuery = `UPDATE ${modelName}`;
|
|
652
|
-
|
|
653
|
-
if (params.args && params.args.data) {
|
|
654
|
-
const setExpressions = [];
|
|
655
|
-
|
|
656
|
-
for (const [key, val] of Object.entries(params.args.data)) {
|
|
657
|
-
let formattedValue;
|
|
658
|
-
if (typeof val === 'string') {
|
|
659
|
-
formattedValue = `'${val}'`;
|
|
660
|
-
} else if (val === null) {
|
|
661
|
-
formattedValue = 'NULL';
|
|
662
|
-
} else if (typeof val === 'object') {
|
|
663
|
-
formattedValue = `'${JSON.stringify(val)}'`;
|
|
664
|
-
} else {
|
|
665
|
-
formattedValue = val;
|
|
666
|
-
}
|
|
667
|
-
|
|
668
|
-
setExpressions.push(`${key} = ${formattedValue}`);
|
|
669
|
-
}
|
|
670
|
-
|
|
671
|
-
if (setExpressions.length > 0) {
|
|
672
|
-
sqlStyleQuery += ` SET ${setExpressions.join(', ')}`;
|
|
673
|
-
}
|
|
674
|
-
}
|
|
675
|
-
|
|
676
|
-
// where 조건 추가
|
|
677
|
-
if (params.args && params.args.where) {
|
|
678
|
-
const conditions = [];
|
|
679
|
-
for (const [key, value] of Object.entries(params.args.where)) {
|
|
680
|
-
if (typeof value === 'object' && value !== null) {
|
|
681
|
-
for (const [op, val] of Object.entries(value)) {
|
|
682
|
-
let sqlOp = op === 'equals' ? '=' : op;
|
|
683
|
-
let sqlVal = typeof val === 'string' ? `'${val}'` : val;
|
|
684
|
-
conditions.push(`${key} ${sqlOp} ${sqlVal}`);
|
|
685
|
-
}
|
|
686
|
-
} else {
|
|
687
|
-
let formattedValue = typeof value === 'string' ? `'${value}'` : value;
|
|
688
|
-
conditions.push(`${key} = ${formattedValue}`);
|
|
689
|
-
}
|
|
690
|
-
}
|
|
691
|
-
|
|
692
|
-
if (conditions.length > 0) {
|
|
693
|
-
sqlStyleQuery += ` WHERE ${conditions.join(' AND ')}`;
|
|
694
|
-
}
|
|
695
|
-
}
|
|
696
|
-
|
|
697
|
-
} else if (action.startsWith('delete')) {
|
|
698
|
-
sqlStyleQuery = `DELETE FROM ${modelName}`;
|
|
699
|
-
|
|
700
|
-
// where 조건 추가
|
|
701
|
-
if (params.args && params.args.where) {
|
|
702
|
-
const conditions = [];
|
|
703
|
-
for (const [key, value] of Object.entries(params.args.where)) {
|
|
704
|
-
if (typeof value === 'object' && value !== null) {
|
|
705
|
-
for (const [op, val] of Object.entries(value)) {
|
|
706
|
-
let sqlOp = op === 'equals' ? '=' : op;
|
|
707
|
-
let sqlVal = typeof val === 'string' ? `'${val}'` : val;
|
|
708
|
-
conditions.push(`${key} ${sqlOp} ${sqlVal}`);
|
|
709
|
-
}
|
|
710
|
-
} else {
|
|
711
|
-
let formattedValue = typeof value === 'string' ? `'${value}'` : value;
|
|
712
|
-
conditions.push(`${key} = ${formattedValue}`);
|
|
713
|
-
}
|
|
714
|
-
}
|
|
715
|
-
|
|
716
|
-
if (conditions.length > 0) {
|
|
717
|
-
sqlStyleQuery += ` WHERE ${conditions.join(' AND ')}`;
|
|
718
|
-
}
|
|
719
|
-
}
|
|
720
|
-
} else {
|
|
721
|
-
// 기타 액션은 기본 형식으로
|
|
722
|
-
sqlStyleQuery = `${action.toUpperCase()} ${modelName}`;
|
|
723
|
-
|
|
724
|
-
if (params.args) {
|
|
725
|
-
sqlStyleQuery += ` ${JSON.stringify(params.args)}`;
|
|
726
|
-
}
|
|
727
|
-
}
|
|
728
|
-
|
|
729
|
-
// 생성된 SQL 쿼리에 escapeLiteral 적용하여 처리
|
|
730
|
-
try {
|
|
731
|
-
var psql = escapeLiteral(sqlStyleQuery);
|
|
732
|
-
if (psql != null) {
|
|
733
|
-
sql_step.hash = psql.sql;
|
|
734
|
-
// CRUD 타입 설정
|
|
735
|
-
if (psql.type) {
|
|
736
|
-
sql_step.crud = psql.type.charCodeAt(0);
|
|
737
|
-
}
|
|
738
|
-
}
|
|
739
|
-
|
|
740
|
-
// 추가 SQL 정보 처리
|
|
741
|
-
var els = new EscapeLiteralSQL(sqlStyleQuery);
|
|
742
|
-
els.process();
|
|
743
|
-
|
|
744
|
-
// SQL 파라미터 처리
|
|
745
|
-
if (conf.profile_sql_param_enabled) {
|
|
746
|
-
sql_step.setTrue(1);
|
|
747
|
-
var crc = {value: 0};
|
|
748
|
-
sql_step.p1 = toParamBytes(psql.param, crc);
|
|
749
|
-
|
|
750
|
-
// 원래 인자를 파라미터로 추가
|
|
751
|
-
const paramsString = JSON.stringify(params.args || {});
|
|
752
|
-
sql_step.p2 = toParamBytes(paramsString, crc);
|
|
753
|
-
sql_step.pcrc = crc.value;
|
|
754
|
-
}
|
|
755
|
-
} catch (e) {
|
|
756
|
-
Logger.printError("WHATAP-306", "escapeLiteral error for model method", e, false);
|
|
757
|
-
}
|
|
758
|
-
} catch (e) {
|
|
759
|
-
Logger.printError("WHATAP-307", "Error creating SQL-style query", e, false);
|
|
760
|
-
}
|
|
509
|
+
// UPSERT 처리 추가
|
|
510
|
+
if (action === "upsert") {
|
|
511
|
+
sql_step.updated = 1; // upsert는 항상 1개의 레코드에 영향을 미침
|
|
761
512
|
}
|
|
762
513
|
|
|
763
514
|
sql_step.elapsed = ctx.getElapsedTime() - sql_step.start_time;
|
|
@@ -173,10 +173,10 @@ EscapeLiteralSQL.prototype._quotation = function () {
|
|
|
173
173
|
break;
|
|
174
174
|
case STAT.ALPHABET:
|
|
175
175
|
this.parsedSql += this.chars[this.pos];
|
|
176
|
-
status = STAT.QUOTATION;
|
|
176
|
+
this.status = STAT.QUOTATION;
|
|
177
177
|
break;
|
|
178
178
|
case STAT.NUMBER:
|
|
179
|
-
parsedSql += this.chars[this.pos];
|
|
179
|
+
this.parsedSql += this.chars[this.pos];
|
|
180
180
|
this.status = STAT.QUOTATION;
|
|
181
181
|
break;
|
|
182
182
|
case STAT.QUOTATION:
|
|
@@ -194,16 +194,16 @@ EscapeLiteralSQL.prototype._dquotation = function () {
|
|
|
194
194
|
}
|
|
195
195
|
this.param += this.chars[this.pos];
|
|
196
196
|
this.status = STAT.DQUOTATION;
|
|
197
|
-
break
|
|
197
|
+
break;
|
|
198
198
|
case STAT.COMMENT:
|
|
199
199
|
this.parsedSql += this.chars[this.pos];
|
|
200
200
|
break;
|
|
201
201
|
case STAT.ALPHABET:
|
|
202
202
|
this.parsedSql += this.chars[this.pos];
|
|
203
|
-
status = STAT.DQUOTATION;
|
|
203
|
+
this.status = STAT.DQUOTATION;
|
|
204
204
|
break;
|
|
205
205
|
case STAT.NUMBER:
|
|
206
|
-
parsedSql += this.chars[this.pos];
|
|
206
|
+
this.parsedSql += this.chars[this.pos];
|
|
207
207
|
this.status = STAT.DQUOTATION;
|
|
208
208
|
break;
|
|
209
209
|
case STAT.DQUOTATION:
|
package/package.json
CHANGED