From f76fb8717b5d74b6816cd5a1370a8bb77aca4135 Mon Sep 17 00:00:00 2001 From: Arthur Schreiber Date: Sun, 16 Apr 2023 13:55:06 +0200 Subject: [PATCH 1/5] ci: update windows sql server 2019 and 2022 update urls (#1538) --- .github/workflows/nodejs.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index ab74bff35..6ed84533d 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -200,12 +200,12 @@ jobs: '2022' { $exe_link = 'https://download.microsoft.com/download/3/8/d/38de7036-2433-4207-8eae-06e247e17b25/SQLServer2022-DEV-x64-ENU.exe' $box_link = 'https://download.microsoft.com/download/3/8/d/38de7036-2433-4207-8eae-06e247e17b25/SQLServer2022-DEV-x64-ENU.box' - $update_link = 'https://download.microsoft.com/download/9/6/8/96819b0c-c8fb-4b44-91b5-c97015bbda9f/SQLServer2022-KB5023127-x64.exe' + $update_link = 'https://download.microsoft.com/download/9/6/8/96819b0c-c8fb-4b44-91b5-c97015bbda9f/SQLServer2022-KB5024396-x64.exe' } '2019' { $exe_link = 'https://download.microsoft.com/download/8/4/c/84c6c430-e0f5-476d-bf43-eaaa222a72e0/SQLServer2019-DEV-x64-ENU.exe' $box_link = 'https://download.microsoft.com/download/8/4/c/84c6c430-e0f5-476d-bf43-eaaa222a72e0/SQLServer2019-DEV-x64-ENU.box' - $update_link = 'https://download.microsoft.com/download/6/e/7/6e72dddf-dfa4-4889-bc3d-e5d3a0fd11ce/SQLServer2019-KB5023049-x64.exe' + $update_link = 'https://download.microsoft.com/download/6/e/7/6e72dddf-dfa4-4889-bc3d-e5d3a0fd11ce/SQLServer2019-KB5024276-x64.exe' } '2017' { $exe_link = 'https://download.microsoft.com/download/E/F/2/EF23C21D-7860-4F05-88CE-39AA114B014B/SQLServer2017-DEV-x64-ENU.exe' From d075b9c38016f7740c7f2f97fa77de9b59981ec3 Mon Sep 17 00:00:00 2001 From: Arthur Schreiber Date: Sun, 16 Apr 2023 14:26:18 +0200 Subject: [PATCH 2/5] chore: upgrade to `node-abort-controller@3.1.1` (#1537) --- package-lock.json | 14 +++++++------- package.json | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5202cca02..caac867a9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,7 +18,7 @@ "js-md4": "^0.3.2", "jsbi": "^4.3.0", "native-duplexpair": "^1.0.0", - "node-abort-controller": "^3.0.1", + "node-abort-controller": "^3.1.1", "punycode": "^2.1.0", "sprintf-js": "^1.1.2" }, @@ -9811,9 +9811,9 @@ } }, "node_modules/node-abort-controller": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.0.1.tgz", - "integrity": "sha512-/ujIVxthRs+7q6hsdjHMaj8hRG9NuWmwrz+JdRwZ14jdFoKSkm+vDsCbF9PLpnSqjaWQJuTmVtcWHNLr+vrOFw==" + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz", + "integrity": "sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==" }, "node_modules/node-emoji": { "version": "1.11.0", @@ -22769,9 +22769,9 @@ } }, "node-abort-controller": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.0.1.tgz", - "integrity": "sha512-/ujIVxthRs+7q6hsdjHMaj8hRG9NuWmwrz+JdRwZ14jdFoKSkm+vDsCbF9PLpnSqjaWQJuTmVtcWHNLr+vrOFw==" + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz", + "integrity": "sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==" }, "node-emoji": { "version": "1.11.0", diff --git a/package.json b/package.json index c3b9ad42e..8a4c15272 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "js-md4": "^0.3.2", "jsbi": "^4.3.0", "native-duplexpair": "^1.0.0", - "node-abort-controller": "^3.0.1", + "node-abort-controller": "^3.1.1", "punycode": "^2.1.0", "sprintf-js": "^1.1.2" }, @@ -64,11 +64,11 @@ "@commitlint/cli": "^16.2.4", "@commitlint/config-conventional": "^16.2.4", "@commitlint/travis-cli": "^16.2.4", - "@types/es-aggregate-error": "^1.0.2", "@types/async": "^3.2.13", "@types/bl": "^5.0.2", "@types/chai": "^4.3.1", "@types/depd": "^1.1.32", + "@types/es-aggregate-error": "^1.0.2", "@types/lru-cache": "^5.1.0", "@types/mocha": "^9.1.1", "@types/node": "^12.20.50", From e4eadf858e1c4ab1f271af58a0b7954f8e131784 Mon Sep 17 00:00:00 2001 From: Ruy Adorno Date: Sat, 6 May 2023 10:02:15 -0300 Subject: [PATCH 3/5] feat: add connector factory method (#1540) This adds a new `connector` config option that may be used to define a custom socket factory method, providing much more flexible control of the socket connection creation. --- examples/custom-connector.js | 30 +++++++++++++++++ src/connection.ts | 25 +++++++++++--- test/unit/custom-connector.js | 62 +++++++++++++++++++++++++++++++++++ 3 files changed, 113 insertions(+), 4 deletions(-) create mode 100644 examples/custom-connector.js create mode 100644 test/unit/custom-connector.js diff --git a/examples/custom-connector.js b/examples/custom-connector.js new file mode 100644 index 000000000..45057addd --- /dev/null +++ b/examples/custom-connector.js @@ -0,0 +1,30 @@ +var net = require('net'); +var Connection = require('../lib/tedious').Connection; + +var config = { + server: '192.168.1.212', + authentication: { + type: 'default', + options: { + userName: 'test', + password: 'test' + } + }, + options: { + connector: async () => net.connect({ + host: '192.168.1.212', + port: 1433, + }) + } +}; + +const connection = new Connection(config); + +connection.connect((err) => { + if (err) { + console.log('Connection Failed'); + throw err; + } + + console.log('Custom connection Succeeded'); +}); diff --git a/src/connection.ts b/src/connection.ts index 20d35fd6c..4241efc85 100644 --- a/src/connection.ts +++ b/src/connection.ts @@ -343,6 +343,7 @@ export interface InternalConnectionOptions { columnEncryptionSetting: boolean; columnNameReplacer: undefined | ((colName: string, index: number, metadata: Metadata) => string); connectionRetryInterval: number; + connector: undefined | (() => Promise); connectTimeout: number; connectionIsolationLevel: typeof ISOLATION_LEVEL[keyof typeof ISOLATION_LEVEL]; cryptoCredentialsDetails: SecureContextOptions; @@ -535,6 +536,13 @@ export interface ConnectionOptions { */ connectionRetryInterval?: number; + /** + * Custom connector factory method. + * + * (default: `undefined`) + */ + connector?: () => Promise; + /** * The number of milliseconds before the attempt to connect is considered failed * @@ -1222,6 +1230,7 @@ class Connection extends EventEmitter { columnNameReplacer: undefined, connectionRetryInterval: DEFAULT_CONNECT_RETRY_INTERVAL, connectTimeout: DEFAULT_CONNECT_TIMEOUT, + connector: undefined, connectionIsolationLevel: ISOLATION_LEVEL.READ_COMMITTED, cryptoCredentialsDetails: {}, database: undefined, @@ -1330,6 +1339,14 @@ class Connection extends EventEmitter { this.config.options.connectTimeout = config.options.connectTimeout; } + if (config.options.connector !== undefined) { + if (typeof config.options.connector !== 'function') { + throw new TypeError('The "config.options.connector" property must be a function.'); + } + + this.config.options.connector = config.options.connector; + } + if (config.options.cryptoCredentialsDetails !== undefined) { if (typeof config.options.cryptoCredentialsDetails !== 'object' || config.options.cryptoCredentialsDetails === null) { throw new TypeError('The "config.options.cryptoCredentialsDetails" property must be of type Object.'); @@ -1884,7 +1901,7 @@ class Connection extends EventEmitter { const signal = this.createConnectTimer(); if (this.config.options.port) { - return this.connectOnPort(this.config.options.port, this.config.options.multiSubnetFailover, signal); + return this.connectOnPort(this.config.options.port, this.config.options.multiSubnetFailover, signal, this.config.options.connector); } else { return instanceLookup({ server: this.config.server, @@ -1893,7 +1910,7 @@ class Connection extends EventEmitter { signal: signal }).then((port) => { process.nextTick(() => { - this.connectOnPort(port, this.config.options.multiSubnetFailover, signal); + this.connectOnPort(port, this.config.options.multiSubnetFailover, signal, this.config.options.connector); }); }, (err) => { this.clearConnectTimer(); @@ -1956,14 +1973,14 @@ class Connection extends EventEmitter { return new TokenStreamParser(message, this.debug, handler, this.config.options); } - connectOnPort(port: number, multiSubnetFailover: boolean, signal: AbortSignal) { + connectOnPort(port: number, multiSubnetFailover: boolean, signal: AbortSignal, customConnector?: () => Promise) { const connectOpts = { host: this.routingData ? this.routingData.server : this.config.server, port: this.routingData ? this.routingData.port : port, localAddress: this.config.options.localAddress }; - const connect = multiSubnetFailover ? connectInParallel : connectInSequence; + const connect = customConnector || (multiSubnetFailover ? connectInParallel : connectInSequence); connect(connectOpts, dns.lookup, signal).then((socket) => { process.nextTick(() => { diff --git a/test/unit/custom-connector.js b/test/unit/custom-connector.js new file mode 100644 index 000000000..36e49d19d --- /dev/null +++ b/test/unit/custom-connector.js @@ -0,0 +1,62 @@ +const net = require('net'); +const assert = require('chai').assert; + +const { Connection } = require('../../src/tedious'); + +describe('custom connector', function() { + let server; + + beforeEach(function(done) { + server = net.createServer(); + server.listen(0, '127.0.0.1', done); + }); + + afterEach(() => { + server.close(); + }); + + it('connection using a custom connector', function(done) { + let attemptedConnection = false; + let customConnectorCalled = false; + + server.on('connection', async (connection) => { + attemptedConnection = true; + // no need to test auth/login, just end the connection sooner + connection.end(); + }); + + const host = server.address().address; + const port = server.address().port; + const connection = new Connection({ + server: host, + options: { + connector: async () => { + customConnectorCalled = true; + return net.connect({ + host, + port, + }); + }, + port + }, + }); + + connection.on('end', (err) => { + // validates the connection was stablished using the custom connector + assert.isOk(attemptedConnection); + assert.isOk(customConnectorCalled); + + connection.close(); + done(); + }); + + connection.on('error', (err) => { + // Connection lost errors are expected due to ending connection sooner + if (!/Connection lost/.test(err)) { + throw err; + } + }); + + connection.connect(); + }); +}); From 9070fa38cac4dcfcaf78f95a4a6585964d8edd82 Mon Sep 17 00:00:00 2001 From: mShan0 <96149598+mShan0@users.noreply.github.com> Date: Wed, 7 Jun 2023 12:24:22 -0700 Subject: [PATCH 4/5] ci: update windows ci download links (#1544) --- .github/workflows/nodejs.yml | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index 6ed84533d..f741f8112 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -194,28 +194,28 @@ jobs: run: | Push-Location C:\temp - $exe_link, $box_link, $update_link = '', '', '' + $exe_link, $box_link, $update_link, $update_download_link = '', '', '', '' switch (${{ matrix.mssql-version }}) { '2022' { $exe_link = 'https://download.microsoft.com/download/3/8/d/38de7036-2433-4207-8eae-06e247e17b25/SQLServer2022-DEV-x64-ENU.exe' $box_link = 'https://download.microsoft.com/download/3/8/d/38de7036-2433-4207-8eae-06e247e17b25/SQLServer2022-DEV-x64-ENU.box' - $update_link = 'https://download.microsoft.com/download/9/6/8/96819b0c-c8fb-4b44-91b5-c97015bbda9f/SQLServer2022-KB5024396-x64.exe' + $update_link = 'https://www.microsoft.com/en-us/download/confirmation.aspx?id=105013' } '2019' { $exe_link = 'https://download.microsoft.com/download/8/4/c/84c6c430-e0f5-476d-bf43-eaaa222a72e0/SQLServer2019-DEV-x64-ENU.exe' $box_link = 'https://download.microsoft.com/download/8/4/c/84c6c430-e0f5-476d-bf43-eaaa222a72e0/SQLServer2019-DEV-x64-ENU.box' - $update_link = 'https://download.microsoft.com/download/6/e/7/6e72dddf-dfa4-4889-bc3d-e5d3a0fd11ce/SQLServer2019-KB5024276-x64.exe' + $update_link = 'https://www.microsoft.com/en-us/download/confirmation.aspx?id=100809' } '2017' { $exe_link = 'https://download.microsoft.com/download/E/F/2/EF23C21D-7860-4F05-88CE-39AA114B014B/SQLServer2017-DEV-x64-ENU.exe' $box_link = 'https://download.microsoft.com/download/E/F/2/EF23C21D-7860-4F05-88CE-39AA114B014B/SQLServer2017-DEV-x64-ENU.box' - $update_link = 'https://download.microsoft.com/download/C/4/F/C4F908C9-98ED-4E5F-88D5-7D6A5004AEBD/SQLServer2017-KB5016884-x64.exe' + $update_link = 'https://www.microsoft.com/en-us/download/confirmation.aspx?id=56128' } '2016' { $exe_link = 'https://download.microsoft.com/download/4/1/A/41AD6EDE-9794-44E3-B3D5-A1AF62CD7A6F/sql16_sp2_dlc/en-us/SQLServer2016SP2-FullSlipstream-DEV-x64-ENU.exe' $box_link = 'https://download.microsoft.com/download/4/1/A/41AD6EDE-9794-44E3-B3D5-A1AF62CD7A6F/sql16_sp2_dlc/en-us/SQLServer2016SP2-FullSlipstream-DEV-x64-ENU.box' - $update_link = 'https://download.microsoft.com/download/a/7/7/a77b5753-8fe7-4804-bfc5-591d9a626c98/SQLServer2016SP3-KB5003279-x64-ENU.exe' + $update_download_link = 'https://download.microsoft.com/download/a/7/7/a77b5753-8fe7-4804-bfc5-591d9a626c98/SQLServer2016SP3-KB5003279-x64-ENU.exe' } default { Write-Error "Invalid SQL Server version specified: ${{ matrix.mssql-version }}" @@ -223,9 +223,20 @@ jobs: } } + if (${{ matrix.mssql-version }} -ne '2016') { + $dl_links = ((Invoke-WebRequest -Uri $update_link).Links | Where-Object {$_.href -like 'https://download.microsoft.com/*'}) + if ($dl_links.count -gt 0) { + $update_download_link = [System.Uri]::new($dl_links[0].href) + } else { + Write-Error "Download link not found" + Exit 1 + } + echo $update_download_link + } + + Invoke-WebRequest -Uri $update_download_link -Outfile sqlupdate.exe Invoke-WebRequest -Uri $exe_link -OutFile sqlsetup.exe Invoke-WebRequest -Uri $box_link -OutFile sqlsetup.box - Invoke-WebRequest -Uri $update_link -Outfile sqlupdate.exe Start-Process -Wait -FilePath ./sqlsetup.exe -ArgumentList /qs, /x:setup From ed02374bf5fdc541ca7fdde0eb34b9a60d9e63de Mon Sep 17 00:00:00 2001 From: Adam <34376104+AdamJohnSwan@users.noreply.github.com> Date: Wed, 7 Jun 2023 15:26:49 -0400 Subject: [PATCH 5/5] docs: add comment about a request lasting longer than its timeout (#1486) docs: add a comment on how a sql query can have potential to run longer than the configured timeout Co-authored-by: Adam S --- src/connection.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/connection.ts b/src/connection.ts index 4241efc85..eef8385e1 100644 --- a/src/connection.ts +++ b/src/connection.ts @@ -765,7 +765,9 @@ export interface ConnectionOptions { readOnlyIntent?: boolean; /** - * The number of milliseconds before a request is considered failed, or `0` for no timeout + * The number of milliseconds before a request is considered failed, or `0` for no timeout. + * + * As soon as a response is received, the timeout is cleared. This means that queries that immediately return a response have ability to run longer than this timeout. * * (default: `15000`). */