UNPKG

72.6 kBMarkdownView Raw
1# node-mssql
2
3**Microsoft SQL Server client for Node.js**
4
5[![NPM Version][npm-image]][npm-url] [![NPM Downloads][downloads-image]][downloads-url] [![Appveyor CI][appveyor-image]][appveyor-url] [![Join the chat at https://gitter.im/patriksimek/node-mssql](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/patriksimek/node-mssql?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
6
7Supported TDS drivers:
8
9- [Tedious][tedious-url] (pure JavaScript - Windows/macOS/Linux, default)
10- [MSNodeSQLv8][msnodesqlv8-url] (Microsoft / Contributors Node V8 Driver for Node.js for SQL Server, v2 native - Windows or Linux/macOS 64 bits only)
11
12## Installation
13
14### Tedious driver (default)
15
16```
17npm install mssql
18```
19
20### MSNodeSQLv8 driver (optional)
21
22```
23npm install mssql msnodesqlv8
24```
25
26## SQL Server prerequisites
27
28This package requires TCP/IP to connect to SQL Server, and you may need to enable this in your installation.
29
30## Short Example: Use Connect String
31
32```javascript
33const sql = require('mssql')
34
35(async () => {
36 try {
37 // make sure that any items are correctly URL encoded in the connection string
38 await sql.connect('Server=localhost,1433;Database=database;User Id=username;Password=password;Encrypt=true')
39 const result = await sql.query`select * from mytable where id = ${value}`
40 console.dir(result)
41 } catch (err) {
42 // ... error checks
43 }
44})()
45```
46
47If you're on Windows Azure, add `?encrypt=true` to your connection string. See [docs](#configuration) to learn more.
48
49Parts of the connection URI should be correctly URL encoded so that the URI can be parsed correctly.
50
51## Longer Example: Connect via Config Object
52
53Assuming you have set the appropriate environment variables, you can construct a config object as follows:
54
55```javascript
56const sql = require('mssql')
57
58const sqlConfig = {
59 user: process.env.DB_USER,
60 password: process.env.DB_PWD,
61 database: process.env.DB_NAME,
62 server: 'localhost',
63 pool: {
64 max: 10,
65 min: 0,
66 idleTimeoutMillis: 30000
67 },
68 options: {
69 encrypt: true, // for azure
70 trustServerCertificate: false // change to true for local dev / self-signed certs
71 }
72}
73
74(async () => {
75 try {
76 // make sure that any items are correctly URL encoded in the connection string
77 await sql.connect(sqlConfig)
78 const result = await sql.query`select * from mytable where id = ${value}`
79 console.dir(result)
80 } catch (err) {
81 // ... error checks
82 }
83})()
84```
85
86## Windows Authentication Example Using MSNodeSQLv8
87
88```javascript
89const sql = require('mssql/msnodesqlv8');
90
91const config = {
92 server: "MyServer",
93 database: "MyDatabase",
94 options: {
95 trustedConnection: true, // Set to true if using Windows Authentication
96 trustServerCertificate: true, // Set to true if using self-signed certificates
97 },
98 driver: "msnodesqlv8", // Required if using Windows Authentication
99};
100
101(async () => {
102 try {
103 await sql.connect(config);
104 const result = await sql.query`select TOP 10 * from MyTable`;
105 console.dir(result);
106 } catch (err) {
107 console.error(err);
108 }
109})();
110```
111
112## Documentation
113
114### Examples
115
116* [Async/Await](#asyncawait)
117* [Promises](#promises)
118* [ES6 Tagged template literals](#es6-tagged-template-literals)
119* [Callbacks](#callbacks)
120* [Streaming](#streaming)
121* [Connection Pools](#connection-pools)
122
123### Configuration
124
125* [General](#general-same-for-all-drivers)
126* [Formats](#formats)
127
128### Drivers
129
130* [Tedious](#tedious)
131* [MSNodeSQLv8](#msnodesqlv8)
132
133### Connections
134
135* [Pool Management](#pool-management)
136* [ConnectionPool](#connections-1)
137* [connect](#connect-callback)
138* [close](#close)
139
140### Requests
141
142* [Request](#request)
143* [execute](#execute-procedure-callback)
144* [input](#input-name-type-value)
145* [output](#output-name-type-value)
146* [toReadableStream](#toReadableStream)
147* [pipe](#pipe-stream)
148* [query](#query-command-callback)
149* [batch](#batch-batch-callback)
150* [bulk](#bulk-table-options-callback)
151* [cancel](#cancel)
152
153### Transactions
154
155* [Transaction](#transaction)
156* [begin](#begin-isolationlevel-callback)
157* [commit](#commit-callback)
158* [rollback](#rollback-callback)
159
160### Prepared Statements
161
162* [PreparedStatement](#prepared-statement)
163* [input](#input-name-type)
164* [output](#output-name-type)
165* [prepare](#prepare-statement-callback)
166* [execute](#execute-values-callback)
167* [unprepare](#unprepare-callback)
168
169### Other
170
171* [CLI](#cli)
172* [Geography and Geometry](#geography-and-geometry)
173* [Table-Valued Parameter](#table-valued-parameter-tvp)
174* [Response Schema](#response-schema)
175* [Affected Rows](#affected-rows)
176* [JSON support](#json-support)
177* [Handling Duplicate Column Names](#handling-duplicate-column-names)
178* [Errors](#errors)
179* [Informational messages](#informational-messages)
180* [Metadata](#metadata)
181* [Data Types](#data-types)
182* [SQL injection](#sql-injection)
183* [Known Issues](#known-issues)
184* [Contributing](https://github.com/tediousjs/node-mssql/wiki/Contributing)
185* [8.x to 9.x changes](#8x-to-9x-changes)
186* [7.x to 8.x changes](#7x-to-8x-changes)
187* [6.x to 7.x changes](#6x-to-7x-changes)
188* [5.x to 6.x changes](#5x-to-6x-changes)
189* [4.x to 5.x changes](#4x-to-5x-changes)
190* [3.x to 4.x changes](#3x-to-4x-changes)
191* [3.x Documentation](https://github.com/tediousjs/node-mssql/blob/1893969195045a250f0fdeeb2de7f30dcf6689ad/README.md)
192
193## Examples
194
195### Config
196
197```javascript
198const config = {
199 user: '...',
200 password: '...',
201 server: 'localhost', // You can use 'localhost\\instance' to connect to named instance
202 database: '...',
203}
204```
205
206
207### Async/Await
208
209```javascript
210const sql = require('mssql')
211
212(async function () {
213 try {
214 let pool = await sql.connect(config)
215 let result1 = await pool.request()
216 .input('input_parameter', sql.Int, value)
217 .query('select * from mytable where id = @input_parameter')
218
219 console.dir(result1)
220
221 // Stored procedure
222
223 let result2 = await pool.request()
224 .input('input_parameter', sql.Int, value)
225 .output('output_parameter', sql.VarChar(50))
226 .execute('procedure_name')
227
228 console.dir(result2)
229 } catch (err) {
230 // ... error checks
231 }
232})()
233
234sql.on('error', err => {
235 // ... error handler
236})
237```
238
239### Promises
240
241#### Queries
242
243```javascript
244const sql = require('mssql')
245
246sql.on('error', err => {
247 // ... error handler
248})
249
250sql.connect(config).then(pool => {
251 // Query
252
253 return pool.request()
254 .input('input_parameter', sql.Int, value)
255 .query('select * from mytable where id = @input_parameter')
256}).then(result => {
257 console.dir(result)
258}).catch(err => {
259 // ... error checks
260});
261```
262
263#### Stored procedures
264
265```js
266const sql = require('mssql')
267
268sql.on('error', err => {
269 // ... error handler
270})
271
272sql.connect(config).then(pool => {
273
274 // Stored procedure
275
276 return pool.request()
277 .input('input_parameter', sql.Int, value)
278 .output('output_parameter', sql.VarChar(50))
279 .execute('procedure_name')
280}).then(result => {
281 console.dir(result)
282}).catch(err => {
283 // ... error checks
284})
285```
286
287Native Promise is used by default. You can easily change this with `sql.Promise = require('myownpromisepackage')`.
288
289### ES6 Tagged template literals
290
291```javascript
292const sql = require('mssql')
293
294sql.connect(config).then(() => {
295 return sql.query`select * from mytable where id = ${value}`
296}).then(result => {
297 console.dir(result)
298}).catch(err => {
299 // ... error checks
300})
301
302sql.on('error', err => {
303 // ... error handler
304})
305```
306
307All values are automatically sanitized against sql injection.
308This is because it is rendered as prepared statement, and thus all limitations imposed in MS SQL on parameters apply.
309e.g. Column names cannot be passed/set in statements using variables.
310
311### Callbacks
312
313```javascript
314const sql = require('mssql')
315
316sql.connect(config, err => {
317 // ... error checks
318
319 // Query
320
321 new sql.Request().query('select 1 as number', (err, result) => {
322 // ... error checks
323
324 console.dir(result)
325 })
326
327 // Stored Procedure
328
329 new sql.Request()
330 .input('input_parameter', sql.Int, value)
331 .output('output_parameter', sql.VarChar(50))
332 .execute('procedure_name', (err, result) => {
333 // ... error checks
334
335 console.dir(result)
336 })
337
338 // Using template literal
339
340 const request = new sql.Request()
341 request.query(request.template`select * from mytable where id = ${value}`, (err, result) => {
342 // ... error checks
343 console.dir(result)
344 })
345})
346
347sql.on('error', err => {
348 // ... error handler
349})
350```
351
352### Streaming
353
354If you plan to work with large amount of rows, you should always use streaming. Once you enable this, you must listen for events to receive data.
355
356```javascript
357const sql = require('mssql')
358
359sql.connect(config, err => {
360 // ... error checks
361
362 const request = new sql.Request()
363 request.stream = true // You can set streaming differently for each request
364 request.query('select * from verylargetable') // or request.execute(procedure)
365
366 request.on('recordset', columns => {
367 // Emitted once for each recordset in a query
368 })
369
370 request.on('row', row => {
371 // Emitted for each row in a recordset
372 })
373
374 request.on('rowsaffected', rowCount => {
375 // Emitted for each `INSERT`, `UPDATE` or `DELETE` statement
376 // Requires NOCOUNT to be OFF (default)
377 })
378
379 request.on('error', err => {
380 // May be emitted multiple times
381 })
382
383 request.on('done', result => {
384 // Always emitted as the last one
385 })
386})
387
388sql.on('error', err => {
389 // ... error handler
390})
391```
392
393When streaming large sets of data you want to back-off or chunk the amount of data you're processing
394 to prevent memory exhaustion issues; you can use the `Request.pause()` function to do this. Here is
395 an example of managing rows in batches of 15:
396
397```javascript
398let rowsToProcess = [];
399request.on('row', row => {
400 rowsToProcess.push(row);
401 if (rowsToProcess.length >= 15) {
402 request.pause();
403 processRows();
404 }
405});
406request.on('done', () => {
407 processRows();
408});
409
410function processRows() {
411 // process rows
412 rowsToProcess = [];
413 request.resume();
414}
415```
416
417## Connection Pools
418
419An important concept to understand when using this library is [Connection Pooling](https://en.wikipedia.org/wiki/Connection_pool) as this library uses connection pooling extensively. As one Node JS process is able to handle multiple requests at once, we can take advantage of this long running process to create a pool of database connections for reuse; this saves overhead of connecting to the database for each request
420(as would be the case in something like PHP, where one process handles one request).
421
422With the advantages of pooling comes some added complexities, but these are mostly just conceptual and once you understand how the pooling is working, it is simple to make use of it efficiently and effectively.
423
424### The Global Connection Pool
425
426To assist with pool management in your application there is the `sql.connect()` function that is used to connect to the global connection pool. You can make repeated calls to this function, and if the global pool is already connected, it will resolve to the connected pool. The following example obtains the global connection pool by running `sql.connect()`, and then runs the query against the pool.
427
428NB: It's important to note that there can only be one global connection pool connected at a time. Providing a different connection config to the `connect()` function will not create a new connection if it is already connected.
429
430```js
431const sql = require('mssql')
432const config = { ... }
433
434// run a query against the global connection pool
435function runQuery(query) {
436 // sql.connect() will return the existing global pool if it exists or create a new one if it doesn't
437 return sql.connect(config).then((pool) => {
438 return pool.query(query)
439 })
440}
441```
442
443Awaiting or `.then`-ing the pool creation is a safe way to ensure that the pool is always ready, without knowing where it is needed first. In practice, once the pool is created then there will be no delay for the next `connect()` call.
444
445Also notice that we do *not* close the global pool by calling `sql.close()` after the query is executed, because other queries may need to be run against this pool and closing it will add additional overhead to running subsequent queries. You should only ever close the global pool if you're certain the application is finished. Or for example, if you are running some kind of CLI tool or a CRON job you can close the pool at the end of the script.
446
447### Global Pool Single Instance
448
449The ability to call `connect()` and `close()` repeatedly on the global pool is intended to make pool management easier, however it is better to maintain your own reference to the pool, where `connect()` is called **once**, and the resulting global pool's connection promise is re-used throughout the entire application.
450
451For example, in Express applications, the following approach uses a single global pool instance added to the `app.locals` so the application has access to it when needed. The server start is then chained inside the `connect()` promise.
452
453```js
454const express = require('express')
455const sql = require('mssql')
456const config = {/*...*/}
457//instantiate a connection pool
458const appPool = new sql.ConnectionPool(config)
459//require route handlers and use the same connection pool everywhere
460const route1 = require('./routes/route1')
461const app = express()
462app.get('/path', route1)
463
464//connect the pool and start the web server when done
465appPool.connect().then(function(pool) {
466 app.locals.db = pool;
467 const server = app.listen(3000, function () {
468 const host = server.address().address
469 const port = server.address().port
470 console.log('Example app listening at http://%s:%s', host, port)
471 })
472}).catch(function(err) {
473 console.error('Error creating connection pool', err)
474});
475```
476
477Then the route uses the connection pool in the `app.locals` object:
478
479```js
480// ./routes/route1.js
481const sql = require('mssql');
482
483module.exports = function(req, res) {
484 req.app.locals.db.query('SELECT TOP 10 * FROM table_name', function(err, recordset) {
485 if (err) {
486 console.error(err)
487 res.status(500).send('SERVER ERROR')
488 return
489 }
490 res.status(200).json({ message: 'success' })
491 })
492}
493```
494
495### Advanced Pool Management
496
497For some use-cases you may want to implement your own connection pool management, rather than using the global connection pool. Reasons for doing this include:
498
499* Supporting connections to multiple databases
500* Creation of separate pools for read vs read/write operations
501
502The following code is an example of a custom connection pool implementation.
503
504```js
505// pool-manager.js
506const mssql = require('mssql')
507const pools = new Map();
508
509module.exports = {
510 /**
511 * Get or create a pool. If a pool doesn't exist the config must be provided.
512 * If the pool does exist the config is ignored (even if it was different to the one provided
513 * when creating the pool)
514 *
515 * @param {string} name
516 * @param {{}} [config]
517 * @return {Promise.<mssql.ConnectionPool>}
518 */
519 get: (name, config) => {
520 if (!pools.has(name)) {
521 if (!config) {
522 throw new Error('Pool does not exist');
523 }
524 const pool = new mssql.ConnectionPool(config);
525 // automatically remove the pool from the cache if `pool.close()` is called
526 const close = pool.close.bind(pool);
527 pool.close = (...args) => {
528 pools.delete(name);
529 return close(...args);
530 }
531 pools.set(name, pool.connect());
532 }
533 return pools.get(name);
534 },
535 /**
536 * Closes all the pools and removes them from the store
537 *
538 * @return {Promise<mssql.ConnectionPool[]>}
539 */
540 closeAll: () => Promise.all(Array.from(pools.values()).map((connect) => {
541 return connect.then((pool) => pool.close());
542 })),
543};
544```
545
546This file can then be used in your application to create, fetch, and close pools.
547
548```js
549const { get } = require('./pool-manager')
550
551async function example() {
552 const pool = await get('default')
553 return pool.request().query('SELECT 1')
554}
555```
556
557Similar to the global connection pool, you should aim to only close a pool when you know it will never be needed by the application again. Typically this will only be when your application is shutting down.
558
559### Result value manipulation
560
561In some instances it is desirable to manipulate the record data as it is returned from the database, this may be to cast it as a particular object (eg: `moment` object instead of `Date`) or similar.
562
563In v8.0.0+ it is possible to register per-datatype handlers:
564
565```js
566const sql = require('mssql')
567
568// in this example all integer values will return 1 more than their actual value in the database
569sql.valueHandler.set(sql.TYPES.Int, (value) => value + 1)
570
571sql.query('SELECT * FROM [example]').then((result) => {
572 // all `int` columns will return a manipulated value as per the callback above
573})
574```
575
576## Configuration
577
578The following is an example configuration object:
579
580```javascript
581const config = {
582 user: '...',
583 password: '...',
584 server: 'localhost',
585 database: '...',
586 pool: {
587 max: 10,
588 min: 0,
589 idleTimeoutMillis: 30000
590 }
591}
592```
593
594### General (same for all drivers)
595
596- **user** - User name to use for authentication.
597- **password** - Password to use for authentication.
598- **server** - Server to connect to. You can use 'localhost\\instance' to connect to named instance.
599- **port** - Port to connect to (default: `1433`). Don't set when connecting to named instance.
600- **domain** - Once you set domain, driver will connect to SQL Server using domain login.
601- **database** - Database to connect to (default: dependent on server configuration).
602- **connectionTimeout** - Connection timeout in ms (default: `15000`).
603- **requestTimeout** - Request timeout in ms (default: `15000`). NOTE: msnodesqlv8 driver doesn't support timeouts < 1 second. When passed via connection string, the key must be `request timeout`
604- **stream** - Stream recordsets/rows instead of returning them all at once as an argument of callback (default: `false`). You can also enable streaming for each request independently (`request.stream = true`). Always set to `true` if you plan to work with large amount of rows.
605- **parseJSON** - Parse JSON recordsets to JS objects (default: `false`). For more information please see section [JSON support](#json-support).
606- **pool.max** - The maximum number of connections there can be in the pool (default: `10`).
607- **pool.min** - The minimum of connections there can be in the pool (default: `0`).
608- **pool.idleTimeoutMillis** - The Number of milliseconds before closing an unused connection (default: `30000`).
609- **arrayRowMode** - Return row results as a an array instead of a keyed object. Also adds `columns` array. (default: `false`) See [Handling Duplicate Column Names](#handling-duplicate-column-names)
610
611Complete list of pool options can be found [here](https://github.com/vincit/tarn.js/#usage).
612
613### Formats
614
615In addition to configuration object there is an option to pass config as a connection string. Connection strings are supported.
616
617##### Classic Connection String
618
619###### Standard configuration using tedious driver
620
621```
622Server=localhost,1433;Database=database;User Id=username;Password=password;Encrypt=true
623```
624###### Standard configuration using MSNodeSQLv8 driver
625```
626Driver=msnodesqlv8;Server=(local)\INSTANCE;Database=database;UID=DOMAIN\username;PWD=password;Encrypt=true
627```
628
629##### Azure Active Directory Authentication Connection String
630
631Several types of Azure Authentication are supported:
632
633###### Authentication using Active Directory Integrated
634```
635Server=*.database.windows.net;Database=database;Authentication=Active Directory Integrated;Client secret=clientsecret;Client Id=clientid;Tenant Id=tenantid;Encrypt=true
636```
637Note: Internally, the 'Active Directory Integrated' will change its type depending on the other parameters you add to it. On the example above, it will change to azure-active-directory-service-principal-secret because we supplied a Client Id, Client secret and Tenant Id.
638
639If you want to utilize Authentication tokens (azure-active-directory-access-token) Just remove the unnecessary additional parameters and supply only a token parameter, such as in this example:
640
641```
642Server=*.database.windows.net;Database=database;Authentication=Active Directory Integrated;token=token;Encrypt=true
643```
644
645Finally if you want to utilize managed identity services such as managed identity service app service you can follow this example below:
646```
647Server=*.database.windows.net;Database=database;Authentication=Active Directory Integrated;msi endpoint=msiendpoint;Client Id=clientid;msi secret=msisecret;Encrypt=true
648```
649or if its managed identity service virtual machines, then follow this:
650```
651Server=*.database.windows.net;Database=database;Authentication=Active Directory Integrated;msi endpoint=msiendpoint;Client Id=clientid;Encrypt=true
652```
653
654We can also utilizes Active Directory Password but unlike the previous examples, it is not part of the Active Directory Integrated Authentication.
655
656###### Authentication using Active Directory Password
657```
658Server=*.database.windows.net;Database=database;Authentication=Active Directory Password;User Id=username;Password=password;Client Id=clientid;Tenant Id=tenantid;Encrypt=true
659```
660
661For more reference, you can consult [here](https://tediousjs.github.io/tedious/api-connection.html#function_newConnection). Under the authentication.type parameter.
662
663## Drivers
664
665### Tedious
666
667Default driver, actively maintained and production ready. Platform independent, runs everywhere Node.js runs. Officially supported by Microsoft.
668
669**Extra options:**
670
671- **beforeConnect(conn)** - Function, which is invoked before opening the connection. The parameter `conn` is the configured tedious `Connection`. It can be used for attaching event handlers like in this example:
672```js
673require('mssql').connect({...config, beforeConnect: conn => {
674 conn.once('connect', err => { err ? console.error(err) : console.log('mssql connected')})
675 conn.once('end', err => { err ? console.error(err) : console.log('mssql disconnected')})
676}})
677```
678- **options.instanceName** - The instance name to connect to. The SQL Server Browser service must be running on the database server, and UDP port 1434 on the database server must be reachable.
679- **options.useUTC** - A boolean determining whether or not use UTC time for values without time zone offset (default: `true`).
680- **options.encrypt** - A boolean determining whether or not the connection will be encrypted (default: `true`).
681- **options.tdsVersion** - The version of TDS to use (default: `7_4`, available: `7_1`, `7_2`, `7_3_A`, `7_3_B`, `7_4`).
682- **options.appName** - Application name used for SQL server logging.
683- **options.abortTransactionOnError** - A boolean determining whether to rollback a transaction automatically if any error is encountered during the given transaction's execution. This sets the value for `XACT_ABORT` during the initial SQL phase of a connection.
684
685**Authentication:**
686
687On top of the extra options, an `authentication` property can be added to the pool config option
688
689- **authentication** - An object with authentication settings, according to the [Tedious Documentation](https://tediousjs.github.io/tedious/api-connection.html). Passing this object will override `user`, `password`, `domain` settings.
690- **authentication.type** - Type of the authentication method, valid types are `default`, `ntlm`, `azure-active-directory-password`, `azure-active-directory-access-token`, `azure-active-directory-msi-vm`, or `azure-active-directory-msi-app-service`
691- **authentication.options** - Options of the authentication required by the `tedious` driver, depends on `authentication.type`. For more details, check [Tedious Authentication Interfaces](https://github.com/tediousjs/tedious/blob/v11.1.1/src/connection.ts#L200-L318)
692- `tedious` does not support Windows Authentication/Trusted Connection, however the `msnodesqlv8` driver does.
693
694More information about Tedious specific options: http://tediousjs.github.io/tedious/api-connection.html
695
696___
697
698### MSNodeSQLv8
699
700Alternative driver, requires Node.js v10+ or newer; Windows (32 or 64-bit) or Linux/macOS (64-bit only). It's not part of the default package so it must be [installed](#msnodesqlv8-driver) in addition. Supports [Windows/Trusted Connection authentication](#windows-authentication-example-using-msnodesqlv8).
701
702**To use this driver you must use this `require` statement:**
703
704```javascript
705const sql = require('mssql/msnodesqlv8')
706```
707
708Note: If you use import into your lib to prepare your request (`const { VarChar } = require('mssql')`) you also need to upgrade all your types import into your code (`const { VarChar } = require('mssql/msnodesqlv8')`) or a `connection.on is not a function` error will be thrown.
709
710
711**Extra options:**
712
713- **beforeConnect(conn)** - Function, which is invoked before opening the connection. The parameter `conn` is the connection configuration, that can be modified to pass extra parameters to the driver's `open()` method.
714- **connectionString** - Connection string (default: see below).
715- **options.instanceName** - The instance name to connect to. The SQL Server Browser service must be running on the database server, and UDP port 1444 on the database server must be reachable.
716- **options.trustedConnection** - Use Windows Authentication (default: `false`).
717- **options.useUTC** - A boolean determining whether or not to use UTC time for values without time zone offset (default: `true`).
718
719Default connection string when connecting to port:
720```
721Driver={SQL Server Native Client 11.0};Server={#{server},#{port}};Database={#{database}};Uid={#{user}};Pwd={#{password}};Trusted_Connection={#{trusted}};
722```
723
724Default connection string when connecting to named instance:
725```
726Driver={SQL Server Native Client 11.0};Server={#{server}\\#{instance}};Database={#{database}};Uid={#{user}};Pwd={#{password}};Trusted_Connection={#{trusted}};
727```
728
729Please note that the connection string with this driver is not the same than tedious and use yes/no instead of true/false. You can see more on the [ODBC](https://docs.microsoft.com/fr-fr/dotnet/api/system.data.odbc.odbcconnection.connectionstring?view=dotnet-plat-ext-5.0) documentation.
730
731___
732
733## Connections
734
735Internally, each `ConnectionPool` instance is a separate pool of TDS connections. Once you create a new `Request`/`Transaction`/`Prepared Statement`, a new TDS connection is acquired from the pool and reserved for desired action. Once the action is complete, connection is released back to the pool. Connection health check is built-in so once the dead connection is discovered, it is immediately replaced with a new one.
736
737**IMPORTANT**: Always attach an `error` listener to created connection. Whenever something goes wrong with the connection it will emit an error and if there is no listener it will crash your application with an uncaught error.
738
739```javascript
740const pool = new sql.ConnectionPool({ /* config */ })
741```
742
743### Events
744
745- **error(err)** - Dispatched on connection error.
746
747---------------------------------------
748
749### connect ([callback])
750
751Create a new connection pool. The initial probe connection is created to find out whether the configuration is valid.
752
753__Arguments__
754
755- **callback(err)** - A callback which is called after initial probe connection has established, or an error has occurred. Optional. If omitted, returns [Promise](#promises).
756
757__Example__
758
759```javascript
760const pool = new sql.ConnectionPool({
761 user: '...',
762 password: '...',
763 server: 'localhost',
764 database: '...'
765})
766
767pool.connect(err => {
768 // ...
769})
770```
771
772__Errors__
773- ELOGIN (`ConnectionError`) - Login failed.
774- ETIMEOUT (`ConnectionError`) - Connection timeout.
775- EALREADYCONNECTED (`ConnectionError`) - Database is already connected!
776- EALREADYCONNECTING (`ConnectionError`) - Already connecting to database!
777- EINSTLOOKUP (`ConnectionError`) - Instance lookup failed.
778- ESOCKET (`ConnectionError`) - Socket error.
779
780---------------------------------------
781
782### close()
783
784Close all active connections in the pool.
785
786__Example__
787
788```javascript
789pool.close()
790```
791
792## Request
793
794```javascript
795const request = new sql.Request(/* [pool or transaction] */)
796```
797
798If you omit pool/transaction argument, global pool is used instead.
799
800### Events
801
802- **recordset(columns)** - Dispatched when metadata for new recordset are parsed.
803- **row(row)** - Dispatched when new row is parsed.
804- **done(returnValue)** - Dispatched when request is complete.
805- **error(err)** - Dispatched on error.
806- **info(message)** - Dispatched on informational message.
807
808---------------------------------------
809
810### execute (procedure, [callback])
811
812Call a stored procedure.
813
814__Arguments__
815
816- **procedure** - Name of the stored procedure to be executed.
817- **callback(err, recordsets, returnValue)** - A callback which is called after execution has completed, or an error has occurred. `returnValue` is also accessible as property of recordsets. Optional. If omitted, returns [Promise](#promises).
818
819__Example__
820
821```javascript
822const request = new sql.Request()
823request.input('input_parameter', sql.Int, value)
824request.output('output_parameter', sql.Int)
825request.execute('procedure_name', (err, result) => {
826 // ... error checks
827
828 console.log(result.recordsets.length) // count of recordsets returned by the procedure
829 console.log(result.recordsets[0].length) // count of rows contained in first recordset
830 console.log(result.recordset) // first recordset from result.recordsets
831 console.log(result.returnValue) // procedure return value
832 console.log(result.output) // key/value collection of output values
833 console.log(result.rowsAffected) // array of numbers, each number represents the number of rows affected by executed statemens
834
835 // ...
836})
837```
838
839__Errors__
840- EREQUEST (`RequestError`) - *Message from SQL Server*
841- ECANCEL (`RequestError`) - Cancelled.
842- ETIMEOUT (`RequestError`) - Request timeout.
843- ENOCONN (`RequestError`) - No connection is specified for that request.
844- ENOTOPEN (`ConnectionError`) - Connection not yet open.
845- ECONNCLOSED (`ConnectionError`) - Connection is closed.
846- ENOTBEGUN (`TransactionError`) - Transaction has not begun.
847- EABORT (`TransactionError`) - Transaction was aborted (by user or because of an error).
848
849---------------------------------------
850
851### input (name, [type], value)
852
853Add an input parameter to the request.
854
855__Arguments__
856
857- **name** - Name of the input parameter without @ char.
858- **type** - SQL data type of input parameter. If you omit type, module automatically decide which SQL data type should be used based on JS data type.
859- **value** - Input parameter value. `undefined` and `NaN` values are automatically converted to `null` values.
860
861__Example__
862
863```javascript
864request.input('input_parameter', value)
865request.input('input_parameter', sql.Int, value)
866```
867
868__JS Data Type To SQL Data Type Map__
869
870- `String` -> `sql.NVarChar`
871- `Number` -> `sql.Int`
872- `Boolean` -> `sql.Bit`
873- `Date` -> `sql.DateTime`
874- `Buffer` -> `sql.VarBinary`
875- `sql.Table` -> `sql.TVP`
876
877Default data type for unknown object is `sql.NVarChar`.
878
879You can define your own type map.
880
881```javascript
882sql.map.register(MyClass, sql.Text)
883```
884
885You can also overwrite the default type map.
886
887```javascript
888sql.map.register(Number, sql.BigInt)
889```
890
891__Errors__ (synchronous)
892- EARGS (`RequestError`) - Invalid number of arguments.
893- EINJECT (`RequestError`) - SQL injection warning.
894
895---------------------------------------
896
897NB: Do not use parameters `@p{n}` as these are used by the internal drivers and cause a conflict.
898
899### output (name, type, [value])
900
901Add an output parameter to the request.
902
903__Arguments__
904
905- **name** - Name of the output parameter without @ char.
906- **type** - SQL data type of output parameter.
907- **value** - Output parameter value initial value. `undefined` and `NaN` values are automatically converted to `null` values. Optional.
908
909__Example__
910
911```javascript
912request.output('output_parameter', sql.Int)
913request.output('output_parameter', sql.VarChar(50), 'abc')
914```
915
916__Errors__ (synchronous)
917- EARGS (`RequestError`) - Invalid number of arguments.
918- EINJECT (`RequestError`) - SQL injection warning.
919
920---------------------------------------
921
922### toReadableStream
923
924Convert request to a Node.js ReadableStream
925
926__Example__
927
928```javascript
929const { pipeline } = require('stream')
930const request = new sql.Request()
931const readableStream = request.toReadableStream()
932pipeline(readableStream, transformStream, writableStream)
933request.query('select * from mytable')
934```
935
936OR if you wanted to increase the highWaterMark of the read stream to buffer more rows in memory
937
938```javascript
939const { pipeline } = require('stream')
940const request = new sql.Request()
941const readableStream = request.toReadableStream({ highWaterMark: 100 })
942pipeline(readableStream, transformStream, writableStream)
943request.query('select * from mytable')
944```
945
946
947### pipe (stream)
948
949Sets request to `stream` mode and pulls all rows from all recordsets to a given stream.
950
951__Arguments__
952
953- **stream** - Writable stream in object mode.
954
955__Example__
956
957```javascript
958const request = new sql.Request()
959request.pipe(stream)
960request.query('select * from mytable')
961stream.on('error', err => {
962 // ...
963})
964stream.on('finish', () => {
965 // ...
966})
967```
968
969---------------------------------------
970
971### query (command, [callback])
972
973Execute the SQL command. To execute commands like `create procedure` or if you plan to work with local temporary tables, use [batch](#batch-batch-callback) instead.
974
975__Arguments__
976
977- **command** - T-SQL command to be executed.
978- **callback(err, recordset)** - A callback which is called after execution has completed, or an error has occurred. Optional. If omitted, returns [Promise](#promises).
979
980__Example__
981
982```javascript
983const request = new sql.Request()
984request.query('select 1 as number', (err, result) => {
985 // ... error checks
986
987 console.log(result.recordset[0].number) // return 1
988
989 // ...
990})
991```
992
993__Errors__
994- ETIMEOUT (`RequestError`) - Request timeout.
995- EREQUEST (`RequestError`) - *Message from SQL Server*
996- ECANCEL (`RequestError`) - Cancelled.
997- ENOCONN (`RequestError`) - No connection is specified for that request.
998- ENOTOPEN (`ConnectionError`) - Connection not yet open.
999- ECONNCLOSED (`ConnectionError`) - Connection is closed.
1000- ENOTBEGUN (`TransactionError`) - Transaction has not begun.
1001- EABORT (`TransactionError`) - Transaction was aborted (by user or because of an error).
1002
1003```javascript
1004const request = new sql.Request()
1005request.query('select 1 as number; select 2 as number', (err, result) => {
1006 // ... error checks
1007
1008 console.log(result.recordset[0].number) // return 1
1009 console.log(result.recordsets[0][0].number) // return 1
1010 console.log(result.recordsets[1][0].number) // return 2
1011})
1012```
1013
1014**NOTE**: To get number of rows affected by the statement(s), see section [Affected Rows](#affected-rows).
1015
1016---------------------------------------
1017
1018### batch (batch, [callback])
1019
1020Execute the SQL command. Unlike [query](#query-command-callback), it doesn't use `sp_executesql`, so is not likely that SQL Server will reuse the execution plan it generates for the SQL. Use this only in special cases, for example when you need to execute commands like `create procedure` which can't be executed with [query](#query-command-callback) or if you're executing statements longer than 4000 chars on SQL Server 2000. Also you should use this if you're plan to work with local temporary tables ([more information here](http://weblogs.sqlteam.com/mladenp/archive/2006/11/03/17197.aspx)).
1021
1022NOTE: Table-Valued Parameter (TVP) is not supported in batch.
1023
1024__Arguments__
1025
1026- **batch** - T-SQL command to be executed.
1027- **callback(err, recordset)** - A callback which is called after execution has completed, or an error has occurred. Optional. If omitted, returns [Promise](#promises).
1028
1029__Example__
1030
1031```javascript
1032const request = new sql.Request()
1033request.batch('create procedure #temporary as select * from table', (err, result) => {
1034 // ... error checks
1035})
1036```
1037
1038__Errors__
1039- ETIMEOUT (`RequestError`) - Request timeout.
1040- EREQUEST (`RequestError`) - *Message from SQL Server*
1041- ECANCEL (`RequestError`) - Cancelled.
1042- ENOCONN (`RequestError`) - No connection is specified for that request.
1043- ENOTOPEN (`ConnectionError`) - Connection not yet open.
1044- ECONNCLOSED (`ConnectionError`) - Connection is closed.
1045- ENOTBEGUN (`TransactionError`) - Transaction has not begun.
1046- EABORT (`TransactionError`) - Transaction was aborted (by user or because of an error).
1047
1048You can enable multiple recordsets in queries with the `request.multiple = true` command.
1049
1050---------------------------------------
1051
1052### bulk (table, [options,] [callback])
1053
1054Perform a bulk insert.
1055
1056__Arguments__
1057
1058- **table** - `sql.Table` instance.
1059- **options** - Options object to be passed through to driver (currently tedious only). Optional. If argument is a function it will be treated as the callback.
1060- **callback(err, rowCount)** - A callback which is called after bulk insert has completed, or an error has occurred. Optional. If omitted, returns [Promise](#promises).
1061
1062__Example__
1063
1064```javascript
1065const table = new sql.Table('table_name') // or temporary table, e.g. #temptable
1066table.create = true
1067table.columns.add('a', sql.Int, {nullable: true, primary: true})
1068table.columns.add('b', sql.VarChar(50), {nullable: false})
1069table.rows.add(777, 'test')
1070
1071const request = new sql.Request()
1072request.bulk(table, (err, result) => {
1073 // ... error checks
1074})
1075```
1076
1077**IMPORTANT**: Always indicate whether the column is nullable or not!
1078
1079**TIP**: If you set `table.create` to `true`, module will check if the table exists before it start sending data. If it doesn't, it will automatically create it. You can specify primary key columns by setting `primary: true` to column's options. Primary key constraint on multiple columns is supported.
1080
1081**TIP**: You can also create Table variable from any recordset with `recordset.toTable()`. You can optionally specify table type name in the first argument.
1082
1083__Errors__
1084- ENAME (`RequestError`) - Table name must be specified for bulk insert.
1085- ETIMEOUT (`RequestError`) - Request timeout.
1086- EREQUEST (`RequestError`) - *Message from SQL Server*
1087- ECANCEL (`RequestError`) - Cancelled.
1088- ENOCONN (`RequestError`) - No connection is specified for that request.
1089- ENOTOPEN (`ConnectionError`) - Connection not yet open.
1090- ECONNCLOSED (`ConnectionError`) - Connection is closed.
1091- ENOTBEGUN (`TransactionError`) - Transaction has not begun.
1092- EABORT (`TransactionError`) - Transaction was aborted (by user or because of an error).
1093
1094---------------------------------------
1095
1096### cancel()
1097
1098Cancel currently executing request. Return `true` if cancellation packet was send successfully.
1099
1100__Example__
1101
1102```javascript
1103const request = new sql.Request()
1104request.query('waitfor delay \'00:00:05\'; select 1 as number', (err, result) => {
1105 console.log(err instanceof sql.RequestError) // true
1106 console.log(err.message) // Cancelled.
1107 console.log(err.code) // ECANCEL
1108
1109 // ...
1110})
1111
1112request.cancel()
1113```
1114
1115## Transaction
1116
1117**IMPORTANT:** always use `Transaction` class to create transactions - it ensures that all your requests are executed on one connection. Once you call `begin`, a single connection is acquired from the connection pool and all subsequent requests (initialized with the `Transaction` object) are executed exclusively on this connection. After you call `commit` or `rollback`, connection is then released back to the connection pool.
1118
1119```javascript
1120const transaction = new sql.Transaction(/* [pool] */)
1121```
1122
1123If you omit connection argument, global connection is used instead.
1124
1125__Example__
1126
1127```javascript
1128const transaction = new sql.Transaction(/* [pool] */)
1129transaction.begin(err => {
1130 // ... error checks
1131
1132 const request = new sql.Request(transaction)
1133 request.query('insert into mytable (mycolumn) values (12345)', (err, result) => {
1134 // ... error checks
1135
1136 transaction.commit(err => {
1137 // ... error checks
1138
1139 console.log("Transaction committed.")
1140 })
1141 })
1142})
1143```
1144
1145Transaction can also be created by `const transaction = pool.transaction()`. Requests can also be created by `const request = transaction.request()`.
1146
1147__Aborted transactions__
1148
1149This example shows how you should correctly handle transaction errors when `abortTransactionOnError` (`XACT_ABORT`) is enabled. Added in 2.0.
1150
1151```javascript
1152const transaction = new sql.Transaction(/* [pool] */)
1153transaction.begin(err => {
1154 // ... error checks
1155
1156 let rolledBack = false
1157
1158 transaction.on('rollback', aborted => {
1159 // emited with aborted === true
1160
1161 rolledBack = true
1162 })
1163
1164 new sql.Request(transaction)
1165 .query('insert into mytable (bitcolumn) values (2)', (err, result) => {
1166 // insert should fail because of invalid value
1167
1168 if (err) {
1169 if (!rolledBack) {
1170 transaction.rollback(err => {
1171 // ... error checks
1172 })
1173 }
1174 } else {
1175 transaction.commit(err => {
1176 // ... error checks
1177 })
1178 }
1179 })
1180})
1181```
1182
1183### Events
1184
1185- **begin** - Dispatched when transaction begin.
1186- **commit** - Dispatched on successful commit.
1187- **rollback(aborted)** - Dispatched on successful rollback with an argument determining if the transaction was aborted (by user or because of an error).
1188
1189---------------------------------------
1190
1191### begin ([isolationLevel], [callback])
1192
1193Begin a transaction.
1194
1195__Arguments__
1196
1197- **isolationLevel** - Controls the locking and row versioning behavior of TSQL statements issued by a connection. Optional. `READ_COMMITTED` by default. For possible values see `sql.ISOLATION_LEVEL`.
1198- **callback(err)** - A callback which is called after transaction has began, or an error has occurred. Optional. If omitted, returns [Promise](#promises).
1199
1200__Example__
1201
1202```javascript
1203const transaction = new sql.Transaction()
1204transaction.begin(err => {
1205 // ... error checks
1206})
1207```
1208
1209__Errors__
1210- ENOTOPEN (`ConnectionError`) - Connection not yet open.
1211- EALREADYBEGUN (`TransactionError`) - Transaction has already begun.
1212
1213---------------------------------------
1214
1215### commit ([callback])
1216
1217Commit a transaction.
1218
1219__Arguments__
1220
1221- **callback(err)** - A callback which is called after transaction has committed, or an error has occurred. Optional. If omitted, returns [Promise](#promises).
1222
1223__Example__
1224
1225```javascript
1226const transaction = new sql.Transaction()
1227transaction.begin(err => {
1228 // ... error checks
1229
1230 transaction.commit(err => {
1231 // ... error checks
1232 })
1233})
1234```
1235
1236__Errors__
1237- ENOTBEGUN (`TransactionError`) - Transaction has not begun.
1238- EREQINPROG (`TransactionError`) - Can't commit transaction. There is a request in progress.
1239
1240---------------------------------------
1241
1242### rollback ([callback])
1243
1244Rollback a transaction. If the queue isn't empty, all queued requests will be Cancelled and the transaction will be marked as aborted.
1245
1246__Arguments__
1247
1248- **callback(err)** - A callback which is called after transaction has rolled back, or an error has occurred. Optional. If omitted, returns [Promise](#promises).
1249
1250__Example__
1251
1252```javascript
1253const transaction = new sql.Transaction()
1254transaction.begin(err => {
1255 // ... error checks
1256
1257 transaction.rollback(err => {
1258 // ... error checks
1259 })
1260})
1261```
1262
1263__Errors__
1264- ENOTBEGUN (`TransactionError`) - Transaction has not begun.
1265- EREQINPROG (`TransactionError`) - Can't rollback transaction. There is a request in progress.
1266
1267## Prepared Statement
1268
1269**IMPORTANT:** always use `PreparedStatement` class to create prepared statements - it ensures that all your executions of prepared statement are executed on one connection. Once you call `prepare`, a single connection is acquired from the connection pool and all subsequent executions are executed exclusively on this connection. After you call `unprepare`, the connection is then released back to the connection pool.
1270
1271```javascript
1272const ps = new sql.PreparedStatement(/* [pool] */)
1273```
1274
1275If you omit the connection argument, the global connection is used instead.
1276
1277__Example__
1278
1279```javascript
1280const ps = new sql.PreparedStatement(/* [pool] */)
1281ps.input('param', sql.Int)
1282ps.prepare('select @param as value', err => {
1283 // ... error checks
1284
1285 ps.execute({param: 12345}, (err, result) => {
1286 // ... error checks
1287
1288 // release the connection after queries are executed
1289 ps.unprepare(err => {
1290 // ... error checks
1291
1292 })
1293 })
1294})
1295```
1296
1297**IMPORTANT**: Remember that each prepared statement means one reserved connection from the pool. Don't forget to unprepare a prepared statement when you've finished your queries!
1298
1299You can execute multiple queries against the same prepared statement but you *must* unprepare the statement when you have finished using it otherwise you will cause the connection pool to run out of available connections.
1300
1301**TIP**: You can also create prepared statements in transactions (`new sql.PreparedStatement(transaction)`), but keep in mind you can't execute other requests in the transaction until you call `unprepare`.
1302
1303---------------------------------------
1304
1305### input (name, type)
1306
1307Add an input parameter to the prepared statement.
1308
1309__Arguments__
1310
1311- **name** - Name of the input parameter without @ char.
1312- **type** - SQL data type of input parameter.
1313
1314__Example__
1315
1316```javascript
1317ps.input('input_parameter', sql.Int)
1318ps.input('input_parameter', sql.VarChar(50))
1319```
1320
1321__Errors__ (synchronous)
1322- EARGS (`PreparedStatementError`) - Invalid number of arguments.
1323- EINJECT (`PreparedStatementError`) - SQL injection warning.
1324
1325---------------------------------------
1326
1327### output (name, type)
1328
1329Add an output parameter to the prepared statement.
1330
1331__Arguments__
1332
1333- **name** - Name of the output parameter without @ char.
1334- **type** - SQL data type of output parameter.
1335
1336__Example__
1337
1338```javascript
1339ps.output('output_parameter', sql.Int)
1340ps.output('output_parameter', sql.VarChar(50))
1341```
1342
1343__Errors__ (synchronous)
1344- EARGS (`PreparedStatementError`) - Invalid number of arguments.
1345- EINJECT (`PreparedStatementError`) - SQL injection warning.
1346
1347---------------------------------------
1348
1349### prepare (statement, [callback])
1350
1351Prepare a statement.
1352
1353__Arguments__
1354
1355- **statement** - T-SQL statement to prepare.
1356- **callback(err)** - A callback which is called after preparation has completed, or an error has occurred. Optional. If omitted, returns [Promise](#promises).
1357
1358__Example__
1359
1360```javascript
1361const ps = new sql.PreparedStatement()
1362ps.prepare('select @param as value', err => {
1363 // ... error checks
1364})
1365```
1366
1367__Errors__
1368- ENOTOPEN (`ConnectionError`) - Connection not yet open.
1369- EALREADYPREPARED (`PreparedStatementError`) - Statement is already prepared.
1370- ENOTBEGUN (`TransactionError`) - Transaction has not begun.
1371
1372---------------------------------------
1373
1374### execute (values, [callback])
1375
1376Execute a prepared statement.
1377
1378__Arguments__
1379
1380- **values** - An object whose names correspond to the names of parameters that were added to the prepared statement before it was prepared.
1381- **callback(err)** - A callback which is called after execution has completed, or an error has occurred. Optional. If omitted, returns [Promise](#promises).
1382
1383__Example__
1384
1385```javascript
1386const ps = new sql.PreparedStatement()
1387ps.input('param', sql.Int)
1388ps.prepare('select @param as value', err => {
1389 // ... error checks
1390
1391 ps.execute({param: 12345}, (err, result) => {
1392 // ... error checks
1393
1394 console.log(result.recordset[0].value) // return 12345
1395 console.log(result.rowsAffected) // Returns number of affected rows in case of INSERT, UPDATE or DELETE statement.
1396
1397 ps.unprepare(err => {
1398 // ... error checks
1399 })
1400 })
1401})
1402```
1403
1404You can also stream executed request.
1405
1406```javascript
1407const ps = new sql.PreparedStatement()
1408ps.input('param', sql.Int)
1409ps.prepare('select @param as value', err => {
1410 // ... error checks
1411
1412 ps.stream = true
1413 const request = ps.execute({param: 12345})
1414
1415 request.on('recordset', columns => {
1416 // Emitted once for each recordset in a query
1417 })
1418
1419 request.on('row', row => {
1420 // Emitted for each row in a recordset
1421 })
1422
1423 request.on('error', err => {
1424 // May be emitted multiple times
1425 })
1426
1427 request.on('done', result => {
1428 // Always emitted as the last one
1429
1430 console.log(result.rowsAffected) // Returns number of affected rows in case of INSERT, UPDATE or DELETE statement.
1431
1432 ps.unprepare(err => {
1433 // ... error checks
1434 })
1435 })
1436})
1437```
1438
1439**TIP**: To learn more about how number of affected rows works, see section [Affected Rows](#affected-rows).
1440
1441__Errors__
1442- ENOTPREPARED (`PreparedStatementError`) - Statement is not prepared.
1443- ETIMEOUT (`RequestError`) - Request timeout.
1444- EREQUEST (`RequestError`) - *Message from SQL Server*
1445- ECANCEL (`RequestError`) - Cancelled.
1446
1447---------------------------------------
1448
1449### unprepare ([callback])
1450
1451Unprepare a prepared statement.
1452
1453__Arguments__
1454
1455- **callback(err)** - A callback which is called after unpreparation has completed, or an error has occurred. Optional. If omitted, returns [Promise](#promises).
1456
1457__Example__
1458
1459```javascript
1460const ps = new sql.PreparedStatement()
1461ps.input('param', sql.Int)
1462ps.prepare('select @param as value', err => {
1463 // ... error checks
1464
1465 ps.unprepare(err => {
1466 // ... error checks
1467
1468 })
1469})
1470```
1471
1472__Errors__
1473- ENOTPREPARED (`PreparedStatementError`) - Statement is not prepared.
1474
1475## CLI
1476
1477If you want to add the MSSQL CLI tool to your path, you must install it globally with `npm install -g mssql`.
1478
1479__Setup__
1480
1481Create a `.mssql.json` configuration file (anywhere). Structure of the file is the same as the standard configuration object.
1482
1483```json
1484{
1485 "user": "...",
1486 "password": "...",
1487 "server": "localhost",
1488 "database": "..."
1489}
1490```
1491
1492__Example__
1493
1494```shell
1495echo "select * from mytable" | mssql /path/to/config
1496```
1497Results in:
1498```json
1499[[{"username":"patriksimek","password":"tooeasy"}]]
1500```
1501
1502You can also query for multiple recordsets.
1503
1504```shell
1505echo "select * from mytable; select * from myothertable" | mssql
1506```
1507Results in:
1508```json
1509[[{"username":"patriksimek","password":"tooeasy"}],[{"id":15,"name":"Product name"}]]
1510```
1511
1512If you omit config path argument, mssql will try to load it from current working directory.
1513
1514__Overriding config settings__
1515
1516You can override some config settings via CLI options (`--user`, `--password`, `--server`, `--database`, `--port`).
1517
1518```shell
1519echo "select * from mytable" | mssql /path/to/config --database anotherdatabase
1520```
1521Results in:
1522```json
1523[[{"username":"onotheruser","password":"quiteeasy"}]]
1524```
1525
1526## Geography and Geometry
1527
1528node-mssql has built-in deserializer for Geography and Geometry CLR data types.
1529
1530### Geography
1531
1532Geography types can be constructed several different ways. Refer carefully to documentation to verify the coordinate ordering; the ST methods tend to order parameters as longitude (x) then latitude (y), while custom CLR methods tend to prefer to order them as latitude (y) then longitude (x).
1533
1534The query:
1535
1536```sql
1537select geography::STGeomFromText(N'POLYGON((1 1, 3 1, 3 1, 1 1))',4326)
1538```
1539
1540results in:
1541
1542```javascript
1543{
1544 srid: 4326,
1545 version: 2,
1546 points: [
1547 Point { lat: 1, lng: 1, z: null, m: null },
1548 Point { lat: 1, lng: 3, z: null, m: null },
1549 Point { lat: 1, lng: 3, z: null, m: null },
1550 Point { lat: 1, lng: 1, z: null, m: null }
1551 ],
1552 figures: [ { attribute: 1, pointOffset: 0 } ],
1553 shapes: [ { parentOffset: -1, figureOffset: 0, type: 3 } ],
1554 segments: []
1555}
1556```
1557
1558**NOTE:** You will also see `x` and `y` coordinates in parsed Geography points,
1559they are not recommended for use. They have thus been omitted from this example.
1560For compatibility, they remain flipped (x, the horizontal offset, is instead used for latitude, the vertical), and thus risk misleading you.
1561Prefer instead to use the `lat` and `lng` properties.
1562
1563### Geometry
1564
1565Geometry types can also be constructed in several ways. Unlike Geographies, they are consistent in always placing x before y. node-mssql decodes the result of this query:
1566
1567```sql
1568select geometry::STGeomFromText(N'POLYGON((1 1, 3 1, 3 7, 1 1))',4326)
1569```
1570
1571into the JavaScript object:
1572
1573```javascript
1574{
1575 srid: 4326,
1576 version: 1,
1577 points: [
1578 Point { x: 1, y: 1, z: null, m: null },
1579 Point { x: 1, y: 3, z: null, m: null },
1580 Point { x: 7, y: 3, z: null, m: null },
1581 Point { x: 1, y: 1, z: null, m: null }
1582 ],
1583 figures: [ { attribute: 2, pointOffset: 0 } ],
1584 shapes: [ { parentOffset: -1, figureOffset: 0, type: 3 } ],
1585 segments: []
1586}
1587```
1588
1589## Table-Valued Parameter (TVP)
1590
1591Supported on SQL Server 2008 and later. You can pass a data table as a parameter to stored procedure. First, we have to create custom type in our database.
1592
1593```sql
1594CREATE TYPE TestType AS TABLE ( a VARCHAR(50), b INT );
1595```
1596
1597Next we will need a stored procedure.
1598
1599```sql
1600CREATE PROCEDURE MyCustomStoredProcedure (@tvp TestType readonly) AS SELECT * FROM @tvp
1601```
1602
1603Now let's go back to our Node.js app.
1604
1605```javascript
1606const tvp = new sql.Table() // You can optionally specify table type name in the first argument.
1607
1608// Columns must correspond with type we have created in database.
1609tvp.columns.add('a', sql.VarChar(50))
1610tvp.columns.add('b', sql.Int)
1611
1612// Add rows
1613tvp.rows.add('hello tvp', 777) // Values are in same order as columns.
1614```
1615
1616You can send table as a parameter to stored procedure.
1617
1618```javascript
1619const request = new sql.Request()
1620request.input('tvp', tvp)
1621request.execute('MyCustomStoredProcedure', (err, result) => {
1622 // ... error checks
1623
1624 console.dir(result.recordsets[0][0]) // {a: 'hello tvp', b: 777}
1625})
1626```
1627
1628**TIP**: You can also create Table variable from any recordset with `recordset.toTable()`. You can optionally specify table type name in the first argument.
1629
1630You can clear the table rows for easier batching by using `table.rows.clear()`
1631
1632```js
1633const tvp = new sql.Table() // You can optionally specify table type name in the first argument.
1634
1635// Columns must correspond with type we have created in database.
1636tvp.columns.add('a', sql.VarChar(50))
1637tvp.columns.add('b', sql.Int)
1638
1639// Add rows
1640tvp.rows.add('hello tvp', 777) // Values are in same order as columns.
1641tvp.rows.clear()
1642```
1643
1644## Response Schema
1645
1646An object returned from a `sucessful` basic query would look like the following.
1647```javascript
1648{
1649 recordsets: [
1650 [
1651 {
1652 COL1: "some content",
1653 COL2: "some more content"
1654 }
1655 ]
1656 ],
1657 recordset: [
1658 {
1659 COL1: "some content",
1660 COL2: "some more content"
1661 }
1662 ],
1663 output: {},
1664 rowsAffected: [1]
1665}
1666
1667```
1668
1669## Affected Rows
1670
1671If you're performing `INSERT`, `UPDATE` or `DELETE` in a query, you can read number of affected rows. The `rowsAffected` variable is an array of numbers. Each number represents number of affected rows by a single statement.
1672
1673__Example using Promises__
1674
1675```javascript
1676const request = new sql.Request()
1677request.query('update myAwesomeTable set awesomness = 100').then(result => {
1678 console.log(result.rowsAffected)
1679})
1680```
1681
1682__Example using callbacks__
1683
1684```javascript
1685const request = new sql.Request()
1686request.query('update myAwesomeTable set awesomness = 100', (err, result) => {
1687 console.log(result.rowsAffected)
1688})
1689```
1690
1691__Example using streaming__
1692
1693In addition to the rowsAffected attribute on the done event, each statement will emit the number of affected rows as it is completed.
1694
1695```javascript
1696const request = new sql.Request()
1697request.stream = true
1698request.query('update myAwesomeTable set awesomness = 100')
1699request.on('rowsaffected', rowCount => {
1700 console.log(rowCount)
1701})
1702request.on('done', result => {
1703 console.log(result.rowsAffected)
1704})
1705```
1706
1707## JSON support
1708
1709SQL Server 2016 introduced built-in JSON serialization. By default, JSON is returned as a plain text in a special column named `JSON_F52E2B61-18A1-11d1-B105-00805F49916B`.
1710
1711Example
1712```sql
1713SELECT
1714 1 AS 'a.b.c',
1715 2 AS 'a.b.d',
1716 3 AS 'a.x',
1717 4 AS 'a.y'
1718FOR JSON PATH
1719```
1720
1721Results in:
1722```javascript
1723recordset = [ { 'JSON_F52E2B61-18A1-11d1-B105-00805F49916B': '{"a":{"b":{"c":1,"d":2},"x":3,"y":4}}' } ]
1724```
1725
1726You can enable built-in JSON parser with `config.parseJSON = true`. Once you enable this, recordset will contain rows of parsed JS objects. Given the same example, result will look like this:
1727```javascript
1728recordset = [ { a: { b: { c: 1, d: 2 }, x: 3, y: 4 } } ]
1729```
1730
1731**IMPORTANT**: In order for this to work, there must be exactly one column named `JSON_F52E2B61-18A1-11d1-B105-00805F49916B` in the recordset.
1732
1733More information about JSON support can be found in [official documentation](https://msdn.microsoft.com/en-us/library/dn921882.aspx).
1734
1735## Handling Duplicate Column Names
1736
1737If your queries contain output columns with identical names, the default behaviour of `mssql` will only return column metadata for the last column with that name. You will also not always be able to re-assemble the order of output columns requested.
1738
1739Default behaviour:
1740```javascript
1741const request = new sql.Request()
1742request
1743 .query("select 'asdf' as name, 'qwerty' as other_name, 'jkl' as name")
1744 .then(result => {
1745 console.log(result)
1746 });
1747```
1748Results in:
1749```javascript
1750{
1751 recordsets: [
1752 [ { name: [ 'asdf', 'jkl' ], other_name: 'qwerty' } ]
1753 ],
1754 recordset: [ { name: [ 'asdf', 'jkl' ], other_name: 'qwerty' } ],
1755 output: {},
1756 rowsAffected: [ 1 ]
1757}
1758```
1759
1760You can use the `arrayRowMode` configuration parameter to return the row values as arrays and add a separate array of column values. `arrayRowMode` can be set globally during the initial connection, or per-request.
1761
1762```javascript
1763const request = new sql.Request()
1764request.arrayRowMode = true
1765request
1766 .query("select 'asdf' as name, 'qwerty' as other_name, 'jkl' as name")
1767 .then(result => {
1768 console.log(result)
1769 });
1770```
1771
1772Results in:
1773```javascript
1774{
1775 recordsets: [ [ [ 'asdf', 'qwerty', 'jkl' ] ] ],
1776 recordset: [ [ 'asdf', 'qwerty', 'jkl' ] ],
1777 output: {},
1778 rowsAffected: [ 1 ],
1779 columns: [
1780 [
1781 {
1782 index: 0,
1783 name: 'name',
1784 length: 4,
1785 type: [sql.VarChar],
1786 scale: undefined,
1787 precision: undefined,
1788 nullable: false,
1789 caseSensitive: false,
1790 identity: false,
1791 readOnly: true
1792 },
1793 {
1794 index: 1,
1795 name: 'other_name',
1796 length: 6,
1797 type: [sql.VarChar],
1798 scale: undefined,
1799 precision: undefined,
1800 nullable: false,
1801 caseSensitive: false,
1802 identity: false,
1803 readOnly: true
1804 },
1805 {
1806 index: 2,
1807 name: 'name',
1808 length: 3,
1809 type: [sql.VarChar],
1810 scale: undefined,
1811 precision: undefined,
1812 nullable: false,
1813 caseSensitive: false,
1814 identity: false,
1815 readOnly: true
1816 }
1817 ]
1818 ]
1819}
1820```
1821
1822__Streaming Duplicate Column Names__
1823
1824When using `arrayRowMode` with `stream` enabled, the output from the `recordset` event (as described in [Streaming](#streaming)) is returned as an array of column metadata, instead of as a keyed object. The order of the column metadata provided by the `recordset` event will match the order of row values when `arrayRowMode` is enabled.
1825
1826Default behaviour (without `arrayRowMode`):
1827```javascript
1828const request = new sql.Request()
1829request.stream = true
1830request.query("select 'asdf' as name, 'qwerty' as other_name, 'jkl' as name")
1831request.on('recordset', recordset => console.log(recordset))
1832```
1833
1834
1835Results in:
1836
1837```javascript
1838{
1839 name: {
1840 index: 2,
1841 name: 'name',
1842 length: 3,
1843 type: [sql.VarChar],
1844 scale: undefined,
1845 precision: undefined,
1846 nullable: false,
1847 caseSensitive: false,
1848 identity: false,
1849 readOnly: true
1850 },
1851 other_name: {
1852 index: 1,
1853 name: 'other_name',
1854 length: 6,
1855 type: [sql.VarChar],
1856 scale: undefined,
1857 precision: undefined,
1858 nullable: false,
1859 caseSensitive: false,
1860 identity: false,
1861 readOnly: true
1862 }
1863}
1864```
1865
1866With `arrayRowMode`:
1867```javascript
1868const request = new sql.Request()
1869request.stream = true
1870request.arrayRowMode = true
1871request.query("select 'asdf' as name, 'qwerty' as other_name, 'jkl' as name")
1872
1873request.on('recordset', recordset => console.log(recordset))
1874```
1875
1876Results in:
1877```javascript
1878[
1879 {
1880 index: 0,
1881 name: 'name',
1882 length: 4,
1883 type: [sql.VarChar],
1884 scale: undefined,
1885 precision: undefined,
1886 nullable: false,
1887 caseSensitive: false,
1888 identity: false,
1889 readOnly: true
1890 },
1891 {
1892 index: 1,
1893 name: 'other_name',
1894 length: 6,
1895 type: [sql.VarChar],
1896 scale: undefined,
1897 precision: undefined,
1898 nullable: false,
1899 caseSensitive: false,
1900 identity: false,
1901 readOnly: true
1902 },
1903 {
1904 index: 2,
1905 name: 'name',
1906 length: 3,
1907 type: [sql.VarChar],
1908 scale: undefined,
1909 precision: undefined,
1910 nullable: false,
1911 caseSensitive: false,
1912 identity: false,
1913 readOnly: true
1914 }
1915]
1916```
1917
1918## Errors
1919
1920There are 4 types of errors you can handle:
1921
1922- **ConnectionError** - Errors related to connections and connection pool.
1923- **TransactionError** - Errors related to creating, committing and rolling back transactions.
1924- **RequestError** - Errors related to queries and stored procedures execution.
1925- **PreparedStatementError** - Errors related to prepared statements.
1926
1927Those errors are initialized in node-mssql module and its original stack may be cropped. You can always access original error with `err.originalError`.
1928
1929SQL Server may generate more than one error for one request so you can access preceding errors with `err.precedingErrors`.
1930
1931### Error Codes
1932
1933Each known error has `name`, `code` and `message` properties.
1934
1935Name | Code | Message
1936:--- | :--- | :---
1937`ConnectionError` | ELOGIN | Login failed.
1938`ConnectionError` | ETIMEOUT | Connection timeout.
1939`ConnectionError` | EDRIVER | Unknown driver.
1940`ConnectionError` | EALREADYCONNECTED | Database is already connected!
1941`ConnectionError` | EALREADYCONNECTING | Already connecting to database!
1942`ConnectionError` | ENOTOPEN | Connection not yet open.
1943`ConnectionError` | EINSTLOOKUP | Instance lookup failed.
1944`ConnectionError` | ESOCKET | Socket error.
1945`ConnectionError` | ECONNCLOSED | Connection is closed.
1946`TransactionError` | ENOTBEGUN | Transaction has not begun.
1947`TransactionError` | EALREADYBEGUN | Transaction has already begun.
1948`TransactionError` | EREQINPROG | Can't commit/rollback transaction. There is a request in progress.
1949`TransactionError` | EABORT | Transaction has been aborted.
1950`RequestError` | EREQUEST | Message from SQL Server. Error object contains additional details.
1951`RequestError` | ECANCEL | Cancelled.
1952`RequestError` | ETIMEOUT | Request timeout.
1953`RequestError` | EARGS | Invalid number of arguments.
1954`RequestError` | EINJECT | SQL injection warning.
1955`RequestError` | ENOCONN | No connection is specified for that request.
1956`PreparedStatementError` | EARGS | Invalid number of arguments.
1957`PreparedStatementError` | EINJECT | SQL injection warning.
1958`PreparedStatementError` | EALREADYPREPARED | Statement is already prepared.
1959`PreparedStatementError` | ENOTPREPARED | Statement is not prepared.
1960
1961### Detailed SQL Errors
1962
1963SQL errors (`RequestError` with `err.code` equal to `EREQUEST`) contains additional details.
1964
1965- **err.number** - The error number.
1966- **err.state** - The error state, used as a modifier to the number.
1967- **err.class** - The class (severity) of the error. A class of less than 10 indicates an informational message. Detailed explanation can be found [here](https://msdn.microsoft.com/en-us/library/dd304156.aspx).
1968- **err.lineNumber** - The line number in the SQL batch or stored procedure that caused the error. Line numbers begin at 1; therefore, if the line number is not applicable to the message, the value of LineNumber will be 0.
1969- **err.serverName** - The server name.
1970- **err.procName** - The stored procedure name.
1971
1972## Informational messages
1973
1974To receive informational messages generated by `PRINT` or `RAISERROR` commands use:
1975
1976```javascript
1977const request = new sql.Request()
1978request.on('info', info => {
1979 console.dir(info)
1980})
1981request.query('print \'Hello world.\';', (err, result) => {
1982 // ...
1983})
1984```
1985
1986Structure of informational message:
1987
1988- **info.message** - Message.
1989- **info.number** - The message number.
1990- **info.state** - The message state, used as a modifier to the number.
1991- **info.class** - The class (severity) of the message. Equal or lower than 10. Detailed explanation can be found [here](https://msdn.microsoft.com/en-us/library/dd304156.aspx).
1992- **info.lineNumber** - The line number in the SQL batch or stored procedure that generated the message. Line numbers begin at 1; therefore, if the line number is not applicable to the message, the value of LineNumber will be 0.
1993- **info.serverName** - The server name.
1994- **info.procName** - The stored procedure name.
1995
1996## Metadata
1997
1998Recordset metadata are accessible through the `recordset.columns` property.
1999
2000```javascript
2001const request = new sql.Request()
2002request.query('select convert(decimal(18, 4), 1) as first, \'asdf\' as second', (err, result) => {
2003 console.dir(result.recordset.columns)
2004
2005 console.log(result.recordset.columns.first.type === sql.Decimal) // true
2006 console.log(result.recordset.columns.second.type === sql.VarChar) // true
2007})
2008```
2009
2010Columns structure for example above:
2011
2012```javascript
2013{
2014 first: {
2015 index: 0,
2016 name: 'first',
2017 length: 17,
2018 type: [sql.Decimal],
2019 scale: 4,
2020 precision: 18,
2021 nullable: true,
2022 caseSensitive: false
2023 identity: false
2024 readOnly: true
2025 },
2026 second: {
2027 index: 1,
2028 name: 'second',
2029 length: 4,
2030 type: [sql.VarChar],
2031 nullable: false,
2032 caseSensitive: false
2033 identity: false
2034 readOnly: true
2035 }
2036}
2037```
2038
2039## Data Types
2040
2041You can define data types with length/precision/scale:
2042
2043```javascript
2044request.input("name", sql.VarChar, "abc") // varchar(3)
2045request.input("name", sql.VarChar(50), "abc") // varchar(50)
2046request.input("name", sql.VarChar(sql.MAX), "abc") // varchar(MAX)
2047request.output("name", sql.VarChar) // varchar(8000)
2048request.output("name", sql.VarChar, "abc") // varchar(3)
2049
2050request.input("name", sql.Decimal, 155.33) // decimal(18, 0)
2051request.input("name", sql.Decimal(10), 155.33) // decimal(10, 0)
2052request.input("name", sql.Decimal(10, 2), 155.33) // decimal(10, 2)
2053
2054request.input("name", sql.DateTime2, new Date()) // datetime2(7)
2055request.input("name", sql.DateTime2(5), new Date()) // datetime2(5)
2056```
2057
2058List of supported data types:
2059
2060```
2061sql.Bit
2062sql.BigInt
2063sql.Decimal ([precision], [scale])
2064sql.Float
2065sql.Int
2066sql.Money
2067sql.Numeric ([precision], [scale])
2068sql.SmallInt
2069sql.SmallMoney
2070sql.Real
2071sql.TinyInt
2072
2073sql.Char ([length])
2074sql.NChar ([length])
2075sql.Text
2076sql.NText
2077sql.VarChar ([length])
2078sql.NVarChar ([length])
2079sql.Xml
2080
2081sql.Time ([scale])
2082sql.Date
2083sql.DateTime
2084sql.DateTime2 ([scale])
2085sql.DateTimeOffset ([scale])
2086sql.SmallDateTime
2087
2088sql.UniqueIdentifier
2089
2090sql.Variant
2091
2092sql.Binary
2093sql.VarBinary ([length])
2094sql.Image
2095
2096sql.UDT
2097sql.Geography
2098sql.Geometry
2099```
2100
2101To setup MAX length for `VarChar`, `NVarChar` and `VarBinary` use `sql.MAX` length. Types `sql.XML` and `sql.Variant` are not supported as input parameters.
2102
2103## SQL injection
2104
2105This module has built-in SQL injection protection. Always use parameters or tagged template literals to pass sanitized values to your queries.
2106
2107```javascript
2108const request = new sql.Request()
2109request.input('myval', sql.VarChar, '-- commented')
2110request.query('select @myval as myval', (err, result) => {
2111 console.dir(result)
2112})
2113```
2114
2115## Known issues
2116
2117### Tedious
2118
2119- If you're facing problems with connecting SQL Server 2000, try setting the default TDS version to 7.1 with `config.options.tdsVersion = '7_1'` ([issue](https://github.com/tediousjs/node-mssql/issues/36))
2120- If you're executing a statement longer than 4000 chars on SQL Server 2000, always use [batch](#batch-batch-callback) instead of [query](#query-command-callback) ([issue](https://github.com/tediousjs/node-mssql/issues/68))
2121
2122## 8.x to 9.x changes
2123
2124- Upgraded to tedious version 15
2125- Dropped support for Node version <= 12
2126
2127## 7.x to 8.x changes
2128
2129- Upgraded to tedious version 14
2130- Removed internal library for connection string parsing. Connection strings can be resolved using the static method `parseConnectionString` on ConnectionPool
2131
2132## 6.x to 7.x changes
2133
2134- Upgraded tedious version to v11
2135- Upgraded msnodesqlv8 version support to v2
2136- Upgraded tarn.js version to v3
2137- Requests in stream mode that pipe into other streams no longer pass errors up the stream chain
2138- Request.pipe now pipes a true node stream for better support of backpressure
2139- tedious config option `trustServerCertificate` defaults to `false` if not supplied
2140- Dropped support for Node < 10
2141
2142## 5.x to 6.x changes
2143
2144- Upgraded `tarn.js` so `_poolDestroy` can take advantage of being a promise
2145- `ConnectionPool.close()` now returns a promise / callbacks will be executed once closing of the pool is complete; you must make
2146sure that connections are properly released back to the pool otherwise the pool may fail to close.
2147- It is safe to pass read-only config objects to the library; config objects are now cloned
2148- `options.encrypt` is now `true` by default
2149- `TYPES.Null` has now been removed
2150- Upgraded tedious driver to v6 and upgraded support for msnodesqlv8]
2151- You can now close the global connection by reference and this will clean up the global connection, eg: `const conn = sql.connect(); conn.close()` will be the same as `sql.close()`
2152- Bulk table inserts will attempt to coerce dates from non-Date objects if the column type is expecting a date
2153- Repeat calls to the global connect function (`sql.connect()`) will return the current global connection if it exists (rather than throwing an error)
2154- Attempting to add a parameter to queries / stored procedures will now throw an error; use `replaceInput` and `replaceOutput` instead
2155- Invalid isolation levels passed to `Transaction`s will now throw an error
2156- `ConnectionPool` now reports if it is healthy or not (`ConnectionPool.healthy`) which can be used to determine if the pool is able
2157to create new connections or not
2158- Pause/Resume support for streamed results has been added to the msnodesqlv8 driver
2159
2160## 4.x to 5.x changes
2161
2162- Moved pool library from `node-pool` to `tarn.js`
2163- `ConnectionPool.pool.size` deprecated, use `ConnectionPool.size` instead
2164- `ConnectionPool.pool.available` deprecated, use `ConnectionPool.available` instead
2165- `ConnectionPool.pool.pending` deprecated, use `ConnectionPool.pending` instead
2166- `ConnectionPool.pool.borrowed` deprecated, use `ConnectionPool.borrowed` instead
2167
2168## 3.x to 4.x changes
2169
2170- Library & tests are rewritten to ES6.
2171- `Connection` was renamed to `ConnectionPool`.
2172- Drivers are no longer loaded dynamically so the library is now compatible with Webpack. To use `msnodesqlv8` driver, use `const sql = require('mssql/msnodesqlv8')` syntax.
2173- Every callback/resolve now returns `result` object only. This object contains `recordsets` (array of recordsets), `recordset` (first recordset from array of recordsets), `rowsAffected` (array of numbers representig number of affected rows by each insert/update/delete statement) and `output` (key/value collection of output parameters' values).
2174- Affected rows are now returned as an array. A separate number for each SQL statement.
2175- Directive `multiple: true` was removed.
2176- `Transaction` and `PreparedStatement` internal queues was removed.
2177- ConnectionPool no longer emits `connect` and `close` events.
2178- Removed verbose and debug mode.
2179- Removed support for `tds` and `msnodesql` drivers.
2180- Removed support for Node versions lower than 4.
2181
2182[npm-image]: https://img.shields.io/npm/v/mssql.svg?style=flat-square
2183[npm-url]: https://www.npmjs.com/package/mssql
2184[downloads-image]: https://img.shields.io/npm/dm/mssql.svg?style=flat-square
2185[downloads-url]: https://www.npmjs.com/package/mssql
2186[david-image]: https://img.shields.io/david/tediousjs/node-mssql.svg?style=flat-square
2187[david-url]: https://david-dm.org/tediousjs/node-mssql
2188[appveyor-image]: https://ci.appveyor.com/api/projects/status/e5gq1a0ujwams9t7/branch/master?svg=true
2189[appveyor-url]: https://ci.appveyor.com/project/tediousjs/node-mssql
2190
2191[tedious-url]: https://www.npmjs.com/package/tedious
2192[msnodesqlv8-url]: https://www.npmjs.com/package/msnodesqlv8
2193
\No newline at end of file