mssql 12.3.0 → 12.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +189 -14
- package/lib/base/connection-pool.js +61 -10
- package/lib/base/index.js +2 -0
- package/lib/base/prepared-statement.js +62 -14
- package/lib/base/request.js +137 -65
- package/lib/base/transaction.js +32 -1
- package/lib/diagnostics.js +153 -0
- package/lib/msnodesqlv8/connection-pool.js +15 -2
- package/lib/tedious/connection-pool.js +13 -0
- package/lib/tedious/request.js +55 -25
- package/lib/tedious/transaction.js +5 -0
- package/lib/udt.js +25 -23
- package/lib/utils.js +10 -1
- package/package.json +2 -2
package/lib/base/request.js
CHANGED
|
@@ -3,11 +3,12 @@
|
|
|
3
3
|
const debug = require('debug')('mssql:base')
|
|
4
4
|
const { EventEmitter } = require('node:events')
|
|
5
5
|
const { Readable } = require('node:stream')
|
|
6
|
-
const { IDS, objectHasProperty } = require('../utils')
|
|
6
|
+
const { IDS, objectHasProperty, getPoolId } = require('../utils')
|
|
7
7
|
const globalConnection = require('../global-connection')
|
|
8
8
|
const { RequestError, ConnectionError } = require('../error')
|
|
9
9
|
const { TYPES } = require('../datatypes')
|
|
10
10
|
const shared = require('../shared')
|
|
11
|
+
const { CHANNELS, tracePromise, traceCallback, publish } = require('../diagnostics')
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* Class Request.
|
|
@@ -37,6 +38,7 @@ class Request extends EventEmitter {
|
|
|
37
38
|
|
|
38
39
|
this.canceled = false
|
|
39
40
|
this._paused = false
|
|
41
|
+
this._internal = false
|
|
40
42
|
this.parent = parent || globalConnection.pool
|
|
41
43
|
this.parameters = {}
|
|
42
44
|
this.stream = null
|
|
@@ -218,6 +220,24 @@ class Request extends EventEmitter {
|
|
|
218
220
|
return this.output(name, type, value)
|
|
219
221
|
}
|
|
220
222
|
|
|
223
|
+
_getParameterNames () {
|
|
224
|
+
return Object.keys(this.parameters)
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
_tracedPromise (channel, contextFactory, fn) {
|
|
228
|
+
if (this._internal) {
|
|
229
|
+
return fn()
|
|
230
|
+
}
|
|
231
|
+
return tracePromise(channel, fn, contextFactory)
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
_tracedCallback (channel, contextFactory, fn, position, args) {
|
|
235
|
+
if (this._internal) {
|
|
236
|
+
return fn.apply(this, args)
|
|
237
|
+
}
|
|
238
|
+
return traceCallback(channel, fn, position, contextFactory, this, args)
|
|
239
|
+
}
|
|
240
|
+
|
|
221
241
|
/**
|
|
222
242
|
* Execute the SQL batch.
|
|
223
243
|
*
|
|
@@ -232,7 +252,11 @@ class Request extends EventEmitter {
|
|
|
232
252
|
this.rowsAffected = 0
|
|
233
253
|
|
|
234
254
|
if (typeof callback === 'function') {
|
|
235
|
-
this.
|
|
255
|
+
this._tracedCallback(CHANNELS.TRACE_BATCH, () => ({
|
|
256
|
+
command: batch,
|
|
257
|
+
requestId: IDS.get(this),
|
|
258
|
+
poolId: getPoolId(this)
|
|
259
|
+
}), this._batch, 1, [batch, (err, recordsets, output, rowsAffected) => {
|
|
236
260
|
if (this.stream) {
|
|
237
261
|
if (err) this.emit('error', err)
|
|
238
262
|
err = null
|
|
@@ -250,7 +274,7 @@ class Request extends EventEmitter {
|
|
|
250
274
|
output,
|
|
251
275
|
rowsAffected
|
|
252
276
|
})
|
|
253
|
-
})
|
|
277
|
+
}])
|
|
254
278
|
return this
|
|
255
279
|
}
|
|
256
280
|
|
|
@@ -261,24 +285,31 @@ class Request extends EventEmitter {
|
|
|
261
285
|
batch = this._template(strings, values)
|
|
262
286
|
}
|
|
263
287
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
288
|
+
const batchCommand = batch
|
|
289
|
+
return this._tracedPromise(CHANNELS.TRACE_BATCH, () => ({
|
|
290
|
+
command: batchCommand,
|
|
291
|
+
requestId: IDS.get(this),
|
|
292
|
+
poolId: getPoolId(this)
|
|
293
|
+
}), () => {
|
|
294
|
+
return new shared.Promise((resolve, reject) => {
|
|
295
|
+
this._batch(batchCommand, (err, recordsets, output, rowsAffected) => {
|
|
296
|
+
if (this.stream) {
|
|
297
|
+
if (err) this.emit('error', err)
|
|
298
|
+
err = null
|
|
299
|
+
|
|
300
|
+
this.emit('done', {
|
|
301
|
+
output,
|
|
302
|
+
rowsAffected
|
|
303
|
+
})
|
|
304
|
+
}
|
|
269
305
|
|
|
270
|
-
|
|
306
|
+
if (err) return reject(err)
|
|
307
|
+
resolve({
|
|
308
|
+
recordsets,
|
|
309
|
+
recordset: recordsets && recordsets[0],
|
|
271
310
|
output,
|
|
272
311
|
rowsAffected
|
|
273
312
|
})
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
if (err) return reject(err)
|
|
277
|
-
resolve({
|
|
278
|
-
recordsets,
|
|
279
|
-
recordset: recordsets && recordsets[0],
|
|
280
|
-
output,
|
|
281
|
-
rowsAffected
|
|
282
313
|
})
|
|
283
314
|
})
|
|
284
315
|
})
|
|
@@ -324,7 +355,12 @@ class Request extends EventEmitter {
|
|
|
324
355
|
if (this.arrayRowMode === null && this.parent) this.arrayRowMode = this.parent.config.arrayRowMode
|
|
325
356
|
|
|
326
357
|
if (this.stream || typeof callback === 'function') {
|
|
327
|
-
this.
|
|
358
|
+
this._tracedCallback(CHANNELS.TRACE_BULK, () => ({
|
|
359
|
+
table: table.path || table.name,
|
|
360
|
+
rowCount: table.rows ? table.rows.length : 0,
|
|
361
|
+
requestId: IDS.get(this),
|
|
362
|
+
poolId: getPoolId(this)
|
|
363
|
+
}), this._bulk, 2, [table, options, (err, rowsAffected) => {
|
|
328
364
|
if (this.stream) {
|
|
329
365
|
if (err) this.emit('error', err)
|
|
330
366
|
return this.emit('done', {
|
|
@@ -336,15 +372,22 @@ class Request extends EventEmitter {
|
|
|
336
372
|
callback(null, {
|
|
337
373
|
rowsAffected
|
|
338
374
|
})
|
|
339
|
-
})
|
|
375
|
+
}])
|
|
340
376
|
return this
|
|
341
377
|
}
|
|
342
378
|
|
|
343
|
-
return
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
379
|
+
return this._tracedPromise(CHANNELS.TRACE_BULK, () => ({
|
|
380
|
+
table: table.path || table.name,
|
|
381
|
+
rowCount: table.rows ? table.rows.length : 0,
|
|
382
|
+
requestId: IDS.get(this),
|
|
383
|
+
poolId: getPoolId(this)
|
|
384
|
+
}), () => {
|
|
385
|
+
return new shared.Promise((resolve, reject) => {
|
|
386
|
+
this._bulk(table, options, (err, rowsAffected) => {
|
|
387
|
+
if (err) return reject(err)
|
|
388
|
+
resolve({
|
|
389
|
+
rowsAffected
|
|
390
|
+
})
|
|
348
391
|
})
|
|
349
392
|
})
|
|
350
393
|
})
|
|
@@ -429,7 +472,12 @@ class Request extends EventEmitter {
|
|
|
429
472
|
this.rowsAffected = 0
|
|
430
473
|
|
|
431
474
|
if (typeof callback === 'function') {
|
|
432
|
-
this.
|
|
475
|
+
this._tracedCallback(CHANNELS.TRACE_QUERY, () => ({
|
|
476
|
+
command,
|
|
477
|
+
parameters: this._getParameterNames(),
|
|
478
|
+
requestId: IDS.get(this),
|
|
479
|
+
poolId: getPoolId(this)
|
|
480
|
+
}), this._query, 1, [command, (err, recordsets, output, rowsAffected, columns) => {
|
|
433
481
|
if (this.stream) {
|
|
434
482
|
if (err) this.emit('error', err)
|
|
435
483
|
err = null
|
|
@@ -449,7 +497,7 @@ class Request extends EventEmitter {
|
|
|
449
497
|
}
|
|
450
498
|
if (this.arrayRowMode) result.columns = columns
|
|
451
499
|
callback(null, result)
|
|
452
|
-
})
|
|
500
|
+
}])
|
|
453
501
|
return this
|
|
454
502
|
}
|
|
455
503
|
|
|
@@ -460,27 +508,34 @@ class Request extends EventEmitter {
|
|
|
460
508
|
command = this._template(strings, values)
|
|
461
509
|
}
|
|
462
510
|
|
|
463
|
-
return
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
511
|
+
return this._tracedPromise(CHANNELS.TRACE_QUERY, () => ({
|
|
512
|
+
command,
|
|
513
|
+
parameters: this._getParameterNames(),
|
|
514
|
+
requestId: IDS.get(this),
|
|
515
|
+
poolId: getPoolId(this)
|
|
516
|
+
}), () => {
|
|
517
|
+
return new shared.Promise((resolve, reject) => {
|
|
518
|
+
this._query(command, (err, recordsets, output, rowsAffected, columns) => {
|
|
519
|
+
if (this.stream) {
|
|
520
|
+
if (err) this.emit('error', err)
|
|
521
|
+
err = null
|
|
522
|
+
|
|
523
|
+
this.emit('done', {
|
|
524
|
+
output,
|
|
525
|
+
rowsAffected
|
|
526
|
+
})
|
|
527
|
+
}
|
|
468
528
|
|
|
469
|
-
|
|
529
|
+
if (err) return reject(err)
|
|
530
|
+
const result = {
|
|
531
|
+
recordsets,
|
|
532
|
+
recordset: recordsets && recordsets[0],
|
|
470
533
|
output,
|
|
471
534
|
rowsAffected
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
const result = {
|
|
477
|
-
recordsets,
|
|
478
|
-
recordset: recordsets && recordsets[0],
|
|
479
|
-
output,
|
|
480
|
-
rowsAffected
|
|
481
|
-
}
|
|
482
|
-
if (this.arrayRowMode) result.columns = columns
|
|
483
|
-
resolve(result)
|
|
535
|
+
}
|
|
536
|
+
if (this.arrayRowMode) result.columns = columns
|
|
537
|
+
resolve(result)
|
|
538
|
+
})
|
|
484
539
|
})
|
|
485
540
|
})
|
|
486
541
|
}
|
|
@@ -518,7 +573,12 @@ class Request extends EventEmitter {
|
|
|
518
573
|
this.rowsAffected = 0
|
|
519
574
|
|
|
520
575
|
if (typeof callback === 'function') {
|
|
521
|
-
this.
|
|
576
|
+
this._tracedCallback(CHANNELS.TRACE_EXECUTE, () => ({
|
|
577
|
+
procedure: command,
|
|
578
|
+
parameters: this._getParameterNames(),
|
|
579
|
+
requestId: IDS.get(this),
|
|
580
|
+
poolId: getPoolId(this)
|
|
581
|
+
}), this._execute, 1, [command, (err, recordsets, output, returnValue, rowsAffected, columns) => {
|
|
522
582
|
if (this.stream) {
|
|
523
583
|
if (err) this.emit('error', err)
|
|
524
584
|
err = null
|
|
@@ -540,33 +600,40 @@ class Request extends EventEmitter {
|
|
|
540
600
|
}
|
|
541
601
|
if (this.arrayRowMode) result.columns = columns
|
|
542
602
|
callback(null, result)
|
|
543
|
-
})
|
|
603
|
+
}])
|
|
544
604
|
return this
|
|
545
605
|
}
|
|
546
606
|
|
|
547
|
-
return
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
607
|
+
return this._tracedPromise(CHANNELS.TRACE_EXECUTE, () => ({
|
|
608
|
+
procedure: command,
|
|
609
|
+
parameters: this._getParameterNames(),
|
|
610
|
+
requestId: IDS.get(this),
|
|
611
|
+
poolId: getPoolId(this)
|
|
612
|
+
}), () => {
|
|
613
|
+
return new shared.Promise((resolve, reject) => {
|
|
614
|
+
this._execute(command, (err, recordsets, output, returnValue, rowsAffected, columns) => {
|
|
615
|
+
if (this.stream) {
|
|
616
|
+
if (err) this.emit('error', err)
|
|
617
|
+
err = null
|
|
618
|
+
|
|
619
|
+
this.emit('done', {
|
|
620
|
+
output,
|
|
621
|
+
rowsAffected,
|
|
622
|
+
returnValue
|
|
623
|
+
})
|
|
624
|
+
}
|
|
552
625
|
|
|
553
|
-
|
|
626
|
+
if (err) return reject(err)
|
|
627
|
+
const result = {
|
|
628
|
+
recordsets,
|
|
629
|
+
recordset: recordsets && recordsets[0],
|
|
554
630
|
output,
|
|
555
631
|
rowsAffected,
|
|
556
632
|
returnValue
|
|
557
|
-
}
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
const result = {
|
|
562
|
-
recordsets,
|
|
563
|
-
recordset: recordsets && recordsets[0],
|
|
564
|
-
output,
|
|
565
|
-
rowsAffected,
|
|
566
|
-
returnValue
|
|
567
|
-
}
|
|
568
|
-
if (this.arrayRowMode) result.columns = columns
|
|
569
|
-
resolve(result)
|
|
633
|
+
}
|
|
634
|
+
if (this.arrayRowMode) result.columns = columns
|
|
635
|
+
resolve(result)
|
|
636
|
+
})
|
|
570
637
|
})
|
|
571
638
|
})
|
|
572
639
|
}
|
|
@@ -598,6 +665,11 @@ class Request extends EventEmitter {
|
|
|
598
665
|
|
|
599
666
|
cancel () {
|
|
600
667
|
this._cancel()
|
|
668
|
+
if (!this._internal) {
|
|
669
|
+
publish(CHANNELS.REQUEST_CANCEL, () => ({
|
|
670
|
+
requestId: IDS.get(this)
|
|
671
|
+
}))
|
|
672
|
+
}
|
|
601
673
|
return true
|
|
602
674
|
}
|
|
603
675
|
|
package/lib/base/transaction.js
CHANGED
|
@@ -2,11 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
const debug = require('debug')('mssql:base')
|
|
4
4
|
const { EventEmitter } = require('node:events')
|
|
5
|
-
const { IDS } = require('../utils')
|
|
5
|
+
const { IDS, getPoolId } = require('../utils')
|
|
6
6
|
const globalConnection = require('../global-connection')
|
|
7
7
|
const { TransactionError } = require('../error')
|
|
8
8
|
const shared = require('../shared')
|
|
9
9
|
const ISOLATION_LEVEL = require('../isolationlevel')
|
|
10
|
+
const { CHANNELS, publish } = require('../diagnostics')
|
|
11
|
+
|
|
12
|
+
const ISOLATION_LEVEL_NAMES = Object.fromEntries(
|
|
13
|
+
Object.entries(ISOLATION_LEVEL).map(([name, value]) => [value, name])
|
|
14
|
+
)
|
|
10
15
|
|
|
11
16
|
/**
|
|
12
17
|
* Class Transaction.
|
|
@@ -101,6 +106,12 @@ class Transaction extends EventEmitter {
|
|
|
101
106
|
if (typeof callback === 'function') {
|
|
102
107
|
this._begin(isolationLevel, err => {
|
|
103
108
|
if (!err) {
|
|
109
|
+
publish(CHANNELS.TRANSACTION_BEGIN, () => ({
|
|
110
|
+
transactionId: IDS.get(this),
|
|
111
|
+
isolationLevel: this.isolationLevel,
|
|
112
|
+
isolationLevelName: ISOLATION_LEVEL_NAMES[this.isolationLevel],
|
|
113
|
+
poolId: getPoolId(this)
|
|
114
|
+
}))
|
|
104
115
|
this.emit('begin')
|
|
105
116
|
}
|
|
106
117
|
callback(err)
|
|
@@ -111,6 +122,12 @@ class Transaction extends EventEmitter {
|
|
|
111
122
|
return new shared.Promise((resolve, reject) => {
|
|
112
123
|
this._begin(isolationLevel, err => {
|
|
113
124
|
if (err) return reject(err)
|
|
125
|
+
publish(CHANNELS.TRANSACTION_BEGIN, () => ({
|
|
126
|
+
transactionId: IDS.get(this),
|
|
127
|
+
isolationLevel: this.isolationLevel,
|
|
128
|
+
isolationLevelName: ISOLATION_LEVEL_NAMES[this.isolationLevel],
|
|
129
|
+
poolId: getPoolId(this)
|
|
130
|
+
}))
|
|
114
131
|
this.emit('begin')
|
|
115
132
|
resolve(this)
|
|
116
133
|
})
|
|
@@ -155,6 +172,9 @@ class Transaction extends EventEmitter {
|
|
|
155
172
|
if (typeof callback === 'function') {
|
|
156
173
|
this._commit(err => {
|
|
157
174
|
if (!err) {
|
|
175
|
+
publish(CHANNELS.TRANSACTION_COMMIT, () => ({
|
|
176
|
+
transactionId: IDS.get(this)
|
|
177
|
+
}))
|
|
158
178
|
this.emit('commit')
|
|
159
179
|
}
|
|
160
180
|
callback(err)
|
|
@@ -165,6 +185,9 @@ class Transaction extends EventEmitter {
|
|
|
165
185
|
return new shared.Promise((resolve, reject) => {
|
|
166
186
|
this._commit(err => {
|
|
167
187
|
if (err) return reject(err)
|
|
188
|
+
publish(CHANNELS.TRANSACTION_COMMIT, () => ({
|
|
189
|
+
transactionId: IDS.get(this)
|
|
190
|
+
}))
|
|
168
191
|
this.emit('commit')
|
|
169
192
|
resolve()
|
|
170
193
|
})
|
|
@@ -214,6 +237,10 @@ class Transaction extends EventEmitter {
|
|
|
214
237
|
if (typeof callback === 'function') {
|
|
215
238
|
this._rollback(err => {
|
|
216
239
|
if (!err) {
|
|
240
|
+
publish(CHANNELS.TRANSACTION_ROLLBACK, () => ({
|
|
241
|
+
transactionId: IDS.get(this),
|
|
242
|
+
aborted: this._aborted
|
|
243
|
+
}))
|
|
217
244
|
this.emit('rollback', this._aborted)
|
|
218
245
|
}
|
|
219
246
|
callback(err)
|
|
@@ -224,6 +251,10 @@ class Transaction extends EventEmitter {
|
|
|
224
251
|
return new shared.Promise((resolve, reject) => {
|
|
225
252
|
return this._rollback(err => {
|
|
226
253
|
if (err) return reject(err)
|
|
254
|
+
publish(CHANNELS.TRANSACTION_ROLLBACK, () => ({
|
|
255
|
+
transactionId: IDS.get(this),
|
|
256
|
+
aborted: this._aborted
|
|
257
|
+
}))
|
|
227
258
|
this.emit('rollback', this._aborted)
|
|
228
259
|
resolve()
|
|
229
260
|
})
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const dc = require('node:diagnostics_channel')
|
|
4
|
+
|
|
5
|
+
// TracingChannel names
|
|
6
|
+
const TRACE_QUERY = 'mssql:query'
|
|
7
|
+
const TRACE_BATCH = 'mssql:batch'
|
|
8
|
+
const TRACE_EXECUTE = 'mssql:execute'
|
|
9
|
+
const TRACE_BULK = 'mssql:bulk'
|
|
10
|
+
const TRACE_CONNECT = 'mssql:connect'
|
|
11
|
+
const TRACE_POOL_ACQUIRE = 'mssql:pool:acquire'
|
|
12
|
+
const TRACE_PREPARED_STATEMENT_PREPARE = 'mssql:prepared-statement:prepare'
|
|
13
|
+
const TRACE_PREPARED_STATEMENT_EXECUTE = 'mssql:prepared-statement:execute'
|
|
14
|
+
|
|
15
|
+
// Point-event channel names
|
|
16
|
+
const CONNECTION_ACQUIRE = 'mssql:connection:acquire'
|
|
17
|
+
const CONNECTION_RELEASE = 'mssql:connection:release'
|
|
18
|
+
const CONNECTION_CREATE = 'mssql:connection:create'
|
|
19
|
+
const CONNECTION_DESTROY = 'mssql:connection:destroy'
|
|
20
|
+
const POOL_CLOSE = 'mssql:pool:close'
|
|
21
|
+
const TRANSACTION_BEGIN = 'mssql:transaction:begin'
|
|
22
|
+
const TRANSACTION_COMMIT = 'mssql:transaction:commit'
|
|
23
|
+
const TRANSACTION_ROLLBACK = 'mssql:transaction:rollback'
|
|
24
|
+
const REQUEST_CANCEL = 'mssql:request:cancel'
|
|
25
|
+
const PREPARED_STATEMENT_UNPREPARE = 'mssql:prepared-statement:unprepare'
|
|
26
|
+
|
|
27
|
+
const CHANNELS = Object.freeze({
|
|
28
|
+
TRACE_QUERY,
|
|
29
|
+
TRACE_BATCH,
|
|
30
|
+
TRACE_EXECUTE,
|
|
31
|
+
TRACE_BULK,
|
|
32
|
+
TRACE_CONNECT,
|
|
33
|
+
TRACE_POOL_ACQUIRE,
|
|
34
|
+
TRACE_PREPARED_STATEMENT_PREPARE,
|
|
35
|
+
TRACE_PREPARED_STATEMENT_EXECUTE,
|
|
36
|
+
CONNECTION_ACQUIRE,
|
|
37
|
+
CONNECTION_RELEASE,
|
|
38
|
+
CONNECTION_CREATE,
|
|
39
|
+
CONNECTION_DESTROY,
|
|
40
|
+
POOL_CLOSE,
|
|
41
|
+
TRANSACTION_BEGIN,
|
|
42
|
+
TRANSACTION_COMMIT,
|
|
43
|
+
TRANSACTION_ROLLBACK,
|
|
44
|
+
REQUEST_CANCEL,
|
|
45
|
+
PREPARED_STATEMENT_UNPREPARE
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
// Pre-create TracingChannel instances at module load time
|
|
49
|
+
const tracingChannels = {
|
|
50
|
+
[TRACE_QUERY]: dc.tracingChannel(TRACE_QUERY),
|
|
51
|
+
[TRACE_BATCH]: dc.tracingChannel(TRACE_BATCH),
|
|
52
|
+
[TRACE_EXECUTE]: dc.tracingChannel(TRACE_EXECUTE),
|
|
53
|
+
[TRACE_BULK]: dc.tracingChannel(TRACE_BULK),
|
|
54
|
+
[TRACE_CONNECT]: dc.tracingChannel(TRACE_CONNECT),
|
|
55
|
+
[TRACE_POOL_ACQUIRE]: dc.tracingChannel(TRACE_POOL_ACQUIRE),
|
|
56
|
+
[TRACE_PREPARED_STATEMENT_PREPARE]: dc.tracingChannel(TRACE_PREPARED_STATEMENT_PREPARE),
|
|
57
|
+
[TRACE_PREPARED_STATEMENT_EXECUTE]: dc.tracingChannel(TRACE_PREPARED_STATEMENT_EXECUTE)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Pre-create point-event channel instances at module load time
|
|
61
|
+
const pointChannels = {
|
|
62
|
+
[CONNECTION_ACQUIRE]: dc.channel(CONNECTION_ACQUIRE),
|
|
63
|
+
[CONNECTION_RELEASE]: dc.channel(CONNECTION_RELEASE),
|
|
64
|
+
[CONNECTION_CREATE]: dc.channel(CONNECTION_CREATE),
|
|
65
|
+
[CONNECTION_DESTROY]: dc.channel(CONNECTION_DESTROY),
|
|
66
|
+
[POOL_CLOSE]: dc.channel(POOL_CLOSE),
|
|
67
|
+
[TRANSACTION_BEGIN]: dc.channel(TRANSACTION_BEGIN),
|
|
68
|
+
[TRANSACTION_COMMIT]: dc.channel(TRANSACTION_COMMIT),
|
|
69
|
+
[TRANSACTION_ROLLBACK]: dc.channel(TRANSACTION_ROLLBACK),
|
|
70
|
+
[REQUEST_CANCEL]: dc.channel(REQUEST_CANCEL),
|
|
71
|
+
[PREPARED_STATEMENT_UNPREPARE]: dc.channel(PREPARED_STATEMENT_UNPREPARE)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// TracingChannel.hasSubscribers was added in Node 22. On 18.19 / 20 the
|
|
75
|
+
// aggregate property is undefined, so we fall back to checking the
|
|
76
|
+
// sub-channels directly (these have existed since the original
|
|
77
|
+
// diagnostics_channel API). Preserves the zero-cost fast path across all
|
|
78
|
+
// supported runtimes.
|
|
79
|
+
function tracingChannelHasSubscribers (tc) {
|
|
80
|
+
if (typeof tc.hasSubscribers === 'boolean') return tc.hasSubscribers
|
|
81
|
+
return tc.start.hasSubscribers ||
|
|
82
|
+
tc.end.hasSubscribers ||
|
|
83
|
+
tc.asyncStart.hasSubscribers ||
|
|
84
|
+
tc.asyncEnd.hasSubscribers ||
|
|
85
|
+
tc.error.hasSubscribers
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Trace an async operation using a TracingChannel.
|
|
90
|
+
*
|
|
91
|
+
* When subscribers are active, wraps `fn` with TracingChannel.tracePromise().
|
|
92
|
+
* When no subscribers are active, calls `fn` directly with zero overhead
|
|
93
|
+
* (no context allocation).
|
|
94
|
+
*
|
|
95
|
+
* @param {string} name - TracingChannel name (one of CHANNELS.TRACE_*)
|
|
96
|
+
* @param {Function} fn - The function to trace (must return a Promise)
|
|
97
|
+
* @param {Function} contextFactory - Factory function returning the context object
|
|
98
|
+
* @returns {Promise} The return value of fn
|
|
99
|
+
*/
|
|
100
|
+
function tracePromise (name, fn, contextFactory) {
|
|
101
|
+
const channel = tracingChannels[name]
|
|
102
|
+
if (tracingChannelHasSubscribers(channel)) {
|
|
103
|
+
return channel.tracePromise(fn, contextFactory())
|
|
104
|
+
}
|
|
105
|
+
return fn()
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Trace a callback-style async operation using a TracingChannel.
|
|
110
|
+
*
|
|
111
|
+
* When subscribers are active, delegates to TracingChannel.traceCallback,
|
|
112
|
+
* which replaces the callback at `position` in `args` with a wrapped
|
|
113
|
+
* version that publishes to start/end/asyncStart/asyncEnd/error. When
|
|
114
|
+
* no subscribers are active, calls `fn` directly with zero overhead.
|
|
115
|
+
*
|
|
116
|
+
* @param {string} name - TracingChannel name (one of CHANNELS.TRACE_*)
|
|
117
|
+
* @param {Function} fn - The function to call (receives callback at `position`)
|
|
118
|
+
* @param {number} position - Index of the callback within `args`
|
|
119
|
+
* @param {Function} contextFactory - Factory function returning the context object
|
|
120
|
+
* @param {*} thisArg - `this` binding for fn
|
|
121
|
+
* @param {Array} args - Arguments to pass to fn (includes the callback at `position`)
|
|
122
|
+
* @returns {*} The return value of fn
|
|
123
|
+
*/
|
|
124
|
+
function traceCallback (name, fn, position, contextFactory, thisArg, args) {
|
|
125
|
+
const channel = tracingChannels[name]
|
|
126
|
+
if (tracingChannelHasSubscribers(channel)) {
|
|
127
|
+
return channel.traceCallback(fn, position, contextFactory(), thisArg, ...args)
|
|
128
|
+
}
|
|
129
|
+
return fn.apply(thisArg, args)
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Publish a point event on a named channel.
|
|
134
|
+
*
|
|
135
|
+
* Only allocates the message object when subscribers are active.
|
|
136
|
+
*
|
|
137
|
+
* @param {string} name - Point-event channel name (one of CHANNELS.*)
|
|
138
|
+
* @param {Function} factory - Factory function that returns the message object
|
|
139
|
+
*/
|
|
140
|
+
function publish (name, factory) {
|
|
141
|
+
const channel = pointChannels[name]
|
|
142
|
+
if (channel.hasSubscribers) {
|
|
143
|
+
channel.publish(factory())
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
module.exports = {
|
|
148
|
+
CHANNELS,
|
|
149
|
+
tracingChannels,
|
|
150
|
+
tracePromise,
|
|
151
|
+
traceCallback,
|
|
152
|
+
publish
|
|
153
|
+
}
|
|
@@ -8,6 +8,7 @@ const shared = require('../shared')
|
|
|
8
8
|
const ConnectionError = require('../error/connection-error')
|
|
9
9
|
const { platform } = require('node:os')
|
|
10
10
|
const { build } = require('@tediousjs/connection-string')
|
|
11
|
+
const { CHANNELS, publish } = require('../diagnostics')
|
|
11
12
|
|
|
12
13
|
const DEFAULT_CONNECTION_DRIVER = ['darwin', 'linux'].includes(platform()) ? 'ODBC Driver 17 for SQL Server' : 'SQL Server Native Client 11.0'
|
|
13
14
|
|
|
@@ -58,6 +59,12 @@ class ConnectionPool extends BaseConnectionPool {
|
|
|
58
59
|
IDS.add(tds, 'Connection', connedtionId)
|
|
59
60
|
tds.setUseUTC(this.config.options.useUTC)
|
|
60
61
|
debug('connection(%d): established', IDS.get(tds))
|
|
62
|
+
publish(CHANNELS.CONNECTION_CREATE, () => ({
|
|
63
|
+
connectionId: IDS.get(tds),
|
|
64
|
+
poolId: IDS.get(this),
|
|
65
|
+
server: this.config.server,
|
|
66
|
+
database: this.config.database
|
|
67
|
+
}))
|
|
61
68
|
resolve(tds)
|
|
62
69
|
})
|
|
63
70
|
})
|
|
@@ -80,9 +87,15 @@ class ConnectionPool extends BaseConnectionPool {
|
|
|
80
87
|
resolve()
|
|
81
88
|
return
|
|
82
89
|
}
|
|
83
|
-
|
|
90
|
+
const connectionId = IDS.get(tds)
|
|
91
|
+
const poolId = IDS.get(this)
|
|
92
|
+
debug('connection(%d): destroying', connectionId)
|
|
84
93
|
tds.close(() => {
|
|
85
|
-
debug('connection(%d): destroyed',
|
|
94
|
+
debug('connection(%d): destroyed', connectionId)
|
|
95
|
+
publish(CHANNELS.CONNECTION_DESTROY, () => ({
|
|
96
|
+
connectionId,
|
|
97
|
+
poolId
|
|
98
|
+
}))
|
|
86
99
|
resolve()
|
|
87
100
|
})
|
|
88
101
|
})
|
|
@@ -6,6 +6,7 @@ const BaseConnectionPool = require('../base/connection-pool')
|
|
|
6
6
|
const { IDS } = require('../utils')
|
|
7
7
|
const shared = require('../shared')
|
|
8
8
|
const ConnectionError = require('../error/connection-error')
|
|
9
|
+
const { CHANNELS, publish } = require('../diagnostics')
|
|
9
10
|
|
|
10
11
|
class ConnectionPool extends BaseConnectionPool {
|
|
11
12
|
_config () {
|
|
@@ -88,6 +89,12 @@ class ConnectionPool extends BaseConnectionPool {
|
|
|
88
89
|
|
|
89
90
|
debug('connection(%d): established', IDS.get(tedious))
|
|
90
91
|
this.collation = tedious.databaseCollation
|
|
92
|
+
publish(CHANNELS.CONNECTION_CREATE, () => ({
|
|
93
|
+
connectionId: IDS.get(tedious),
|
|
94
|
+
poolId: IDS.get(this),
|
|
95
|
+
server: this.config.server,
|
|
96
|
+
database: this.config.database
|
|
97
|
+
}))
|
|
91
98
|
resolveOnce(tedious)
|
|
92
99
|
})
|
|
93
100
|
IDS.add(tedious, 'Connection')
|
|
@@ -156,6 +163,8 @@ class ConnectionPool extends BaseConnectionPool {
|
|
|
156
163
|
return
|
|
157
164
|
}
|
|
158
165
|
debug('connection(%d): destroying', IDS.get(tedious))
|
|
166
|
+
const connectionId = IDS.get(tedious)
|
|
167
|
+
const poolId = IDS.get(this)
|
|
159
168
|
|
|
160
169
|
if (tedious.closed) {
|
|
161
170
|
debug('connection(%d): already closed', IDS.get(tedious))
|
|
@@ -163,6 +172,10 @@ class ConnectionPool extends BaseConnectionPool {
|
|
|
163
172
|
} else {
|
|
164
173
|
tedious.once('end', () => {
|
|
165
174
|
debug('connection(%d): destroyed', IDS.get(tedious))
|
|
175
|
+
publish(CHANNELS.CONNECTION_DESTROY, () => ({
|
|
176
|
+
connectionId,
|
|
177
|
+
poolId
|
|
178
|
+
}))
|
|
166
179
|
resolve()
|
|
167
180
|
})
|
|
168
181
|
|