mssql2
Version:
Microsoft SQL Server client for Node.js (fork)
1,568 lines (1,132 loc) • 59.1 kB
Markdown
*****
This is a fork of [https://github.com/patriksimek/node-mssql]() with added
support for [dynamic driver
option](https://github.com/jholster/node-mssql/commit/f56617ef38d5c3ed99c5647d1d8163859fda85a3)
for browserify compatibility. This fork will be deleted if the patch is
accepted in the original project.
Installable as `npm install mssql2`.
*****
# node-mssql
Microsoft SQL Server client for Node.js
[![NPM Version][npm-image]][npm-url] [![NPM Downloads][downloads-image]][downloads-url] [![Package Quality][quality-image]][quality-url] [![Travis CI][travis-image]][travis-url] [![Appveyor CI][appveyor-image]][appveyor-url] [](https://gitter.im/patriksimek/node-mssql?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
**node-mssql**
- Has unified interface for multiple TDS drivers.
- Has built-in connection pooling.
- Supports built-in JSON serialization introduced in SQL Server 2016.
- Supports Stored Procedures, Transactions, Prepared Statements, Bulk Load and TVP.
- Supports serialization of Geography and Geometry CLR types.
- Has smart JS data type to SQL data type mapper.
- Supports Promises, Streams and standard callbacks.
- Supports ES6 tagged template literals.
- Is stable and tested in production environment.
- Is well documented.
There is also [co](https://github.com/tj/co) wrapper available - [co-mssql](https://github.com/patriksimek/co-mssql).
If you're looking for session store for connect/express, visit [connect-mssql](https://github.com/patriksimek/connect-mssql).
Supported TDS drivers:
- [![Github Stars][tedious-image] Tedious][tedious-url] (pure JavaScript - Windows/OSX/Linux)
- [![Github Stars][msnodesqlv8-image] Microsoft / Contributors Node V8 Driver for Node.js for SQL Server][msnodesqlv8-url] (native - Windows only)
- [![Github Stars][msnodesql-image] Microsoft Driver for Node.js for SQL Server][msnodesql-url] (native - Windows only)
- [![Github Stars][tds-image] node-tds][tds-url] (pure JavaScript - Windows/OSX/Linux)
node-mssql uses Tedious as the default driver.
## Installation
npm install mssql
## Quick Example
```javascript
var sql = require('mssql');
sql.connect("mssql://username:password@localhost/database").then(function() {
// Query
new sql.Request().query('select * from mytable').then(function(recordset) {
console.dir(recordset);
}).catch(function(err) {
// ... query error checks
});
// Stored Procedure
new sql.Request()
.input('input_parameter', sql.Int, value)
.output('output_parameter', sql.VarChar(50))
.execute('procedure_name').then(function(recordsets) {
console.dir(recordsets);
}).catch(function(err) {
// ... execute error checks
});
// ES6 Tagged template literals (experimental)
sql.query`select * from mytable where id = ${value}`.then(function(recordset) {
console.dir(recordset);
}).catch(function(err) {
// ... query error checks
});
}).catch(function(err) {
// ... connect error checks
});
```
If you're on Windows Azure, add `?encrypt=true` to your connection string. See [docs](#configuration) to learn more.
## Documentation
* [2.x to 3.x changes](#2x-to-3x-changes)
### Examples
* [Promises](#promises)
* [Nested callbacks](#nested-callbacks)
* [Streaming](#streaming)
* [Multiple Connections](#multiple-connections)
### Configuration
* [General](#general-same-for-all-drivers)
* [Formats](#formats)
### Drivers
* [Tedious](#tedious)
* [Microsoft / Contributors Node V8 Driver for Node.js for SQL Server](#microsoft--contributors-node-v8-driver-for-nodejs-for-sql-server)
* [Microsoft Driver for Node.js for SQL Server](#microsoft-driver-for-nodejs-for-sql-server)
* [node-tds](#node-tds)
### Connections
* [Connection](#connection)
* [connect](#connect-callback)
* [close](#close)
### Requests
* [Request](#request)
* [execute](#execute-procedure-callback)
* [input](#input-name-type-value)
* [output](#output-name-type-value)
* [pipe](#pipe-stream)
* [query](#query-command-callback)
* [batch](#batch-batch-callback)
* [bulk](#bulk-table-callback)
* [cancel](#cancel)
### Transactions
* [Transaction](#transaction)
* [begin](#begin-isolationlevel-callback)
* [commit](#commit-callback)
* [rollback](#rollback-callback)
### Prepared Statements
* [PreparedStatement](#prepared-statement)
* [input](#input-name-type)
* [output](#output-name-type)
* [prepare](#prepare-statement-callback)
* [execute](#execute-values-callback)
* [unprepare](#unprepare-callback)
### Other
* [CLI](#cli)
* [Geography and Geometry](#geography-and-geometry)
* [Table-Valued Parameter](#table-valued-parameter-tvp)
* [Affected Rows](#affected-rows)
* [JSON support](#json-support)
* [Errors](#errors)
* [Informational messages](#informational-messages)
* [Metadata](#metadata)
* [Data Types](#data-types)
* [SQL injection](#sql-injection)
* [Verbose Mode](#verbose-mode)
* [Known Issues](#known-issues)
* [Contributing](https://github.com/patriksimek/node-mssql/wiki/Contributing)
## Examples
### Promises
```javascript
var sql = require('mssql');
var config = {
user: '...',
password: '...',
server: 'localhost', // You can use 'localhost\\instance' to connect to named instance
database: '...',
options: {
encrypt: true // Use this if you're on Windows Azure
}
}
sql.connect(config).then(function() {
// Query
new sql.Request();
.input('input_parameter', sql.Int, value);
.query('select * from mytable where id = @input_parameter').then(function(recordset) {
console.dir(recordset);
}).catch(function(err) {
// ... error checks
});
// Stored Procedure
new sql.Request();
.input('input_parameter', sql.Int, value);
.output('output_parameter', sql.VarChar(50));
.execute('procedure_name').then(function(recordsets) {
console.dir(recordsets);
}).catch(function(err) {
// ... error checks
});
}).catch(function(err) {
// ... error checks
});
```
Native Promise is used by default. You can easily change this with `sql.Promise = require('myownpromisepackage')`.
**ES6 Tagged template literals (experimental)**
```javascript
sql.connect(config).then(function() {
sql.query`select * from mytable where id = ${value}`.then(function(recordset) {
console.dir(recordset);
}).catch(function(err) {
// ... error checks
});
}).catch(function(err) {
// ... error checks
});
```
All values are automatically sanitized against sql injection.
### Nested callbacks
```javascript
var sql = require('mssql');
var config = {
user: '...',
password: '...',
server: 'localhost', // You can use 'localhost\\instance' to connect to named instance
database: '...',
options: {
encrypt: true // Use this if you're on Windows Azure
}
}
sql.connect(config, function(err) {
// ... error checks
// Query
new sql.Request().query('select 1 as number', function(err, recordset) {
// ... error checks
console.dir(recordset);
});
// Stored Procedure
new sql.Request()
.input('input_parameter', sql.Int, value)
.output('output_parameter', sql.VarChar(50))
.execute('procedure_name', function(err, recordsets, returnValue) {
// ... error checks
console.dir(recordsets);
});
});
sql.on('error', function(err) {
// ... error handler
});
```
### Streaming
If 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.
```javascript
var sql = require('mssql');
var config = {
user: '...',
password: '...',
server: 'localhost', // You can use 'localhost\\instance' to connect to named instance
database: '...',
stream: true, // You can enable streaming globally
options: {
encrypt: true // Use this if you're on Windows Azure
}
}
sql.connect(config, function(err) {
// ... error checks
var request = new sql.Request();
request.stream = true; // You can set streaming differently for each request
request.query('select * from verylargetable'); // or request.execute(procedure);
request.on('recordset', function(columns) {
// Emitted once for each recordset in a query
});
request.on('row', function(row) {
// Emitted for each row in a recordset
});
request.on('error', function(err) {
// May be emitted multiple times
});
request.on('done', function(affected) {
// Always emitted as the last one
});
});
sql.on('error', function(err) {
// ... error handler
});
```
## Multiple Connections
```javascript
var sql = require('mssql');
var config = {
user: '...',
password: '...',
server: 'localhost', // You can use 'localhost\\instance' to connect to named instance
database: '...',
options: {
encrypt: true // Use this if you're on Windows Azure
}
}
var connection1 = new sql.Connection(config, function(err) {
// ... error checks
// Query
var request = new sql.Request(connection1); // or: var request = connection1.request();
request.query('select 1 as number', function(err, recordset) {
// ... error checks
console.dir(recordset);
});
});
connection1.on('error', function(err) {
// ... error handler
});
var connection2 = new sql.Connection(config, function(err) {
// ... error checks
// Stored Procedure
var request = new sql.Request(connection2); // or: var request = connection2.request();
request.input('input_parameter', sql.Int, 10);
request.output('output_parameter', sql.VarChar(50));
request.execute('procedure_name', function(err, recordsets, returnValue) {
// ... error checks
console.dir(recordsets);
});
});
connection2.on('error', function(err) {
// ... error handler
});
```
**ES6 Tagged template literals (experimental)**
```javascript
new sql.Connection(config).connect().then(function(conn) {
conn.query`select * from mytable where id = ${value}`.then(function(recordset) {
console.dir(recordset);
}).catch(function(err) {
// ... error checks
});
}).catch(function(err) {
// ... error checks
});
```
All values are automatically sanitized against sql injection.
## Configuration
```javascript
var config = {
user: '...',
password: '...',
server: 'localhost',
database: '...',
pool: {
max: 10,
min: 0,
idleTimeoutMillis: 30000
}
}
```
### General (same for all drivers)
- **driver** - Driver to use (default: `tedious`). Possible values: `tedious`, `msnodesqlv8` or `msnodesql` or `tds`.
- **user** - User name to use for authentication.
- **password** - Password to use for authentication.
- **server** - Server to connect to. You can use 'localhost\\instance' to connect to named instance.
- **port** - Port to connect to (default: `1433`). Don't set when connecting to named instance.
- **domain** - Once you set domain, driver will connect to SQL Server using domain login.
- **database** - Database to connect to (default: dependent on server configuration).
- **connectionTimeout** - Connection timeout in ms (default: `15000`).
- **requestTimeout** - Request timeout in ms (default: `15000`).
- **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.
- **parseJSON** - Parse JSON recordsets to JS objects (default: `false`). For more information please see section [JSON support](#json-support).
- **pool.max** - The maximum number of connections there can be in the pool (default: `10`).
- **pool.min** - The minimum of connections there can be in the pool (default: `0`).
- **pool.idleTimeoutMillis** - The Number of milliseconds before closing an unused connection (default: `30000`).
### Formats
In addition to configuration object there is an option to pass config as a connection string. Two formats of connection string are supported.
##### Classic Connection String
```
Server=localhost,1433;Database=database;User Id=username;Password=password;Encrypt=true
Driver=msnodesqlv8;Server=(local)\INSTANCE;Database=database;UID=DOMAIN\username;PWD=password;Encrypt=true
```
##### Connection String URI
```
mssql://username:password@localhost:1433/database?encrypt=true
mssql://username:password@localhost/INSTANCE/database?encrypt=true&domain=DOMAIN&driver=msnodesqlv8
```
__Version__
2.5
## Drivers
### Tedious
Default driver, actively maintained and production ready. Platform independent, runs everywhere Node.js runs.
**Extra options:**
- **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.
- **options.useUTC** - A boolean determining whether or not use UTC time for values without time zone offset (default: `true`).
- **options.encrypt** - A boolean determining whether or not the connection will be encrypted (default: `false`).
- **options.tdsVersion** - The version of TDS to use (default: `7_4`, available: `7_1`, `7_2`, `7_3_A`, `7_3_B`, `7_4`).
- **options.appName** - Application name used for SQL server logging.
- **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.
More information about Tedious specific options: http://pekim.github.io/tedious/api-connection.html
### Microsoft / Contributors Node V8 Driver for Node.js for SQL Server
**Requires Node.js 0.12.x/4.2.0. Windows only.** This driver is not part of the default package and must be installed separately by `npm install msnodesqlv8`.
**Extra options:**
- **connectionString** - Connection string (default: see below).
- **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.
- **options.trustedConnection** - Use Windows Authentication (default: `false`).
- **options.useUTC** - A boolean determining whether or not to use UTC time for values without time zone offset (default: `true`).
Default connection string when connecting to port:
```
Driver={SQL Server Native Client 11.0};Server={#{server},#{port}};Database={#{database}};Uid={#{user}};Pwd={#{password}};Trusted_Connection={#{trusted}};
```
Default connection string when connecting to named instance:
```
Driver={SQL Server Native Client 11.0};Server={#{server}\\#{instance}};Database={#{database}};Uid={#{user}};Pwd={#{password}};Trusted_Connection={#{trusted}};
```
### Microsoft Driver for Node.js for SQL Server
**Requires Node.js 0.6.x/0.8.x/0.10.x. Windows only.** This driver is not part of the default package and must be installed separately by `npm install msnodesql`. If you are looking for compiled binaries, see [node-sqlserver-binary](https://github.com/jorgeazevedo/node-sqlserver-unofficial).
**Extra options:**
- **connectionString** - Connection string (default: see below).
- **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.
- **options.trustedConnection** - Use Windows Authentication (default: `false`).
- **options.useUTC** - A boolean determining whether or not to use UTC time for values without time zone offset (default: `true`).
Default connection string when connecting to port:
```
Driver={SQL Server Native Client 11.0};Server={#{server},#{port}};Database={#{database}};Uid={#{user}};Pwd={#{password}};Trusted_Connection={#{trusted}};
```
Default connection string when connecting to named instance:
```
Driver={SQL Server Native Client 11.0};Server={#{server}\\#{instance}};Database={#{database}};Uid={#{user}};Pwd={#{password}};Trusted_Connection={#{trusted}};
```
### node-tds
**Legacy support, don't use this driver for new projects.** This driver is not part of the default package and must be installed separately by `npm install tds`.
_node-mssql updates this driver with extra features and bug fixes by overriding some of its internal functions. If you want to disable this, require module with `var sql = require('mssql/nofix')`._
## Connection
Internally, each `Connection` 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.
**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 (and no domain listener as a backup) it will crash the application as an uncaught error.
```javascript
var connection = new sql.Connection({ /* config */ });
```
__Errors__
- EDRIVER (`ConnectionError`) - Unknown driver.
### Events
- **connect** - Dispatched after connection has established.
- **close** - Dispatched after connection has closed a pool (by calling `close`).
- **error(err)** - Dispatched on connection error.
---------------------------------------
### connect ([callback])
Create a new connection pool with one active connection. This one initial connection serves as a probe to find out whether the configuration is valid.
__Arguments__
- **callback(err)** - A callback which is called after connection has established, or an error has occurred. Optional. If omitted, returns [Promise](#promises).
__Example__
```javascript
var connection = new sql.Connection({
user: '...',
password: '...',
server: 'localhost',
database: '...'
});
connection.connect(function(err) {
// ...
});
```
__Errors__
- ELOGIN (`ConnectionError`) - Login failed.
- ETIMEOUT (`ConnectionError`) - Connection timeout.
- EALREADYCONNECTED (`ConnectionError`) - Database is already connected!
- EALREADYCONNECTING (`ConnectionError`) - Already connecting to database!
- EINSTLOOKUP (`ConnectionError`) - Instance lookup failed.
- ESOCKET (`ConnectionError`) - Socket error.
---------------------------------------
### close()
Close all active connections in the pool.
__Example__
```javascript
connection.close();
```
## Request
```javascript
var request = new sql.Request(/* [connection] */);
```
If you omit connection argument, global connection is used instead.
### Events
- **recordset(columns)** - Dispatched when metadata for new recordset are parsed.
- **row(row)** - Dispatched when new row is parsed.
- **done(returnValue)** - Dispatched when request is complete.
- **error(err)** - Dispatched on error.
- **info(message)** - Dispatched on informational message.
---------------------------------------
### execute (procedure, [callback])
Call a stored procedure.
__Arguments__
- **procedure** - Name of the stored procedure to be executed.
- **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).
__Example__
```javascript
var request = new sql.Request();
request.input('input_parameter', sql.Int, value);
request.output('output_parameter', sql.Int);
request.execute('procedure_name', function(err, recordsets, returnValue, affected) {
// ... error checks
console.log(recordsets.length); // count of recordsets returned by the procedure
console.log(recordsets[0].length); // count of rows contained in first recordset
console.log(returnValue); // procedure return value
console.log(recordsets.returnValue); // same as previous line
console.log(affected); // number of rows affected by the statemens
console.log(recordsets.rowsAffected); // same as previous line
console.log(request.parameters.output_parameter.value); // output value
// ...
});
```
__Errors__
- EREQUEST (`RequestError`) - *Message from SQL Server*
- ECANCEL (`RequestError`) - Cancelled.
- ETIMEOUT (`RequestError`) - Request timeout.
- ENOCONN (`RequestError`) - No connection is specified for that request.
- ENOTOPEN (`ConnectionError`) - Connection not yet open.
- ECONNCLOSED (`ConnectionError`) - Connection is closed.
- ENOTBEGUN (`TransactionError`) - Transaction has not begun.
- EABORT (`TransactionError`) - Transaction was aborted (by user or because of an error).
---------------------------------------
### input (name, [type], value)
Add an input parameter to the request.
__Arguments__
- **name** - Name of the input parameter without @ char.
- **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.
- **value** - Input parameter value. `undefined` ans `NaN` values are automatically converted to `null` values.
__Example__
```javascript
request.input('input_parameter', value);
request.input('input_parameter', sql.Int, value);
```
__JS Data Type To SQL Data Type Map__
- `String` -> `sql.NVarChar`
- `Number` -> `sql.Int`
- `Boolean` -> `sql.Bit`
- `Date` -> `sql.DateTime`
- `Buffer` -> `sql.VarBinary`
- `sql.Table` -> `sql.TVP`
Default data type for unknown object is `sql.NVarChar`.
You can define your own type map.
```javascript
sql.map.register(MyClass, sql.Text);
```
You can also overwrite the default type map.
```javascript
sql.map.register(Number, sql.BigInt);
```
__Errors__ (synchronous)
- EARGS (`RequestError`) - Invalid number of arguments.
- EINJECT (`RequestError`) - SQL injection warning.
---------------------------------------
### output (name, type, [value])
Add an output parameter to the request.
__Arguments__
- **name** - Name of the output parameter without @ char.
- **type** - SQL data type of output parameter.
- **value** - Output parameter value initial value. `undefined` and `NaN` values are automatically converted to `null` values. Optional.
__Example__
```javascript
request.output('output_parameter', sql.Int);
request.output('output_parameter', sql.VarChar(50), 'abc');
```
__Errors__ (synchronous)
- EARGS (`RequestError`) - Invalid number of arguments.
- EINJECT (`RequestError`) - SQL injection warning.
---------------------------------------
### pipe (stream)
Sets request to `stream` mode and pulls all rows from all recordsets to a given stream.
__Arguments__
- **stream** - Writable stream in object mode.
__Example__
```javascript
var request = new sql.Request();
request.pipe(stream);
request.query('select * from mytable');
stream.on('error', function(err) {
// ...
});
stream.on('finish', function() {
// ...
});
```
__Version__
2.0
---------------------------------------
### query (command, [callback])
Execute 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.
__Arguments__
- **command** - T-SQL command to be executed.
- **callback(err, recordset)** - A callback which is called after execution has completed, or an error has occurred. Optional. If omitted, returns [Promise](#promises).
__Example__
```javascript
var request = new sql.Request();
request.query('select 1 as number', function(err, recordset) {
// ... error checks
console.log(recordset[0].number); // return 1
// ...
});
```
__Errors__
- ETIMEOUT (`RequestError`) - Request timeout.
- EREQUEST (`RequestError`) - *Message from SQL Server*
- ECANCEL (`RequestError`) - Cancelled.
- ENOCONN (`RequestError`) - No connection is specified for that request.
- ENOTOPEN (`ConnectionError`) - Connection not yet open.
- ECONNCLOSED (`ConnectionError`) - Connection is closed.
- ENOTBEGUN (`TransactionError`) - Transaction has not begun.
- EABORT (`TransactionError`) - Transaction was aborted (by user or because of an error).
You can enable multiple recordsets in queries with the `request.multiple = true` command.
```javascript
var request = new sql.Request();
request.multiple = true;
request.query('select 1 as number; select 2 as number', function(err, recordsets, affected) {
// ... error checks
console.log(recordsets[0][0].number); // return 1
console.log(recordsets[1][0].number); // return 2
});
```
**NOTE**: To get number of rows affected by the statement(s), see section [Affected Rows](#affected-rows).
---------------------------------------
### batch (batch, [callback])
Execute 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)).
NOTE: Table-Valued Parameter (TVP) is not supported in batch.
__Arguments__
- **batch** - T-SQL command to be executed.
- **callback(err, recordset)** - A callback which is called after execution has completed, or an error has occurred. Optional. If omitted, returns [Promise](#promises).
__Example__
```javascript
var request = new sql.Request();
request.batch('create procedure #temporary as select * from table', function(err, recordset) {
// ... error checks
});
```
__Errors__
- ETIMEOUT (`RequestError`) - Request timeout.
- EREQUEST (`RequestError`) - *Message from SQL Server*
- ECANCEL (`RequestError`) - Cancelled.
- ENOCONN (`RequestError`) - No connection is specified for that request.
- ENOTOPEN (`ConnectionError`) - Connection not yet open.
- ECONNCLOSED (`ConnectionError`) - Connection is closed.
- ENOTBEGUN (`TransactionError`) - Transaction has not begun.
- EABORT (`TransactionError`) - Transaction was aborted (by user or because of an error).
You can enable multiple recordsets in queries with the `request.multiple = true` command.
---------------------------------------
### bulk(table, [callback])
Perform a bulk insert.
__Arguments__
- **table** - `sql.Table` instance.
- **callback(err, rowCount)** - A callback which is called after bulk insert has completed, or an error has occurred. Optional. If omitted, returns [Promise](#promises).
__Example__
```javascript
var table = new sql.Table('table_name'); // or temporary table, e.g. #temptable
table.create = true;
table.columns.add('a', sql.Int, {nullable: true, primary: true});
table.columns.add('b', sql.VarChar(50), {nullable: false});
table.rows.add(777, 'test');
var request = new sql.Request();
request.bulk(table, function(err, rowCount) {
// ... error checks
});
```
**IMPORTANT**: Always indicate whether the column is nullable or not!
**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.
**TIP**: You can also create Table variable from any recordset with `recordset.toTable()`.
__Errors__
- ENAME (`RequestError`) - Table name must be specified for bulk insert.
- ETIMEOUT (`RequestError`) - Request timeout.
- EREQUEST (`RequestError`) - *Message from SQL Server*
- ECANCEL (`RequestError`) - Cancelled.
- ENOCONN (`RequestError`) - No connection is specified for that request.
- ENOTOPEN (`ConnectionError`) - Connection not yet open.
- ECONNCLOSED (`ConnectionError`) - Connection is closed.
- ENOTBEGUN (`TransactionError`) - Transaction has not begun.
- EABORT (`TransactionError`) - Transaction was aborted (by user or because of an error).
---------------------------------------
### cancel()
Cancel currently executing request. Return `true` if cancellation packet was send successfully.
__Example__
```javascript
var request = new sql.Request();
request.query('waitfor delay \'00:00:05\'; select 1 as number', function(err, recordset) {
console.log(err instanceof sql.RequestError); // true
console.log(err.message); // Cancelled.
console.log(err.code); // ECANCEL
// ...
});
request.cancel();
```
## Transaction
**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. Transaction also contains a queue to make sure your requests are executed in series. After you call `commit` or `rollback`, connection is then released back to the connection pool.
```javascript
var transaction = new sql.Transaction(/* [connection] */);
```
If you omit connection argument, global connection is used instead.
__Example__
```javascript
var transaction = new sql.Transaction(/* [connection] */);
transaction.begin(function(err) {
// ... error checks
var request = new sql.Request(transaction);
request.query('insert into mytable (mycolumn) values (12345)', function(err, recordset) {
// ... error checks
transaction.commit(function(err, recordset) {
// ... error checks
console.log("Transaction committed.");
});
});
});
```
Transaction can also be created by `var transaction = connection.transaction();`. Requests can also be created by `var request = transaction.request();`.
__Aborted transactions__
This example shows how you should correctly handle transaction errors when `abortTransactionOnError` (`XACT_ABORT`) is enabled. Added in 2.0.
```javascript
var transaction = new sql.Transaction(/* [connection] */);
transaction.begin(function(err) {
// ... error checks
var rolledBack = false;
transaction.on('rollback', function(aborted) {
// emited with aborted === true
rolledBack = true;
});
var request = new sql.Request(transaction);
request.query('insert into mytable (bitcolumn) values (2)', function(err, recordset) {
// insert should fail because of invalid value
if (err) {
if (!rolledBack) {
transaction.rollback(function(err) {
// ... error checks
});
}
} else {
transaction.commit(function(err) {
// ... error checks
});
}
});
});
```
### Events
- **begin** - Dispatched when transaction begin.
- **commit** - Dispatched on successful commit.
- **rollback(aborted)** - Dispatched on successful rollback with an argument determining if the transaction was aborted (by user or because of an error).
---------------------------------------
### begin ([isolationLevel], [callback])
Begin a transaction.
__Arguments__
- **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`.
- **callback(err)** - A callback which is called after transaction has began, or an error has occurred. Optional. If omitted, returns [Promise](#promises).
__Example__
```javascript
var transaction = new sql.Transaction();
transaction.begin(function(err) {
// ... error checks
});
```
__Errors__
- ENOTOPEN (`ConnectionError`) - Connection not yet open.
- EALREADYBEGUN (`TransactionError`) - Transaction has already begun.
---------------------------------------
### commit ([callback])
Commit a transaction.
__Arguments__
- **callback(err)** - A callback which is called after transaction has committed, or an error has occurred. Optional. If omitted, returns [Promise](#promises).
__Example__
```javascript
var transaction = new sql.Transaction();
transaction.begin(function(err) {
// ... error checks
transaction.commit(function(err) {
// ... error checks
})
});
```
__Errors__
- ENOTBEGUN (`TransactionError`) - Transaction has not begun.
- EREQINPROG (`TransactionError`) - Can't commit transaction. There is a request in progress.
---------------------------------------
### rollback ([callback])
Rollback a transaction. If the queue isn't empty, all queued requests will be Cancelled and the transaction will be marked as aborted.
__Arguments__
- **callback(err)** - A callback which is called after transaction has rolled back, or an error has occurred. Optional. If omitted, returns [Promise](#promises).
__Example__
```javascript
var transaction = new sql.Transaction();
transaction.begin(function(err) {
// ... error checks
transaction.rollback(function(err) {
// ... error checks
})
});
```
__Errors__
- ENOTBEGUN (`TransactionError`) - Transaction has not begun.
- EREQINPROG (`TransactionError`) - Can't rollback transaction. There is a request in progress.
## Prepared Statement
**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. Prepared Statement also contains a queue to make sure your executions are executed in series. After you call `unprepare`, the connection is then released back to the connection pool.
```javascript
var ps = new sql.PreparedStatement(/* [connection] */);
```
If you omit the connection argument, the global connection is used instead.
__Example__
```javascript
var ps = new sql.PreparedStatement(/* [connection] */);
ps.input('param', sql.Int);
ps.prepare('select @param as value', function(err) {
// ... error checks
ps.execute({param: 12345}, function(err, recordset) {
// ... error checks
ps.unprepare(function(err) {
// ... error checks
});
});
});
```
**IMPORTANT**: Remember that each prepared statement means one reserved connection from the pool. Don't forget to unprepare a prepared statement!
**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`.
---------------------------------------
### input (name, type)
Add an input parameter to the prepared statement.
__Arguments__
- **name** - Name of the input parameter without @ char.
- **type** - SQL data type of input parameter.
__Example__
```javascript
ps.input('input_parameter', sql.Int);
ps.input('input_parameter', sql.VarChar(50));
```
__Errors__ (synchronous)
- EARGS (`PreparedStatementError`) - Invalid number of arguments.
- EINJECT (`PreparedStatementError`) - SQL injection warning.
---------------------------------------
### output (name, type)
Add an output parameter to the prepared statement.
__Arguments__
- **name** - Name of the output parameter without @ char.
- **type** - SQL data type of output parameter.
__Example__
```javascript
ps.output('output_parameter', sql.Int);
ps.output('output_parameter', sql.VarChar(50));
```
__Errors__ (synchronous)
- EARGS (`PreparedStatementError`) - Invalid number of arguments.
- EINJECT (`PreparedStatementError`) - SQL injection warning.
---------------------------------------
### prepare (statement, [callback])
Prepare a statement.
__Arguments__
- **statement** - T-SQL statement to prepare.
- **callback(err)** - A callback which is called after preparation has completed, or an error has occurred. Optional. If omitted, returns [Promise](#promises).
__Example__
```javascript
var ps = new sql.PreparedStatement();
ps.prepare('select @param as value', function(err) {
// ... error checks
});
```
__Errors__
- ENOTOPEN (`ConnectionError`) - Connection not yet open.
- EALREADYPREPARED (`PreparedStatementError`) - Statement is already prepared.
- ENOTBEGUN (`TransactionError`) - Transaction has not begun.
---------------------------------------
### execute (values, [callback])
Execute a prepared statement.
__Arguments__
- **values** - An object whose names correspond to the names of parameters that were added to the prepared statement before it was prepared.
- **callback(err)** - A callback which is called after execution has completed, or an error has occurred. Optional. If omitted, returns [Promise](#promises).
__Example__
```javascript
var ps = new sql.PreparedStatement();
ps.input('param', sql.Int);
ps.prepare('select @param as value', function(err) {
// ... error checks
ps.execute({param: 12345}, function(err, recordset, affected) {
// ... error checks
console.log(recordset[0].value); // return 12345
console.log(affected); // Returns number of affected rows in case of INSERT, UPDATE or DELETE statement.
ps.unprepare(function(err) {
// ... error checks
});
});
});
```
You can enable multiple recordsets by `ps.multiple = true` command.
```javascript
var ps = new sql.PreparedStatement();
ps.input('param', sql.Int);
ps.prepare('select @param as value', function(err) {
// ... error checks
ps.multiple = true;
ps.execute({param: 12345}, function(err, recordsets, affected) {
// ... error checks
console.log(recordsets[0][0].value); // return 12345
console.log(affected); // Returns number of affected rows in case of INSERT, UPDATE or DELETE statement.
ps.unprepare(function(err) {
// ... error checks
});
});
});
```
You can also stream executed request.
```javascript
var ps = new sql.PreparedStatement();
ps.input('param', sql.Int);
ps.prepare('select @param as value', function(err) {
// ... error checks
ps.stream = true;
request = ps.execute({param: 12345});
request.on('recordset', function(columns) {
// Emitted once for each recordset in a query
});
request.on('row', function(row) {
// Emitted for each row in a recordset
});
request.on('error', function(err) {
// May be emitted multiple times
});
request.on('done', function(returnValue, affected) {
// Always emitted as the last one
console.log(affected); // Returns number of affected rows in case of INSERT, UPDATE or DELETE statement.
ps.unprepare(function(err) {
// ... error checks
});
});
});
```
**TIP**: To learn more about how number of affected rows works, see section [Affected Rows](#affected-rows).
**TIP**: To access number of affected rows when using Prepared Statement with Promises, use `ps.lastRequest.affectedRows`.
__Errors__
- ENOTPREPARED (`PreparedStatementError`) - Statement is not prepared.
- ETIMEOUT (`RequestError`) - Request timeout.
- EREQUEST (`RequestError`) - *Message from SQL Server*
- ECANCEL (`RequestError`) - Cancelled.
---------------------------------------
### unprepare ([callback])
Unprepare a prepared statement.
__Arguments__
- **callback(err)** - A callback which is called after unpreparation has completed, or an error has occurred. Optional. If omitted, returns [Promise](#promises).
__Example__
```javascript
var ps = new sql.PreparedStatement();
ps.input('param', sql.Int);
ps.prepare('select @param as value', function(err, recordsets) {
// ... error checks
ps.unprepare(function(err) {
// ... error checks
});
});
```
__Errors__
- ENOTPREPARED (`PreparedStatementError`) - Statement is not prepared.
## CLI
Before you can start using CLI, you must install `mssql` globally with `npm install mssql -g`. Once you do that you will be able to execute `mssql` command.
__Setup__
Create a `.mssql.json` configuration file (anywhere). Structure of the file is the same as the standard configuration object.
```json
{
"user": "...",
"password": "...",
"server": "localhost",
"database": "..."
}
```
__Example__
```shell
echo "select * from mytable" | mssql /path/to/config
```
Results in:
```json
[[{"username":"patriksimek","password":"tooeasy"}]]
```
You can also query for multiple recordsets.
```shell
echo "select * from mytable; select * from myothertable" | mssql
```
Results in:
```json
[[{"username":"patriksimek","password":"tooeasy"}],[{"id":15,"name":"Product name"}]]
```
If you omit config path argument, mssql will try to load it from current working directory.
__Version__
2.0
## Geography and Geometry
node-mssql has built-in serializer for Geography and Geometry CLR data types.
```sql
select geography::STGeomFromText('LINESTRING(-122.360 47.656, -122.343 47.656 )', 4326)
select geometry::STGeomFromText('LINESTRING (100 100 10.3 12, 20 180, 180 180)', 0)
```
Results in:
```javascript
{ srid: 4326,
version: 1,
points: [ { x: 47.656, y: -122.36 }, { x: 47.656, y: -122.343 } ],
figures: [ { attribute: 1, pointOffset: 0 } ],
shapes: [ { parentOffset: -1, figureOffset: 0, type: 2 } ],
segments: [] }
{ srid: 0,
version: 1,
points:
[ { x: 100, y: 100, z: 10.3, m: 12 },
{ x: 20, y: 180, z: NaN, m: NaN },
{ x: 180, y: 180, z: NaN, m: NaN } ],
figures: [ { attribute: 1, pointOffset: 0 } ],
shapes: [ { parentOffset: -1, figureOffset: 0, type: 2 } ],
segments: [] }
```
## Table-Valued Parameter (TVP)
Supported 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.
```sql
CREATE TYPE TestType AS TABLE ( a VARCHAR(50), b INT );
```
Next we will need a stored procedure.
```sql
CREATE PROCEDURE MyCustomStoredProcedure (@tvp TestType readonly) AS SELECT * FROM @tvp
```
Now let's go back to our Node.js app.
```javascript
var tvp = new sql.Table()
// Columns must correspond with type we have created in database.
tvp.columns.add('a', sql.VarChar(50));
tvp.columns.add('b', sql.Int);
// Add rows
tvp.rows.add('hello tvp', 777); // Values are in same order as columns.
```
You can send table as a parameter to stored procedure.
```javascript
var request = new sql.Request();
request.input('tvp', tvp);
request.execute('MyCustomStoredProcedure', function(err, recordsets, returnValue) {
// ... error checks
console.dir(recordsets[0][0]); // {a: 'hello tvp', b: 777}
});
```
**TIP**: You can also create Table variable from any recordset with `recordset.toTable()`.
## Affected Rows
If you're performing `INSERT`, `UPDATE` or `DELETE` in a query, you can read number of affected rows.
__Example using Promises__
```javascript
var request = new sql.Request();
request.query('update myAwesomeTable set awesomness = 100').then(function(recordset) {
console.log(request.rowsAffected);
});
```
__Example using callbacks__
```javascript
var request = new sql.Request();
request.query('update myAwesomeTable set awesomness = 100', function(err, recordset, affected) {
console.log(affected);
});
```
__Example using streaming__
```javascript
var request = new sql.Request();
request.stream = true;
request.query('update myAwesomeTable set awesomness = 100');
request.on('done', function(affected) {
console.log(affected);
});
```
**NOTE**: If your query contains multiple `INSERT`, `UPDATE` or `DELETE` statements, the number of affected rows is a sum of all of them.
__Version__
3.0
## JSON support
SQL 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`.
Example
```sql
SELECT
1 AS 'a.b.c',
2 AS 'a.b.d',
3 AS 'a.x',
4 AS 'a.y'
FOR JSON PATH
```
Results in:
```javascript
recordset = [ { 'JSON_F52E2B61-18A1-11d1-B105-00805F49916B': '{"a":{"b":{"c":1,"d":2},"x":3,"y":4}}' } ]
```
You 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:
```javascript
recordset = [ { a: { b: { c: 1, d: 2 }, x: 3, y: 4 } } ]
```
**IMPORTANT**: In order for this to work, there must be exactly one column named `JSON_F52E2B61-18A1-11d1-B105-00805F49916B` in the recordset.
More information about JSON support can be found in [official documentation](https://msdn.microsoft.com/en-us/library/dn921882.aspx).
__Version__
2.3
## Errors
There are 4 types of errors you can handle:
- **ConnectionError** - Errors related to connections and connection pool.
- **TransactionError** - Errors related to creating, committing and rolling back transactions.
- **RequestError** - Errors related to queries and stored procedures execution.
- **PreparedStatementError** - Errors related to prepared statements.
Those errors are initialized in node-mssql module and its original stack may be cropped. You can always access original error with `err.originalError`.
SQL Server may generate more than one error for one request so you can access preceding errors with `err.precedingErrors`.
### Error Codes
Each known error has `name`, `code` and `message` properties.
Name | Code | Message
:--- | :--- | :---
`ConnectionError` | ELOGIN | Login failed.
`ConnectionError` | ETIMEOUT | Connection timeout.
`ConnectionError` | EDRIVER | Unknown driver.
`ConnectionError` | EALREADYCONNECTED | Database is already connected!
`ConnectionError` | EALREADYCONNECTING | Already connecting to database!
`ConnectionError` | ENOTOPEN | Connection not yet open.
`ConnectionError` | EINSTLOOKUP | Instance lookup failed.
`ConnectionError` | ESOCKET | Socket error.
`ConnectionError` | ECONNCLOSED | Connection is closed.
`TransactionError` | ENOTBEGUN | Transaction has not begun.
`TransactionError` | EALREADYBEGUN | Transaction has already begun.
`TransactionError` | EREQINPROG | Can't commit/rollback transaction. There is a request in progress.
`TransactionError` | EABORT | Transaction has been aborted.
`RequestError` | EREQUEST | Message from SQL Server. Error object contains additional details.
`RequestError` | ECANCEL | Cancelled.
`RequestError` | ETIMEOUT | Request timeout.
`RequestError` | EARGS | Invalid number of arguments.
`RequestError` | EINJECT | SQL injection warning.
`RequestError` | ENOCONN | No connection is specified for that request.
`PreparedStatementError` | EARGS | Invalid number of arguments.
`PreparedStatementError` | EINJECT | SQL injection warning.
`PreparedStatementError` | EALREADYPREPARED | Statement is already prepared.
`PreparedStatementError` | ENOTPREPARED | Statement is not prepared.
### Detailed SQL Errors
SQL errors (`RequestError` with `err.code` equal to `EREQUEST`) contains additional details.
- **err.number** - The error number.
- **err.state** - The error state, used as a modifier to the number.
- **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).
- **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.
- **err.serverName** - The server name.
- **err.procName** - The stored procedure name.
## Informational messages
To receive informational messages generated by `PRINT` or `RAISERROR` commands use:
```javascript
var request = new sql.Request();
request.on('info', function(info) {
console.dir(info);
});
request.query('print \'Hello world.\';', function(err, recordset) {
// ...
});
```
Structure of informational message:
- **info.message** - Message.
- **info.number** - The message number.
- **info.state** - The message state, used as a modifier to the number.
- **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).
- **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.
- **info.serverName** - The server name.
- **info.procName** - The stored procedure name.
__Version__
3.3
## Metadata
Recordset metadata are accessible through the `recordset.columns` property.
```javascript
var request = new sql.Request();
request.query('select convert(decimal(18, 4), 1) as first, \'asdf\' as second', function(err, recordset) {
console.dir(recordset.columns);
console.log(recordset.columns.first.type === sql.Decimal); // true
console.log(recordset.columns.second.type === sql.VarChar); // true
});
```
Columns structure for example above:
```javascript
{
first: {
index: 0,
name: 'first',
length: 17,
type: [sql.Decimal],
scale: 4,
precision: 18,
nullable: true,
caseSensitive: false
identity: false
readOnly: true
},
second: {
index: 1,
name: 'second',
length: 4,
type: [sql.VarChar],
nullable: false,
caseSensitive: false
identity: false
readOnly: true
}
}
```
## Data Types
You can define data types with length/precision/scale:
```javascript
request.input("name", sql.VarChar, "abc"); // varchar(3)
request.input("name", sql.VarChar(50), "abc"); // varchar(50)
request.input("name", sql.VarChar(sql.MAX), "abc