Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions src/connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,7 @@ export interface InternalConnectionOptions {
isolationLevel: typeof ISOLATION_LEVEL[keyof typeof ISOLATION_LEVEL];
language: string;
localAddress: undefined | string;
lockTimeout: undefined | number;
maxRetriesOnTransientErrors: number;
multiSubnetFailover: boolean;
packetSize: number;
Expand Down Expand Up @@ -734,6 +735,13 @@ export interface ConnectionOptions {
*/
localAddress?: string | undefined;

/**
* The number of milliseconds a statement waits for a lock to be released.
* This sets the value for `SET LOCK_TIMEOUT` during the initial SQL phase of a connection.
* For more information, see [here](https://learn.microsoft.com/en-us/sql/t-sql/statements/set-lock-timeout-transact-sql)
*/
lockTimeout?: number | undefined;

/**
* A boolean determining whether to parse unique identifier type with lowercase case characters.
*
Expand Down Expand Up @@ -1306,6 +1314,7 @@ class Connection extends EventEmitter {
isolationLevel: ISOLATION_LEVEL.READ_COMMITTED,
language: DEFAULT_LANGUAGE,
localAddress: undefined,
lockTimeout: undefined,
maxRetriesOnTransientErrors: 3,
multiSubnetFailover: false,
packetSize: DEFAULT_PACKET_SIZE,
Expand Down Expand Up @@ -1592,6 +1601,14 @@ class Connection extends EventEmitter {
this.config.options.localAddress = config.options.localAddress;
}

if (config.options.lockTimeout !== undefined) {
if (typeof config.options.lockTimeout !== 'number') {
throw new TypeError('The "config.options.lockTimeout" property must be of type number.');
}

this.config.options.lockTimeout = config.options.lockTimeout;
}

if (config.options.multiSubnetFailover !== undefined) {
if (typeof config.options.multiSubnetFailover !== 'boolean') {
throw new TypeError('The "config.options.multiSubnetFailover" property must be of type boolean.');
Expand Down Expand Up @@ -2595,6 +2612,10 @@ class Connection extends EventEmitter {
options.push(`set language ${this.config.options.language}`);
}

if (this.config.options.lockTimeout !== undefined) {
options.push(`set lock_timeout ${this.config.options.lockTimeout}`);
}

if (this.config.options.enableNumericRoundabort === true) {
options.push('set numeric_roundabort on');
} else if (this.config.options.enableNumericRoundabort === false) {
Expand Down
53 changes: 53 additions & 0 deletions test/integration/connection-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2268,3 +2268,56 @@ describe('Boolean Config Options Test', function() {
testBadBooleanConfigOption(done, 'abortTransactionOnError');
});
});

describe('should test lock timeout', function() {
/**
* @param {Mocha.Done} done
* @param {number | undefined} lockTimeout
*/
function testLockTimeout(done, lockTimeout) {
const config = getConfig();

const connection = new Connection({
...config,
options: {
...config.options,
lockTimeout: lockTimeout
}
});
lockTimeout = lockTimeout ?? -1;

if (process.env.TEDIOUS_DEBUG) {
connection.on('debug', console.log);
}

const request = new Request(
'SELECT @@LOCK_TIMEOUT',
function(err) {
assert.ifError(err);
connection.close();
}
);

request.on('row', function(columns) {
const lockTimeoutActual = columns[0].value;
assert.strictEqual(lockTimeoutActual, lockTimeout);
});

connection.connect(function(err) {
assert.ifError(err);
connection.execSql(request);
});

connection.on('end', function() {
done();
});
}

it('should test lock timeout default', function(done) {
testLockTimeout(done, undefined);
});

it('should test lock timeout custom', function(done) {
testLockTimeout(done, 1000);
});
});
Loading