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
41 changes: 26 additions & 15 deletions lib/tedious/request.js
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,10 @@ const valueCorrection = function (value, metadata) {

const parameterCorrection = function (value) {
if (value instanceof Table) {
// Use the fully qualified TVP type name as constructed by Table
// Use only schema.name or name for TVP type
// Avoid duplicating schema if already present in name
// Use value.name as the TVP type name, do not prepend schema
const tvp = {
name: value.name,
schema: value.schema,
Expand Down Expand Up @@ -360,6 +364,7 @@ class Request extends BaseRequest {
*/

_query (command, callback) {

super._query(command, err => {
if (err) return callback(err)

Expand Down Expand Up @@ -450,49 +455,55 @@ class Request extends BaseRequest {
if (this.stream) this.emit('error', e)
errors.push(e)
}
})
});

// process batch outputs
if (batchHasOutput) {
if (!this.stream) batchLastRow = recordsets.pop()[0]
if (!this.stream) batchLastRow = recordsets.pop()[0];

for (const name in batchLastRow) {
const value = batchLastRow[name]
const value = batchLastRow[name];
if (name !== '___return___') {
output[name] = value
output[name] = value;
}
}
}

delete this._cancel
delete this._cancel;

let error
let error;
if (errors.length && !this.stream) {
error = errors.pop()
error.precedingErrors = errors
error = errors.pop();
error.precedingErrors = errors;
}

if (!hasReturned) {
for (const event in errorHandlers) {
connection.removeListener(event, errorHandlers[event])
connection.removeListener(event, errorHandlers[event]);
}

this.parent.release(connection)
hasReturned = true
this.parent.release(connection);
hasReturned = true;

if (error) {
debug('request(%d): failed', IDS.get(this), error)
debug('request(%d): failed', IDS.get(this), error);
} else {
debug('request(%d): completed', IDS.get(this))
debug('request(%d): completed', IDS.get(this));
}

if (this.stream) {
callback(null, null, output, rowsAffected, recordsetcolumns)
callback(null, null, output, rowsAffected, recordsetcolumns);
} else {
callback(error, recordsets, output, rowsAffected, recordsetcolumns)
callback(error, recordsets, output, rowsAffected, recordsetcolumns);
}
}
})
// Assign per-request timeout to tedious Request if set
if (this.requestTimeout !== undefined) {
req.timeout = this.requestTimeout;
}



this._setCurrentRequest(req)

Expand Down
38 changes: 37 additions & 1 deletion test/common/tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -1852,7 +1852,43 @@ module.exports = (sql, driver) => {

done()
}).catch(done)
}
},
'Fix default requestTimeout is above 15s'(done) {
const req = new TestRequest();
req.requestTimeout = 25000; // 25 seconds
const start = Date.now();
req.query("WAITFOR DELAY '00:00:20.000';").then(result => {
const elapsed = Date.now() - start;
assert.ok(!result.error, 'Should not error for long WAITFOR DELAY with high timeout');
assert(elapsed >= 20000, 'Query should take at least 20 seconds');
done();
}).catch(done);
},
'TVP with schema-qualified name triggers bug'(done) {
(async () => {
let pool;
try {
pool = await sql.connect(readConfig());
const request = pool.request();
const tvp = new sql.Table('AI.UDT_StringArray');
tvp.columns.add('Name', sql.NVarChar(128), { nullable: false });
tvp.rows.add('TestValue1');
tvp.rows.add('TestValue2');
request.input('InputList', tvp);
await request.execute('AI.USP_TestProcedure');
} catch (err) {
if (err && /Cannot find data type UDT_StringArray/.test(err.message)) {
return done();
}
if (err && /could not find|does not exist|invalid object/i.test(err.message)) {
return done();
}
done(err);
} finally {
if (pool) await sql.close();
}
})();
},
}
}

Expand Down
8 changes: 7 additions & 1 deletion test/tedious/tedious.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

/* globals describe, it, before, after, afterEach */

// Increase Mocha timeout for long-running tests
this.timeout && this.timeout(30000);

const sql = require('../../tedious.js')
const assert = require('node:assert')
const { join } = require('node:path')
Expand All @@ -24,7 +27,8 @@ const config = function () {
let connection1 = null
let connection2 = null

describe('tedious', () => {
describe('tedious', function () {
this.timeout(30000); // Increase Mocha timeout for all tests in this suite
before(done =>
sql.connect(config(), err => {
if (err) return done(err)
Expand Down Expand Up @@ -105,6 +109,8 @@ describe('tedious', () => {
it('type validation', done => TESTS['type validation']('query', done))
it('type validation (batch)', done => TESTS['type validation']('batch', done))
it('chunked xml support', done => TESTS['chunked xml support'](done))
it('Fix default requestTimeout is above 15s', done => TESTS['Fix default requestTimeout is above 15s'](done))
it('TVP with schema-qualified name triggers bug', done => TESTS['TVP with schema-qualified name triggers bug'](done))

after(done => sql.close(done))
})
Expand Down