// Generated by CoffeeScript 1.7.1
(function() {
  var DECLARATIONS, Pool, TYPES, Table, UDT, cast, createColumns, declare, getMssqlType, getTediousType, parameterCorrection, tds, util, valueCorrection, _ref,
    __hasProp = {}.hasOwnProperty,
    __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };

  Pool = require('generic-pool').Pool;

  tds = require('tedious');

  util = require('util');

  _ref = require('./datatypes'), TYPES = _ref.TYPES, declare = _ref.declare, cast = _ref.cast;

  DECLARATIONS = require('./datatypes').DECLARATIONS;

  UDT = require('./udt').PARSERS;

  Table = require('./table');


  /*
  @ignore
   */

  getTediousType = function(type) {
    switch (type) {
      case TYPES.VarChar:
        return tds.TYPES.VarChar;
      case TYPES.NVarChar:
        return tds.TYPES.NVarChar;
      case TYPES.Text:
        return tds.TYPES.Text;
      case TYPES.Int:
        return tds.TYPES.Int;
      case TYPES.BigInt:
        return tds.TYPES.BigInt;
      case TYPES.TinyInt:
        return tds.TYPES.TinyInt;
      case TYPES.SmallInt:
        return tds.TYPES.SmallInt;
      case TYPES.Bit:
        return tds.TYPES.Bit;
      case TYPES.Float:
        return tds.TYPES.Float;
      case TYPES.Decimal:
        return tds.TYPES.Decimal;
      case TYPES.Numeric:
        return tds.TYPES.Numeric;
      case TYPES.Real:
        return tds.TYPES.Real;
      case TYPES.Money:
        return tds.TYPES.Money;
      case TYPES.SmallMoney:
        return tds.TYPES.SmallMoney;
      case TYPES.Time:
        return tds.TYPES.TimeN;
      case TYPES.Date:
        return tds.TYPES.DateN;
      case TYPES.DateTime:
        return tds.TYPES.DateTime;
      case TYPES.DateTime2:
        return tds.TYPES.DateTime2N;
      case TYPES.DateTimeOffset:
        return tds.TYPES.DateTimeOffsetN;
      case TYPES.SmallDateTime:
        return tds.TYPES.SmallDateTime;
      case TYPES.UniqueIdentifier:
        return tds.TYPES.UniqueIdentifierN;
      case TYPES.Xml:
        return tds.TYPES.VarChar;
      case TYPES.Char:
        return tds.TYPES.Char;
      case TYPES.NChar:
        return tds.TYPES.NChar;
      case TYPES.NText:
        return tds.TYPES.NVarChar;
      case TYPES.Image:
        return tds.TYPES.Image;
      case TYPES.Binary:
        return tds.TYPES.Binary;
      case TYPES.VarBinary:
        return tds.TYPES.VarBinary;
      case TYPES.UDT:
      case TYPES.Geography:
      case TYPES.Geometry:
        return tds.TYPES.UDT;
      case TYPES.TVP:
        return tds.TYPES.TVP;
      default:
        return type;
    }
  };


  /*
  @ignore
   */

  getMssqlType = function(type) {
    switch (type) {
      case tds.TYPES.Char:
        return TYPES.Char;
      case tds.TYPES.NChar:
        return TYPES.NChar;
      case tds.TYPES.VarChar:
        return TYPES.VarChar;
      case tds.TYPES.NVarChar:
        return TYPES.NVarChar;
      case tds.TYPES.Text:
        return TYPES.Text;
      case tds.TYPES.NText:
        return TYPES.NText;
      case tds.TYPES.Int:
      case tds.TYPES.IntN:
        return TYPES.Int;
      case tds.TYPES.BigInt:
        return TYPES.BigInt;
      case tds.TYPES.TinyInt:
        return TYPES.TinyInt;
      case tds.TYPES.SmallInt:
        return TYPES.SmallInt;
      case tds.TYPES.Bit:
      case tds.TYPES.BitN:
        return TYPES.Bit;
      case tds.TYPES.Float:
      case tds.TYPES.FloatN:
        return TYPES.Float;
      case tds.TYPES.Real:
        return TYPES.Real;
      case tds.TYPES.Money:
      case tds.TYPES.MoneyN:
        return TYPES.Money;
      case tds.TYPES.SmallMoney:
        return TYPES.SmallMoney;
      case tds.TYPES.Numeric:
      case tds.TYPES.NumericN:
        return TYPES.Numeric;
      case tds.TYPES.Decimal:
      case tds.TYPES.DecimalN:
        return TYPES.Decimal;
      case tds.TYPES.DateTime:
      case tds.TYPES.DateTimeN:
        return TYPES.DateTime;
      case tds.TYPES.TimeN:
        return TYPES.Time;
      case tds.TYPES.DateN:
        return TYPES.Date;
      case tds.TYPES.DateTime2N:
        return TYPES.DateTime2;
      case tds.TYPES.DateTimeOffsetN:
        return TYPES.DateTimeOffset;
      case tds.TYPES.SmallDateTime:
        return TYPES.SmallDateTime;
      case tds.TYPES.UniqueIdentifierN:
        return TYPES.UniqueIdentifier;
      case tds.TYPES.Image:
        return TYPES.Image;
      case tds.TYPES.Binary:
        return TYPES.Binary;
      case tds.TYPES.VarBinary:
        return TYPES.VarBinary;
      case tds.TYPES.Xml:
        return TYPES.Xml;
      case tds.TYPES.UDT:
        return TYPES.UDT;
      case tds.TYPES.TVP:
        return TYPES.TVP;
    }
  };


  /*
  @ignore
   */

  createColumns = function(metadata) {
    var column, index, out, _i, _len;
    out = {};
    for (index = _i = 0, _len = metadata.length; _i < _len; index = ++_i) {
      column = metadata[index];
      out[column.colName] = {
        index: index,
        name: column.colName,
        length: column.dataLength,
        type: getMssqlType(column.type),
        scale: column.scale,
        precision: column.precision,
        nullable: !!(column.flags & 0x01)
      };
      if (column.udtInfo != null) {
        out[column.colName].udt = {
          name: column.udtInfo.typeName,
          database: column.udtInfo.dbname,
          schema: column.udtInfo.owningSchema,
          assembly: column.udtInfo.assemblyName
        };
        if (DECLARATIONS[column.udtInfo.typeName]) {
          out[column.colName].type = DECLARATIONS[column.udtInfo.typeName];
        }
      }
    }
    return out;
  };


  /*
  @ignore
   */

  valueCorrection = function(value, metadata) {
    if (metadata.type === tds.TYPES.UDT && (value != null)) {
      if (UDT[metadata.udtInfo.typeName]) {
        return UDT[metadata.udtInfo.typeName](value);
      } else {
        return value;
      }
    } else {
      return value;
    }
  };


  /*
  @ignore
   */

  parameterCorrection = function(value) {
    var col, tvp, _i, _len, _ref1;
    if (value instanceof Table) {
      tvp = {
        columns: [],
        rows: value.rows
      };
      _ref1 = value.columns;
      for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
        col = _ref1[_i];
        tvp.columns.push({
          name: col.name,
          type: getTediousType(col.type),
          length: col.length,
          scale: col.scale,
          precision: col.precision
        });
      }
      return tvp;
    } else {
      return value;
    }
  };


  /*
  @ignore
   */

  module.exports = function(Connection, Transaction, Request, ConnectionError, TransactionError, RequestError) {
    var TediousConnection, TediousRequest, TediousTransaction;
    TediousConnection = (function(_super) {
      __extends(TediousConnection, _super);

      function TediousConnection() {
        return TediousConnection.__super__.constructor.apply(this, arguments);
      }

      TediousConnection.prototype.pool = null;

      TediousConnection.prototype.connect = function(config, callback) {
        var cfg, cfg_pool, key, value, _base, _base1, _base2, _base3, _base4, _base5, _ref1, _ref2, _ref3, _ref4;
        cfg = {
          userName: config.user,
          password: config.password,
          server: config.server,
          options: config.options,
          domain: config.domain
        };
        if ((_base = cfg.options).database == null) {
          _base.database = config.database;
        }
        if ((_base1 = cfg.options).port == null) {
          _base1.port = config.port;
        }
        if ((_base2 = cfg.options).connectTimeout == null) {
          _base2.connectTimeout = (_ref1 = (_ref2 = config.connectionTimeout) != null ? _ref2 : config.timeout) != null ? _ref1 : 15000;
        }
        if ((_base3 = cfg.options).requestTimeout == null) {
          _base3.requestTimeout = (_ref3 = config.requestTimeout) != null ? _ref3 : 15000;
        }
        if ((_base4 = cfg.options).tdsVersion == null) {
          _base4.tdsVersion = '7_4';
        }
        cfg.options.rowCollectionOnDone = false;
        cfg.options.rowCollectionOnRequestCompletion = false;
        cfg.options.useColumnNames = false;
        if ((_base5 = cfg.options).appName == null) {
          _base5.appName = 'node-mssql';
        }
        if (cfg.options.instanceName) {
          delete cfg.options.port;
        }
        if (config.debug) {
          cfg.options.debug = {
            packet: true,
            token: true,
            data: true,
            payload: true
          };
        }
        cfg_pool = {
          name: 'mssql',
          max: 10,
          min: 0,
          idleTimeoutMillis: 30000,
          create: (function(_this) {
            return function(callback) {
              var c;
              c = new tds.Connection(cfg);
              c.once('connect', function(err) {
                if (err) {
                  err = ConnectionError(err);
                }
                if (err) {
                  return callback(err, null);
                }
                return callback(null, c);
              });
              c.on('error', function(err) {
                return _this.emit('error', err);
              });
              if (config.debug) {
                return c.on('debug', function(msg) {
                  return _this._debug(msg);
                });
              }
            };
          })(this),
          validate: function(c) {
            return (c != null) && !c.closed;
          },
          destroy: function(c) {
            if (c != null) {
              c.close();
            }
            return setTimeout(function() {
              return c != null ? c.removeAllListeners() : void 0;
            }, 500);
          }
        };
        if (config.pool) {
          _ref4 = config.pool;
          for (key in _ref4) {
            value = _ref4[key];
            cfg_pool[key] = value;
          }
        }
        this.pool = Pool(cfg_pool, cfg);
        return this.pool.acquire((function(_this) {
          return function(err, connection) {
            _this.pool.release(connection);
            if (err) {
              _this.pool.destroyAllNow();
              _this.pool = null;
            }
            return callback(err);
          };
        })(this));
      };

      TediousConnection.prototype.close = function(callback) {
        if (!this.pool) {
          return callback(null);
        }
        return this.pool.drain((function(_this) {
          return function() {
            _this.pool.destroyAllNow();
            _this.pool = null;
            return callback(null);
          };
        })(this));
      };

      return TediousConnection;

    })(Connection);
    TediousTransaction = (function(_super) {
      __extends(TediousTransaction, _super);

      function TediousTransaction() {
        return TediousTransaction.__super__.constructor.apply(this, arguments);
      }

      TediousTransaction.prototype.begin = function(callback) {
        return this.connection.pool.acquire((function(_this) {
          return function(err, connection) {
            if (err) {
              return callback(err);
            }
            _this._pooledConnection = connection;
            return connection.beginTransaction(function(err) {
              if (err) {
                err = TransactionError(err);
              }
              return callback(err);
            }, _this.name, _this.isolationLevel);
          };
        })(this));
      };

      TediousTransaction.prototype.commit = function(callback) {
        return this._pooledConnection.commitTransaction((function(_this) {
          return function(err) {
            if (err) {
              err = TransactionError(err);
            }
            _this.connection.pool.release(_this._pooledConnection);
            _this._pooledConnection = null;
            return callback(err);
          };
        })(this));
      };

      TediousTransaction.prototype.rollback = function(callback) {
        return this._pooledConnection.rollbackTransaction((function(_this) {
          return function(err) {
            if (err) {
              err = TransactionError(err);
            }
            _this.connection.pool.release(_this._pooledConnection);
            _this._pooledConnection = null;
            return callback(err);
          };
        })(this));
      };

      return TediousTransaction;

    })(Transaction);
    TediousRequest = (function(_super) {
      __extends(TediousRequest, _super);

      function TediousRequest() {
        return TediousRequest.__super__.constructor.apply(this, arguments);
      }


      /*
      		Execute specified sql batch.
       */

      TediousRequest.prototype.batch = function(batch, callback) {
        this._batch = true;
        return TediousRequest.prototype.query.call(this, batch, callback);
      };


      /*
      		Bulk load.
       */

      TediousRequest.prototype.bulk = function(table, callback) {
        var errors, handleError, started;
        table._makeBulk();
        if (!table.name) {
          process.nextTick(function() {
            return callback(RequestError("Table name must be specified for bulk insert.", "ENAME"));
          });
        }
        if (table.name.charAt(0) === '@') {
          process.nextTick(function() {
            return callback(RequestError("You can't use table variables for bulk insert.", "ENAME"));
          });
        }
        started = Date.now();
        errors = [];
        handleError = (function(_this) {
          return function(err) {
            var e;
            e = new RequestError(err.message, 'EREQUEST');
            if (_this.stream) {
              _this.emit('error', e);
            }
            return errors.push(e);
          };
        })(this);
        return this._acquire((function(_this) {
          return function(err, connection) {
            var bulk, col, done, objectid, req, row, _i, _j, _len, _len1, _ref1, _ref2;
            if (!err) {
              if (_this.verbose) {
                _this._log("-------- sql bulk load --------\n    table: " + table.name);
              }
              if (_this.canceled) {
                if (_this.verbose) {
                  _this._log("---------- canceling ----------");
                }
                _this._release(connection);
                return typeof callback === "function" ? callback(new RequestError("Canceled.", 'ECANCEL')) : void 0;
              }
              _this._cancel = function() {
                if (_this.verbose) {
                  _this._log("---------- canceling ----------");
                }
                return connection.cancel();
              };
              connection.on('errorMessage', handleError);
              done = function(err, rowCount) {
                var elapsed, error, _i, _len, _ref1;
                if (err && err.message !== ((_ref1 = errors[errors.length - 1]) != null ? _ref1.message : void 0)) {
                  err = RequestError(err);
                  if (_this.stream) {
                    _this.emit('error', err);
                  }
                  errors.push(err);
                }
                if (_this.verbose) {
                  if (errors.length) {
                    for (_i = 0, _len = errors.length; _i < _len; _i++) {
                      error = errors[_i];
                      _this._log("    error: " + error);
                    }
                  }
                  elapsed = Date.now() - started;
                  _this._log(" duration: " + elapsed + "ms");
                  _this._log("---------- completed ----------");
                }
                _this._cancel = null;
                if (errors.length && !_this.stream) {
                  error = errors.pop();
                  error.precedingErrors = errors;
                }
                connection.removeListener('errorMessage', handleError);
                _this._release(connection);
                if (_this.stream) {
                  return callback(null, null);
                } else {
                  return typeof callback === "function" ? callback(error, rowCount) : void 0;
                }
              };
              bulk = connection.newBulkLoad(table.name, done);
              _ref1 = table.columns;
              for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
                col = _ref1[_i];
                bulk.addColumn(col.name, getTediousType(col.type), {
                  nullable: col.nullable,
                  length: col.length,
                  scale: col.scale,
                  precision: col.precision
                });
              }
              _ref2 = table.rows;
              for (_j = 0, _len1 = _ref2.length; _j < _len1; _j++) {
                row = _ref2[_j];
                bulk.addRow(row);
              }
              if (_this.verbose) {
                _this._log("---------- response -----------");
              }
              if (table.create) {
                if (table.temporary) {
                  objectid = "tempdb..[" + table.name + "]";
                } else {
                  objectid = table.path;
                }
                req = new tds.Request("if object_id('" + (objectid.replace(/'/g, '\'\'')) + "') is null " + (table.declare()), function(err) {
                  if (err) {
                    return done(err);
                  }
                  return connection.execBulkLoad(bulk);
                });
                return connection.execSqlBatch(req);
              } else {
                return connection.execBulkLoad(bulk);
              }
            }
          };
        })(this));
      };


      /*
      		Execute specified sql command.
       */

      TediousRequest.prototype.query = function(command, callback) {
        var batchHasOutput, batchLastRow, columns, errors, handleError, recordset, recordsets, started;
        columns = {};
        recordset = [];
        recordsets = [];
        started = Date.now();
        errors = [];
        batchLastRow = null;
        batchHasOutput = false;
        handleError = (function(_this) {
          return function(err) {
            var e;
            e = new RequestError(err.message, 'EREQUEST');
            if (_this.stream) {
              _this.emit('error', e);
            }
            return errors.push(e);
          };
        })(this);
        return this._acquire((function(_this) {
          return function(err, connection) {
            var assigns, declarations, doneHandler, name, param, req, selects, _ref1;
            if (!err) {
              if (_this.verbose) {
                _this._log("---------- sql " + (_this._batch ? 'batch' : 'query') + " ----------\n    " + (_this._batch ? 'batch' : 'query') + ": " + command);
              }
              if (_this.canceled) {
                if (_this.verbose) {
                  _this._log("---------- canceling ----------");
                }
                _this._release(connection);
                return typeof callback === "function" ? callback(new RequestError("Canceled.", 'ECANCEL')) : void 0;
              }
              _this._cancel = function() {
                if (_this.verbose) {
                  _this._log("---------- canceling ----------");
                }
                return connection.cancel();
              };
              connection.on('errorMessage', handleError);
              req = new tds.Request(command, function(err) {
                var elapsed, error, name, value, _i, _len, _ref1;
                if (err && err.message !== ((_ref1 = errors[errors.length - 1]) != null ? _ref1.message : void 0)) {
                  err = RequestError(err);
                  if (_this.stream) {
                    _this.emit('error', err);
                  }
                  errors.push(err);
                }
                if (batchHasOutput) {
                  if (!_this.stream) {
                    batchLastRow = recordsets.pop()[0];
                  }
                  for (name in batchLastRow) {
                    value = batchLastRow[name];
                    if (!(name !== '___return___')) {
                      continue;
                    }
                    if (_this.verbose) {
                      if (value === tds.TYPES.Null) {
                        _this._log("   output: @" + name + ", null");
                      } else {
                        _this._log("   output: @" + name + ", " + (_this.parameters[name].type.declaration.toLowerCase()) + ", " + value);
                      }
                    }
                    _this.parameters[name].value = value === tds.TYPES.Null ? null : value;
                  }
                }
                if (_this.verbose) {
                  if (errors.length) {
                    for (_i = 0, _len = errors.length; _i < _len; _i++) {
                      error = errors[_i];
                      _this._log("    error: " + error);
                    }
                  }
                  elapsed = Date.now() - started;
                  _this._log(" duration: " + elapsed + "ms");
                  _this._log("---------- completed ----------");
                }
                _this._cancel = null;
                if (errors.length && !_this.stream) {
                  error = errors.pop();
                  error.precedingErrors = errors;
                }
                connection.removeListener('errorMessage', handleError);
                _this._release(connection);
                if (_this.stream) {
                  return callback(null, null);
                } else {
                  return typeof callback === "function" ? callback(error, _this.multiple ? recordsets : recordsets[0]) : void 0;
                }
              });
              req.on('columnMetadata', function(metadata) {
                columns = createColumns(metadata);
                if (_this.stream) {
                  if (_this._batch) {
                    if (columns["___return___"] == null) {
                      return _this.emit('recordset', columns);
                    }
                  } else {
                    return _this.emit('recordset', columns);
                  }
                }
              });
              doneHandler = function(rowCount, more, rows) {
                if (Object.keys(columns).length === 0) {
                  return;
                }
                if (!_this.stream) {
                  Object.defineProperty(recordset, 'columns', {
                    enumerable: false,
                    value: columns
                  });
                  Object.defineProperty(recordset, 'toTable', {
                    enumerable: false,
                    value: function() {
                      return Table.fromRecordset(this);
                    }
                  });
                  recordsets.push(recordset);
                }
                recordset = [];
                return columns = {};
              };
              req.on('doneInProc', doneHandler);
              req.on('done', doneHandler);
              req.on('returnValue', function(parameterName, value, metadata) {
                if (_this.verbose) {
                  if (value === tds.TYPES.Null) {
                    _this._log("   output: @" + parameterName + ", null");
                  } else {
                    _this._log("   output: @" + parameterName + ", " + (_this.parameters[parameterName].type.declaration.toLowerCase()) + ", " + value);
                  }
                }
                return _this.parameters[parameterName].value = value === tds.TYPES.Null ? null : value;
              });
              req.on('row', function(columns) {
                var col, exi, row, _i, _len;
                if (!recordset) {
                  recordset = [];
                }
                row = {};
                for (_i = 0, _len = columns.length; _i < _len; _i++) {
                  col = columns[_i];
                  col.value = valueCorrection(col.value, col.metadata);
                  exi = row[col.metadata.colName];
                  if (exi != null) {
                    if (exi instanceof Array) {
                      exi.push(col.value);
                    } else {
                      row[col.metadata.colName] = [exi, col.value];
                    }
                  } else {
                    row[col.metadata.colName] = col.value;
                  }
                }
                if (_this.verbose) {
                  _this._log(util.inspect(row));
                  _this._log("---------- --------------------");
                }
                if (_this.stream) {
                  if (_this._batch) {
                    if (row["___return___"] != null) {
                      return batchLastRow = row;
                    } else {
                      return _this.emit('row', row);
                    }
                  } else {
                    return _this.emit('row', row);
                  }
                } else {
                  return recordset.push(row);
                }
              });
              if (_this._batch) {
                if (Object.keys(_this.parameters).length) {
                  declarations = (function() {
                    var _ref1, _results;
                    _ref1 = this.parameters;
                    _results = [];
                    for (name in _ref1) {
                      param = _ref1[name];
                      _results.push("@" + name + " " + (declare(param.type, param)));
                    }
                    return _results;
                  }).call(_this);
                  assigns = (function() {
                    var _ref1, _results;
                    _ref1 = this.parameters;
                    _results = [];
                    for (name in _ref1) {
                      param = _ref1[name];
                      _results.push("@" + name + " = " + (cast(param.value, param.type, param)));
                    }
                    return _results;
                  }).call(_this);
                  selects = (function() {
                    var _ref1, _results;
                    _ref1 = this.parameters;
                    _results = [];
                    for (name in _ref1) {
                      param = _ref1[name];
                      if (param.io === 2) {
                        _results.push("@" + name + " as [" + name + "]");
                      }
                    }
                    return _results;
                  }).call(_this);
                  batchHasOutput = selects.length >  0;
                  req.sqlTextOrProcedure = "declare " + (declarations.join(', ')) + ";select " + (assigns.join(', ')) + ";" + req.sqlTextOrProcedure + ";" + (batchHasOutput ? 'select 1 as [___return___], ' + selects.join(', ') : '');
                }
              } else {
                _ref1 = _this.parameters;
                for (name in _ref1) {
                  param = _ref1[name];
                  if (_this.verbose) {
                    if (param.value === tds.TYPES.Null) {
                      _this._log("   " + (param.io === 1 ? " input" : "output") + ": @" + param.name + ", null");
                    } else {
                      _this._log("   " + (param.io === 1 ? " input" : "output") + ": @" + param.name + ", " + (param.type.declaration.toLowerCase()) + ", " + param.value);
                    }
                  }
                  if (param.io === 1) {
                    req.addParameter(param.name, getTediousType(param.type), parameterCorrection(param.value), {
                      length: param.length,
                      scale: param.scale,
                      precision: param.precision
                    });
                  } else {
                    req.addOutputParameter(param.name, getTediousType(param.type), parameterCorrection(param.value), {
                      length: param.length,
                      scale: param.scale,
                      precision: param.precision
                    });
                  }
                }
              }
              if (_this.verbose) {
                _this._log("---------- response -----------");
              }
              return connection[_this._batch ? 'execSqlBatch' : 'execSql'](req);
            } else {
              if (connection) {
                _this._release(connection);
              }
              return typeof callback === "function" ? callback(err) : void 0;
            }
          };
        })(this));
      };


      /*
      		Execute stored procedure with specified parameters.
       */

      TediousRequest.prototype.execute = function(procedure, callback) {
        var columns, errors, handleError, recordset, recordsets, returnValue, started;
        columns = {};
        recordset = [];
        recordsets = [];
        returnValue = 0;
        started = Date.now();
        errors = [];
        handleError = (function(_this) {
          return function(err) {
            var e;
            e = new RequestError(err.message, 'EREQUEST');
            if (_this.stream) {
              _this.emit('error', e);
            }
            return errors.push(e);
          };
        })(this);
        return this._acquire((function(_this) {
          return function(err, connection) {
            var name, param, req, _ref1;
            if (!err) {
              if (_this.verbose) {
                _this._log("---------- sql execute --------\n     proc: " + procedure);
              }
              if (_this.canceled) {
                if (_this.verbose) {
                  _this._log("---------- canceling ----------");
                }
                _this._release(connection);
                return typeof callback === "function" ? callback(new RequestError("Canceled.", 'ECANCEL')) : void 0;
              }
              _this._cancel = function() {
                if (_this.verbose) {
                  _this._log("---------- canceling ----------");
                }
                return connection.cancel();
              };
              connection.on('errorMessage', handleError);
              req = new tds.Request(procedure, function(err) {
                var elapsed, error, _i, _len, _ref1;
                if (err && err.message !== ((_ref1 = errors[errors.length - 1]) != null ? _ref1.message : void 0)) {
                  err = RequestError(err);
                  if (_this.stream) {
                    _this.emit('error', err);
                  }
                  errors.push(err);
                }
                if (_this.verbose) {
                  if (errors.length) {
                    for (_i = 0, _len = errors.length; _i < _len; _i++) {
                      error = errors[_i];
                      _this._log("    error: " + error);
                    }
                  }
                  elapsed = Date.now() - started;
                  _this._log("   return: " + returnValue);
                  _this._log(" duration: " + elapsed + "ms");
                  _this._log("---------- completed ----------");
                }
                _this._cancel = null;
                if (errors.length && !_this.stream) {
                  error = errors.pop();
                  error.precedingErrors = errors;
                }
                connection.removeListener('errorMessage', handleError);
                _this._release(connection);
                if (_this.stream) {
                  return callback(null, null, returnValue);
                } else {
                  recordsets.returnValue = returnValue;
                  return typeof callback === "function" ? callback(error, recordsets, returnValue) : void 0;
                }
              });
              req.on('columnMetadata', function(metadata) {
                columns = createColumns(metadata);
                if (_this.stream) {
                  return _this.emit('recordset', columns);
                }
              });
              req.on('row', function(columns) {
                var col, exi, row, _i, _len;
                if (!recordset) {
                  recordset = [];
                }
                row = {};
                for (_i = 0, _len = columns.length; _i < _len; _i++) {
                  col = columns[_i];
                  col.value = valueCorrection(col.value, col.metadata);
                  exi = row[col.metadata.colName];
                  if (exi != null) {
                    if (exi instanceof Array) {
                      exi.push(col.value);
                    } else {
                      row[col.metadata.colName] = [exi, col.value];
                    }
                  } else {
                    row[col.metadata.colName] = col.value;
                  }
                }
                if (_this.verbose) {
                  _this._log(util.inspect(row));
                  _this._log("---------- --------------------");
                }
                if (_this.stream) {
                  return _this.emit('row', row);
                } else {
                  return recordset.push(row);
                }
              });
              req.on('doneInProc', function(rowCount, more, rows) {
                if (Object.keys(columns).length === 0) {
                  return;
                }
                if (!_this.stream) {
                  Object.defineProperty(recordset, 'columns', {
                    enumerable: false,
                    value: columns
                  });
                  Object.defineProperty(recordset, 'toTable', {
                    enumerable: false,
                    value: function() {
                      return Table.fromRecordset(this);
                    }
                  });
                  recordsets.push(recordset);
                }
                recordset = [];
                return columns = {};
              });
              req.on('doneProc', function(rowCount, more, returnStatus, rows) {
                return returnValue = returnStatus;
              });
              req.on('returnValue', function(parameterName, value, metadata) {
                if (_this.verbose) {
                  if (value === tds.TYPES.Null) {
                    _this._log("   output: @" + parameterName + ", null");
                  } else {
                    _this._log("   output: @" + parameterName + ", " + (_this.parameters[parameterName].type.declaration.toLowerCase()) + ", " + value);
                  }
                }
                return _this.parameters[parameterName].value = value === tds.TYPES.Null ? null : value;
              });
              _ref1 = _this.parameters;
              for (name in _ref1) {
                param = _ref1[name];
                if (_this.verbose) {
                  if (param.value === tds.TYPES.Null) {
                    _this._log("   " + (param.io === 1 ? " input" : "output") + ": @" + param.name + ", null");
                  } else {
                    _this._log("   " + (param.io === 1 ? " input" : "output") + ": @" + param.name + ", " + (param.type.declaration.toLowerCase()) + ", " + param.value);
                  }
                }
                if (param.io === 1) {
                  req.addParameter(param.name, getTediousType(param.type), parameterCorrection(param.value), {
                    length: param.length,
                    scale: param.scale,
                    precision: param.precision
                  });
                } else {
                  req.addOutputParameter(param.name, getTediousType(param.type), parameterCorrection(param.value), {
                    length: param.length,
                    scale: param.scale,
                    precision: param.precision
                  });
                }
              }
              if (_this.verbose) {
                _this._log("---------- response -----------");
              }
              return connection.callProcedure(req);
            } else {
              if (connection) {
                _this._release(connection);
              }
              return typeof callback === "function" ? callback(err) : void 0;
            }
          };
        })(this));
      };


      /*
      		Cancel currently executed request.
       */

      TediousRequest.prototype.cancel = function() {
        if (this._cancel) {
          return this._cancel();
        }
        return true;
      };

      return TediousRequest;

    })(Request);
    return {
      Connection: TediousConnection,
      Transaction: TediousTransaction,
      Request: TediousRequest,
      fix: function() {}
    };
  };

}).call(this);
