connection.js 84 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.default = void 0;
  6. var _crypto = _interopRequireDefault(require("crypto"));
  7. var _os = _interopRequireDefault(require("os"));
  8. var _constants = _interopRequireDefault(require("constants"));
  9. var _tls = require("tls");
  10. var _msRestNodeauth = require("@azure/ms-rest-nodeauth");
  11. var _bulkLoad = _interopRequireDefault(require("./bulk-load"));
  12. var _debug = _interopRequireDefault(require("./debug"));
  13. var _events = require("events");
  14. var _instanceLookup = require("./instance-lookup");
  15. var _transientErrorLookup = require("./transient-error-lookup");
  16. var _packet = require("./packet");
  17. var _preloginPayload = _interopRequireDefault(require("./prelogin-payload"));
  18. var _login7Payload = _interopRequireDefault(require("./login7-payload"));
  19. var _ntlmPayload = _interopRequireDefault(require("./ntlm-payload"));
  20. var _request = _interopRequireDefault(require("./request"));
  21. var _rpcrequestPayload = _interopRequireDefault(require("./rpcrequest-payload"));
  22. var _sqlbatchPayload = _interopRequireDefault(require("./sqlbatch-payload"));
  23. var _messageIo = _interopRequireDefault(require("./message-io"));
  24. var _tokenStreamParser = require("./token/token-stream-parser");
  25. var _transaction = require("./transaction");
  26. var _errors = require("./errors");
  27. var _connector = require("./connector");
  28. var _library = require("./library");
  29. var _tdsVersions = require("./tds-versions");
  30. var _ntlm = require("./ntlm");
  31. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  32. // A rather basic state machine for managing a connection.
  33. // Implements something approximating s3.2.1.
  34. const KEEP_ALIVE_INITIAL_DELAY = 30 * 1000;
  35. const DEFAULT_CONNECT_TIMEOUT = 15 * 1000;
  36. const DEFAULT_CLIENT_REQUEST_TIMEOUT = 15 * 1000;
  37. const DEFAULT_CANCEL_TIMEOUT = 5 * 1000;
  38. const DEFAULT_CONNECT_RETRY_INTERVAL = 500;
  39. const DEFAULT_PACKET_SIZE = 4 * 1024;
  40. const DEFAULT_TEXTSIZE = '2147483647';
  41. const DEFAULT_DATEFIRST = 7;
  42. const DEFAULT_PORT = 1433;
  43. const DEFAULT_TDS_VERSION = '7_4';
  44. const DEFAULT_LANGUAGE = 'us_english';
  45. const DEFAULT_DATEFORMAT = 'mdy';
  46. const CLEANUP_TYPE = {
  47. NORMAL: 0,
  48. REDIRECT: 1,
  49. RETRY: 2
  50. };
  51. class Connection extends _events.EventEmitter {
  52. constructor(config) {
  53. super();
  54. if (typeof config !== 'object' || config === null) {
  55. throw new TypeError('The "config" argument is required and must be of type Object.');
  56. }
  57. if (typeof config.server !== 'string') {
  58. throw new TypeError('The "config.server" property is required and must be of type string.');
  59. }
  60. this.fedAuthRequired = false;
  61. this.fedAuthInfoToken = undefined;
  62. let authentication;
  63. if (config.authentication !== undefined) {
  64. if (typeof config.authentication !== 'object' || config.authentication === null) {
  65. throw new TypeError('The "config.authentication" property must be of type Object.');
  66. }
  67. const type = config.authentication.type;
  68. const options = config.authentication.options === undefined ? {} : config.authentication.options;
  69. if (typeof type !== 'string') {
  70. throw new TypeError('The "config.authentication.type" property must be of type string.');
  71. }
  72. if (type !== 'default' && type !== 'ntlm' && type !== 'azure-active-directory-password' && type !== 'azure-active-directory-access-token' && type !== 'azure-active-directory-msi-vm' && type !== 'azure-active-directory-msi-app-service' && type !== 'azure-active-directory-service-principal-secret') {
  73. throw new TypeError('The "type" property must one of "default", "ntlm", "azure-active-directory-password", "azure-active-directory-access-token", "azure-active-directory-msi-vm" or "azure-active-directory-msi-app-service" or "azure-active-directory-service-principal-secret".');
  74. }
  75. if (typeof options !== 'object' || options === null) {
  76. throw new TypeError('The "config.authentication.options" property must be of type object.');
  77. }
  78. if (type === 'ntlm') {
  79. if (typeof options.domain !== 'string') {
  80. throw new TypeError('The "config.authentication.options.domain" property must be of type string.');
  81. }
  82. if (options.userName !== undefined && typeof options.userName !== 'string') {
  83. throw new TypeError('The "config.authentication.options.userName" property must be of type string.');
  84. }
  85. if (options.password !== undefined && typeof options.password !== 'string') {
  86. throw new TypeError('The "config.authentication.options.password" property must be of type string.');
  87. }
  88. authentication = {
  89. type: 'ntlm',
  90. options: {
  91. userName: options.userName,
  92. password: options.password,
  93. domain: options.domain && options.domain.toUpperCase()
  94. }
  95. };
  96. } else if (type === 'azure-active-directory-password') {
  97. if (options.userName !== undefined && typeof options.userName !== 'string') {
  98. throw new TypeError('The "config.authentication.options.userName" property must be of type string.');
  99. }
  100. if (options.password !== undefined && typeof options.password !== 'string') {
  101. throw new TypeError('The "config.authentication.options.password" property must be of type string.');
  102. }
  103. authentication = {
  104. type: 'azure-active-directory-password',
  105. options: {
  106. userName: options.userName,
  107. password: options.password
  108. }
  109. };
  110. } else if (type === 'azure-active-directory-access-token') {
  111. if (typeof options.token !== 'string') {
  112. throw new TypeError('The "config.authentication.options.token" property must be of type string.');
  113. }
  114. authentication = {
  115. type: 'azure-active-directory-access-token',
  116. options: {
  117. token: options.token
  118. }
  119. };
  120. } else if (type === 'azure-active-directory-msi-vm') {
  121. if (options.clientId !== undefined && typeof options.clientId !== 'string') {
  122. throw new TypeError('The "config.authentication.options.clientId" property must be of type string.');
  123. }
  124. if (options.msiEndpoint !== undefined && typeof options.msiEndpoint !== 'string') {
  125. throw new TypeError('The "config.authentication.options.msiEndpoint" property must be of type string.');
  126. }
  127. authentication = {
  128. type: 'azure-active-directory-msi-vm',
  129. options: {
  130. clientId: options.clientId,
  131. msiEndpoint: options.msiEndpoint
  132. }
  133. };
  134. } else if (type === 'azure-active-directory-msi-app-service') {
  135. if (options.clientId !== undefined && typeof options.clientId !== 'string') {
  136. throw new TypeError('The "config.authentication.options.clientId" property must be of type string.');
  137. }
  138. if (options.msiEndpoint !== undefined && typeof options.msiEndpoint !== 'string') {
  139. throw new TypeError('The "config.authentication.options.msiEndpoint" property must be of type string.');
  140. }
  141. if (options.msiSecret !== undefined && typeof options.msiSecret !== 'string') {
  142. throw new TypeError('The "config.authentication.options.msiSecret" property must be of type string.');
  143. }
  144. authentication = {
  145. type: 'azure-active-directory-msi-app-service',
  146. options: {
  147. clientId: options.clientId,
  148. msiEndpoint: options.msiEndpoint,
  149. msiSecret: options.msiSecret
  150. }
  151. };
  152. } else if (type === 'azure-active-directory-service-principal-secret') {
  153. if (typeof options.clientId !== 'string') {
  154. throw new TypeError('The "config.authentication.options.clientId" property must be of type string.');
  155. }
  156. if (typeof options.clientSecret !== 'string') {
  157. throw new TypeError('The "config.authentication.options.clientSecret" property must be of type string.');
  158. }
  159. if (typeof options.tenantId !== 'string') {
  160. throw new TypeError('The "config.authentication.options.tenantId" property must be of type string.');
  161. }
  162. authentication = {
  163. type: 'azure-active-directory-service-principal-secret',
  164. options: {
  165. clientId: options.clientId,
  166. clientSecret: options.clientSecret,
  167. tenantId: options.tenantId
  168. }
  169. };
  170. } else {
  171. if (options.userName !== undefined && typeof options.userName !== 'string') {
  172. throw new TypeError('The "config.authentication.options.userName" property must be of type string.');
  173. }
  174. if (options.password !== undefined && typeof options.password !== 'string') {
  175. throw new TypeError('The "config.authentication.options.password" property must be of type string.');
  176. }
  177. authentication = {
  178. type: 'default',
  179. options: {
  180. userName: options.userName,
  181. password: options.password
  182. }
  183. };
  184. }
  185. } else {
  186. authentication = {
  187. type: 'default',
  188. options: {
  189. userName: undefined,
  190. password: undefined
  191. }
  192. };
  193. }
  194. this.config = {
  195. server: config.server,
  196. authentication: authentication,
  197. options: {
  198. abortTransactionOnError: false,
  199. appName: undefined,
  200. camelCaseColumns: false,
  201. cancelTimeout: DEFAULT_CANCEL_TIMEOUT,
  202. columnNameReplacer: undefined,
  203. connectionRetryInterval: DEFAULT_CONNECT_RETRY_INTERVAL,
  204. connectTimeout: DEFAULT_CONNECT_TIMEOUT,
  205. connectionIsolationLevel: _transaction.ISOLATION_LEVEL.READ_COMMITTED,
  206. cryptoCredentialsDetails: {},
  207. database: undefined,
  208. datefirst: DEFAULT_DATEFIRST,
  209. dateFormat: DEFAULT_DATEFORMAT,
  210. debug: {
  211. data: false,
  212. packet: false,
  213. payload: false,
  214. token: false
  215. },
  216. enableAnsiNull: true,
  217. enableAnsiNullDefault: true,
  218. enableAnsiPadding: true,
  219. enableAnsiWarnings: true,
  220. enableArithAbort: false,
  221. enableConcatNullYieldsNull: true,
  222. enableCursorCloseOnCommit: null,
  223. enableImplicitTransactions: false,
  224. enableNumericRoundabort: false,
  225. enableQuotedIdentifier: true,
  226. encrypt: false,
  227. fallbackToDefaultDb: false,
  228. instanceName: undefined,
  229. isolationLevel: _transaction.ISOLATION_LEVEL.READ_COMMITTED,
  230. language: DEFAULT_LANGUAGE,
  231. localAddress: undefined,
  232. maxRetriesOnTransientErrors: 3,
  233. multiSubnetFailover: false,
  234. packetSize: DEFAULT_PACKET_SIZE,
  235. port: DEFAULT_PORT,
  236. readOnlyIntent: false,
  237. requestTimeout: DEFAULT_CLIENT_REQUEST_TIMEOUT,
  238. rowCollectionOnDone: false,
  239. rowCollectionOnRequestCompletion: false,
  240. tdsVersion: DEFAULT_TDS_VERSION,
  241. textsize: DEFAULT_TEXTSIZE,
  242. trustServerCertificate: true,
  243. useColumnNames: false,
  244. useUTC: true,
  245. lowerCaseGuids: false
  246. }
  247. };
  248. if (config.options) {
  249. if (config.options.port && config.options.instanceName) {
  250. throw new Error('Port and instanceName are mutually exclusive, but ' + config.options.port + ' and ' + config.options.instanceName + ' provided');
  251. }
  252. if (config.options.abortTransactionOnError !== undefined) {
  253. if (typeof config.options.abortTransactionOnError !== 'boolean' && config.options.abortTransactionOnError !== null) {
  254. throw new TypeError('The "config.options.abortTransactionOnError" property must be of type string or null.');
  255. }
  256. this.config.options.abortTransactionOnError = config.options.abortTransactionOnError;
  257. }
  258. if (config.options.appName !== undefined) {
  259. if (typeof config.options.appName !== 'string') {
  260. throw new TypeError('The "config.options.appName" property must be of type string.');
  261. }
  262. this.config.options.appName = config.options.appName;
  263. }
  264. if (config.options.camelCaseColumns !== undefined) {
  265. if (typeof config.options.camelCaseColumns !== 'boolean') {
  266. throw new TypeError('The "config.options.camelCaseColumns" property must be of type boolean.');
  267. }
  268. this.config.options.camelCaseColumns = config.options.camelCaseColumns;
  269. }
  270. if (config.options.cancelTimeout !== undefined) {
  271. if (typeof config.options.cancelTimeout !== 'number') {
  272. throw new TypeError('The "config.options.cancelTimeout" property must be of type number.');
  273. }
  274. this.config.options.cancelTimeout = config.options.cancelTimeout;
  275. }
  276. if (config.options.columnNameReplacer) {
  277. if (typeof config.options.columnNameReplacer !== 'function') {
  278. throw new TypeError('The "config.options.cancelTimeout" property must be of type function.');
  279. }
  280. this.config.options.columnNameReplacer = config.options.columnNameReplacer;
  281. }
  282. if (config.options.connectTimeout !== undefined) {
  283. if (typeof config.options.connectTimeout !== 'number') {
  284. throw new TypeError('The "config.options.connectTimeout" property must be of type number.');
  285. }
  286. this.config.options.connectTimeout = config.options.connectTimeout;
  287. }
  288. if (config.options.connectionIsolationLevel !== undefined) {
  289. this.config.options.connectionIsolationLevel = config.options.connectionIsolationLevel;
  290. }
  291. if (config.options.connectTimeout !== undefined) {
  292. if (typeof config.options.connectTimeout !== 'number') {
  293. throw new TypeError('The "config.options.connectTimeout" property must be of type number.');
  294. }
  295. this.config.options.connectTimeout = config.options.connectTimeout;
  296. }
  297. if (config.options.cryptoCredentialsDetails !== undefined) {
  298. if (typeof config.options.cryptoCredentialsDetails !== 'object' || config.options.cryptoCredentialsDetails === null) {
  299. throw new TypeError('The "config.options.cryptoCredentialsDetails" property must be of type Object.');
  300. }
  301. this.config.options.cryptoCredentialsDetails = config.options.cryptoCredentialsDetails;
  302. }
  303. if (config.options.database !== undefined) {
  304. if (typeof config.options.database !== 'string') {
  305. throw new TypeError('The "config.options.database" property must be of type string.');
  306. }
  307. this.config.options.database = config.options.database;
  308. }
  309. if (config.options.datefirst !== undefined) {
  310. if (typeof config.options.datefirst !== 'number' && config.options.datefirst !== null) {
  311. throw new TypeError('The "config.options.datefirst" property must be of type number.');
  312. }
  313. if (config.options.datefirst !== null && (config.options.datefirst < 1 || config.options.datefirst > 7)) {
  314. throw new RangeError('The "config.options.datefirst" property must be >= 1 and <= 7');
  315. }
  316. this.config.options.datefirst = config.options.datefirst;
  317. }
  318. if (config.options.dateFormat !== undefined) {
  319. if (typeof config.options.dateFormat !== 'string' && config.options.dateFormat !== null) {
  320. throw new TypeError('The "config.options.dateFormat" property must be of type string or null.');
  321. }
  322. this.config.options.dateFormat = config.options.dateFormat;
  323. }
  324. if (config.options.debug) {
  325. if (config.options.debug.data !== undefined) {
  326. if (typeof config.options.debug.data !== 'boolean') {
  327. throw new TypeError('The "config.options.debug.data" property must be of type boolean.');
  328. }
  329. this.config.options.debug.data = config.options.debug.data;
  330. }
  331. if (config.options.debug.packet !== undefined) {
  332. if (typeof config.options.debug.packet !== 'boolean') {
  333. throw new TypeError('The "config.options.debug.packet" property must be of type boolean.');
  334. }
  335. this.config.options.debug.packet = config.options.debug.packet;
  336. }
  337. if (config.options.debug.payload !== undefined) {
  338. if (typeof config.options.debug.payload !== 'boolean') {
  339. throw new TypeError('The "config.options.debug.payload" property must be of type boolean.');
  340. }
  341. this.config.options.debug.payload = config.options.debug.payload;
  342. }
  343. if (config.options.debug.token !== undefined) {
  344. if (typeof config.options.debug.token !== 'boolean') {
  345. throw new TypeError('The "config.options.debug.token" property must be of type boolean.');
  346. }
  347. this.config.options.debug.token = config.options.debug.token;
  348. }
  349. }
  350. if (config.options.enableAnsiNull !== undefined) {
  351. if (typeof config.options.enableAnsiNull !== 'boolean' && config.options.enableAnsiNull !== null) {
  352. throw new TypeError('The "config.options.enableAnsiNull" property must be of type boolean or null.');
  353. }
  354. this.config.options.enableAnsiNull = config.options.enableAnsiNull;
  355. }
  356. if (config.options.enableAnsiNullDefault !== undefined) {
  357. if (typeof config.options.enableAnsiNullDefault !== 'boolean' && config.options.enableAnsiNullDefault !== null) {
  358. throw new TypeError('The "config.options.enableAnsiNullDefault" property must be of type boolean or null.');
  359. }
  360. this.config.options.enableAnsiNullDefault = config.options.enableAnsiNullDefault;
  361. }
  362. if (config.options.enableAnsiPadding !== undefined) {
  363. if (typeof config.options.enableAnsiPadding !== 'boolean' && config.options.enableAnsiPadding !== null) {
  364. throw new TypeError('The "config.options.enableAnsiPadding" property must be of type boolean or null.');
  365. }
  366. this.config.options.enableAnsiPadding = config.options.enableAnsiPadding;
  367. }
  368. if (config.options.enableAnsiWarnings !== undefined) {
  369. if (typeof config.options.enableAnsiWarnings !== 'boolean' && config.options.enableAnsiWarnings !== null) {
  370. throw new TypeError('The "config.options.enableAnsiWarnings" property must be of type boolean or null.');
  371. }
  372. this.config.options.enableAnsiWarnings = config.options.enableAnsiWarnings;
  373. }
  374. if (config.options.enableArithAbort !== undefined) {
  375. if (typeof config.options.enableArithAbort !== 'boolean' && config.options.enableArithAbort !== null) {
  376. throw new TypeError('The "config.options.enableArithAbort" property must be of type boolean or null.');
  377. }
  378. this.config.options.enableArithAbort = config.options.enableArithAbort;
  379. }
  380. if (config.options.enableConcatNullYieldsNull !== undefined) {
  381. if (typeof config.options.enableConcatNullYieldsNull !== 'boolean' && config.options.enableConcatNullYieldsNull !== null) {
  382. throw new TypeError('The "config.options.enableConcatNullYieldsNull" property must be of type boolean or null.');
  383. }
  384. this.config.options.enableConcatNullYieldsNull = config.options.enableConcatNullYieldsNull;
  385. }
  386. if (config.options.enableCursorCloseOnCommit !== undefined) {
  387. if (typeof config.options.enableCursorCloseOnCommit !== 'boolean' && config.options.enableCursorCloseOnCommit !== null) {
  388. throw new TypeError('The "config.options.enableCursorCloseOnCommit" property must be of type boolean or null.');
  389. }
  390. this.config.options.enableCursorCloseOnCommit = config.options.enableCursorCloseOnCommit;
  391. }
  392. if (config.options.enableImplicitTransactions !== undefined) {
  393. if (typeof config.options.enableImplicitTransactions !== 'boolean' && config.options.enableImplicitTransactions !== null) {
  394. throw new TypeError('The "config.options.enableImplicitTransactions" property must be of type boolean or null.');
  395. }
  396. this.config.options.enableImplicitTransactions = config.options.enableImplicitTransactions;
  397. }
  398. if (config.options.enableNumericRoundabort !== undefined) {
  399. if (typeof config.options.enableNumericRoundabort !== 'boolean' && config.options.enableNumericRoundabort !== null) {
  400. throw new TypeError('The "config.options.enableNumericRoundabort" property must be of type boolean or null.');
  401. }
  402. this.config.options.enableNumericRoundabort = config.options.enableNumericRoundabort;
  403. }
  404. if (config.options.enableQuotedIdentifier !== undefined) {
  405. if (typeof config.options.enableQuotedIdentifier !== 'boolean' && config.options.enableQuotedIdentifier !== null) {
  406. throw new TypeError('The "config.options.enableQuotedIdentifier" property must be of type boolean or null.');
  407. }
  408. this.config.options.enableQuotedIdentifier = config.options.enableQuotedIdentifier;
  409. }
  410. if (config.options.encrypt !== undefined) {
  411. if (typeof config.options.encrypt !== 'boolean') {
  412. throw new TypeError('The "config.options.encrypt" property must be of type boolean.');
  413. }
  414. this.config.options.encrypt = config.options.encrypt;
  415. } else {
  416. this.config.options.encrypt = true;
  417. }
  418. if (config.options.fallbackToDefaultDb !== undefined) {
  419. if (typeof config.options.fallbackToDefaultDb !== 'boolean') {
  420. throw new TypeError('The "config.options.fallbackToDefaultDb" property must be of type boolean.');
  421. }
  422. this.config.options.fallbackToDefaultDb = config.options.fallbackToDefaultDb;
  423. }
  424. if (config.options.instanceName !== undefined) {
  425. if (typeof config.options.instanceName !== 'string') {
  426. throw new TypeError('The "config.options.instanceName" property must be of type string.');
  427. }
  428. this.config.options.instanceName = config.options.instanceName;
  429. this.config.options.port = undefined;
  430. }
  431. if (config.options.isolationLevel !== undefined) {
  432. if (typeof config.options.isolationLevel !== 'number') {
  433. throw new TypeError('The "config.options.language" property must be of type numer.');
  434. }
  435. this.config.options.isolationLevel = config.options.isolationLevel;
  436. }
  437. if (config.options.language !== undefined) {
  438. if (typeof config.options.language !== 'string' && config.options.language !== null) {
  439. throw new TypeError('The "config.options.language" property must be of type string or null.');
  440. }
  441. this.config.options.language = config.options.language;
  442. }
  443. if (config.options.localAddress !== undefined) {
  444. if (typeof config.options.localAddress !== 'string') {
  445. throw new TypeError('The "config.options.localAddress" property must be of type string.');
  446. }
  447. this.config.options.localAddress = config.options.localAddress;
  448. }
  449. if (config.options.multiSubnetFailover !== undefined) {
  450. if (typeof config.options.multiSubnetFailover !== 'boolean') {
  451. throw new TypeError('The "config.options.multiSubnetFailover" property must be of type boolean.');
  452. }
  453. this.config.options.multiSubnetFailover = config.options.multiSubnetFailover;
  454. }
  455. if (config.options.packetSize !== undefined) {
  456. if (typeof config.options.packetSize !== 'number') {
  457. throw new TypeError('The "config.options.packetSize" property must be of type number.');
  458. }
  459. this.config.options.packetSize = config.options.packetSize;
  460. }
  461. if (config.options.port !== undefined) {
  462. if (typeof config.options.port !== 'number') {
  463. throw new TypeError('The "config.options.port" property must be of type number.');
  464. }
  465. if (config.options.port <= 0 || config.options.port >= 65536) {
  466. throw new RangeError('The "config.options.port" property must be > 0 and < 65536');
  467. }
  468. this.config.options.port = config.options.port;
  469. this.config.options.instanceName = undefined;
  470. }
  471. if (config.options.readOnlyIntent !== undefined) {
  472. if (typeof config.options.readOnlyIntent !== 'boolean') {
  473. throw new TypeError('The "config.options.readOnlyIntent" property must be of type boolean.');
  474. }
  475. this.config.options.readOnlyIntent = config.options.readOnlyIntent;
  476. }
  477. if (config.options.requestTimeout !== undefined) {
  478. if (typeof config.options.requestTimeout !== 'number') {
  479. throw new TypeError('The "config.options.requestTimeout" property must be of type number.');
  480. }
  481. this.config.options.requestTimeout = config.options.requestTimeout;
  482. }
  483. if (config.options.maxRetriesOnTransientErrors !== undefined) {
  484. if (typeof config.options.maxRetriesOnTransientErrors !== 'number') {
  485. throw new TypeError('The "config.options.maxRetriesOnTransientErrors" property must be of type number.');
  486. }
  487. if (config.options.maxRetriesOnTransientErrors < 0) {
  488. throw new TypeError('The "config.options.maxRetriesOnTransientErrors" property must be equal or greater than 0.');
  489. }
  490. this.config.options.maxRetriesOnTransientErrors = config.options.maxRetriesOnTransientErrors;
  491. }
  492. if (config.options.connectionRetryInterval !== undefined) {
  493. if (typeof config.options.connectionRetryInterval !== 'number') {
  494. throw new TypeError('The "config.options.connectionRetryInterval" property must be of type number.');
  495. }
  496. if (config.options.connectionRetryInterval <= 0) {
  497. throw new TypeError('The "config.options.connectionRetryInterval" property must be greater than 0.');
  498. }
  499. this.config.options.connectionRetryInterval = config.options.connectionRetryInterval;
  500. }
  501. if (config.options.rowCollectionOnDone !== undefined) {
  502. if (typeof config.options.rowCollectionOnDone !== 'boolean') {
  503. throw new TypeError('The "config.options.rowCollectionOnDone" property must be of type boolean.');
  504. }
  505. this.config.options.rowCollectionOnDone = config.options.rowCollectionOnDone;
  506. }
  507. if (config.options.rowCollectionOnRequestCompletion !== undefined) {
  508. if (typeof config.options.rowCollectionOnRequestCompletion !== 'boolean') {
  509. throw new TypeError('The "config.options.rowCollectionOnRequestCompletion" property must be of type boolean.');
  510. }
  511. this.config.options.rowCollectionOnRequestCompletion = config.options.rowCollectionOnRequestCompletion;
  512. }
  513. if (config.options.tdsVersion !== undefined) {
  514. if (typeof config.options.tdsVersion !== 'string') {
  515. throw new TypeError('The "config.options.tdsVersion" property must be of type string.');
  516. }
  517. this.config.options.tdsVersion = config.options.tdsVersion;
  518. }
  519. if (config.options.textsize !== undefined) {
  520. if (typeof config.options.textsize !== 'number' && config.options.textsize !== null) {
  521. throw new TypeError('The "config.options.textsize" property must be of type number or null.');
  522. }
  523. this.config.options.textsize = config.options.textsize;
  524. }
  525. if (config.options.trustServerCertificate !== undefined) {
  526. if (typeof config.options.trustServerCertificate !== 'boolean') {
  527. throw new TypeError('The "config.options.trustServerCertificate" property must be of type boolean.');
  528. }
  529. this.config.options.trustServerCertificate = config.options.trustServerCertificate;
  530. }
  531. if (config.options.useColumnNames !== undefined) {
  532. if (typeof config.options.useColumnNames !== 'boolean') {
  533. throw new TypeError('The "config.options.useColumnNames" property must be of type boolean.');
  534. }
  535. this.config.options.useColumnNames = config.options.useColumnNames;
  536. }
  537. if (config.options.useUTC !== undefined) {
  538. if (typeof config.options.useUTC !== 'boolean') {
  539. throw new TypeError('The "config.options.useUTC" property must be of type boolean.');
  540. }
  541. this.config.options.useUTC = config.options.useUTC;
  542. }
  543. if (config.options.lowerCaseGuids !== undefined) {
  544. if (typeof config.options.lowerCaseGuids !== 'boolean') {
  545. throw new TypeError('The "config.options.lowerCaseGuids" property must be of type boolean.');
  546. }
  547. this.config.options.lowerCaseGuids = config.options.lowerCaseGuids;
  548. }
  549. }
  550. let credentialsDetails = this.config.options.cryptoCredentialsDetails;
  551. if (credentialsDetails.secureOptions === undefined) {
  552. // If the caller has not specified their own `secureOptions`,
  553. // we set `SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS` here.
  554. // Older SQL Server instances running on older Windows versions have
  555. // trouble with the BEAST workaround in OpenSSL.
  556. // As BEAST is a browser specific exploit, we can just disable this option here.
  557. credentialsDetails = Object.create(credentialsDetails, {
  558. secureOptions: {
  559. value: _constants.default.SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
  560. }
  561. });
  562. }
  563. this.secureContext = (0, _tls.createSecureContext)(credentialsDetails);
  564. this.debug = this.createDebug();
  565. this.tokenStreamParser = this.createTokenStreamParser();
  566. this.inTransaction = false;
  567. this.transactionDescriptors = [Buffer.from([0, 0, 0, 0, 0, 0, 0, 0])]; // 'beginTransaction', 'commitTransaction' and 'rollbackTransaction'
  568. // events are utilized to maintain inTransaction property state which in
  569. // turn is used in managing transactions. These events are only fired for
  570. // TDS version 7.2 and beyond. The properties below are used to emulate
  571. // equivalent behavior for TDS versions before 7.2.
  572. this.transactionDepth = 0;
  573. this.isSqlBatch = false;
  574. this.closed = false;
  575. this.loggedIn = false;
  576. this.messageBuffer = Buffer.alloc(0);
  577. this.curTransientRetryCount = 0;
  578. this.transientErrorLookup = new _transientErrorLookup.TransientErrorLookup();
  579. this.state = this.STATE.CONNECTING;
  580. this.state.enter.call(this);
  581. }
  582. close() {
  583. this.transitionTo(this.STATE.FINAL);
  584. }
  585. initialiseConnection() {
  586. this.connect();
  587. this.createConnectTimer();
  588. }
  589. cleanupConnection(cleanupType) {
  590. if (!this.closed) {
  591. this.clearConnectTimer();
  592. this.clearRequestTimer();
  593. this.clearRetryTimer();
  594. this.closeConnection();
  595. if (cleanupType === CLEANUP_TYPE.REDIRECT) {
  596. this.emit('rerouting');
  597. } else if (cleanupType !== CLEANUP_TYPE.RETRY) {
  598. process.nextTick(() => {
  599. this.emit('end');
  600. });
  601. }
  602. const request = this.request;
  603. if (request) {
  604. const err = (0, _errors.RequestError)('Connection closed before request completed.', 'ECLOSE');
  605. request.callback(err);
  606. this.request = undefined;
  607. }
  608. this.closed = true;
  609. this.loggedIn = false;
  610. this.loginError = undefined;
  611. }
  612. }
  613. createDebug() {
  614. const debug = new _debug.default(this.config.options.debug);
  615. debug.on('debug', message => {
  616. this.emit('debug', message);
  617. });
  618. return debug;
  619. }
  620. createTokenStreamParser() {
  621. const tokenStreamParser = new _tokenStreamParser.Parser(this.debug, undefined, this.config.options);
  622. tokenStreamParser.on('infoMessage', token => {
  623. this.emit('infoMessage', token);
  624. });
  625. tokenStreamParser.on('sspichallenge', token => {
  626. if (token.ntlmpacket) {
  627. this.ntlmpacket = token.ntlmpacket;
  628. this.ntlmpacketBuffer = token.ntlmpacketBuffer;
  629. }
  630. this.emit('sspichallenge', token);
  631. });
  632. tokenStreamParser.on('errorMessage', token => {
  633. this.emit('errorMessage', token);
  634. if (this.loggedIn) {
  635. const request = this.request;
  636. if (request) {
  637. if (!request.canceled) {
  638. const error = new _errors.RequestError(token.message, 'EREQUEST');
  639. error.number = token.number;
  640. error.state = token.state;
  641. error.class = token.class;
  642. error.serverName = token.serverName;
  643. error.procName = token.procName;
  644. error.lineNumber = token.lineNumber;
  645. request.error = error;
  646. }
  647. }
  648. } else {
  649. const error = (0, _errors.ConnectionError)(token.message, 'ELOGIN');
  650. const isLoginErrorTransient = this.transientErrorLookup.isTransientError(token.number);
  651. if (isLoginErrorTransient && this.curTransientRetryCount !== this.config.options.maxRetriesOnTransientErrors) {
  652. error.isTransient = true;
  653. }
  654. this.loginError = error;
  655. }
  656. });
  657. tokenStreamParser.on('databaseChange', token => {
  658. this.emit('databaseChange', token.newValue);
  659. });
  660. tokenStreamParser.on('languageChange', token => {
  661. this.emit('languageChange', token.newValue);
  662. });
  663. tokenStreamParser.on('charsetChange', token => {
  664. this.emit('charsetChange', token.newValue);
  665. });
  666. tokenStreamParser.on('fedAuthInfo', token => {
  667. this.dispatchEvent('fedAuthInfo', token);
  668. });
  669. tokenStreamParser.on('featureExtAck', token => {
  670. this.dispatchEvent('featureExtAck', token);
  671. });
  672. tokenStreamParser.on('loginack', token => {
  673. if (!token.tdsVersion) {
  674. // unsupported TDS version
  675. this.loginError = (0, _errors.ConnectionError)('Server responded with unknown TDS version.', 'ETDS');
  676. this.loggedIn = false;
  677. return;
  678. }
  679. if (!token.interface) {
  680. // unsupported interface
  681. this.loginError = (0, _errors.ConnectionError)('Server responded with unsupported interface.', 'EINTERFACENOTSUPP');
  682. this.loggedIn = false;
  683. return;
  684. } // use negotiated version
  685. this.config.options.tdsVersion = token.tdsVersion;
  686. this.loggedIn = true;
  687. });
  688. tokenStreamParser.on('routingChange', token => {
  689. this.routingData = token.newValue;
  690. this.dispatchEvent('routingChange');
  691. });
  692. tokenStreamParser.on('packetSizeChange', token => {
  693. this.messageIo.packetSize(token.newValue);
  694. }); // A new top-level transaction was started. This is not fired
  695. // for nested transactions.
  696. tokenStreamParser.on('beginTransaction', token => {
  697. this.transactionDescriptors.push(token.newValue);
  698. this.inTransaction = true;
  699. }); // A top-level transaction was committed. This is not fired
  700. // for nested transactions.
  701. tokenStreamParser.on('commitTransaction', () => {
  702. this.transactionDescriptors.length = 1;
  703. this.inTransaction = false;
  704. }); // A top-level transaction was rolled back. This is not fired
  705. // for nested transactions. This is also fired if a batch
  706. // aborting error happened that caused a rollback.
  707. tokenStreamParser.on('rollbackTransaction', () => {
  708. this.transactionDescriptors.length = 1; // An outermost transaction was rolled back. Reset the transaction counter
  709. this.inTransaction = false;
  710. this.emit('rollbackTransaction');
  711. });
  712. tokenStreamParser.on('columnMetadata', token => {
  713. const request = this.request;
  714. if (request) {
  715. if (!request.canceled) {
  716. if (this.config.options.useColumnNames) {
  717. const columns = {};
  718. for (let j = 0, len = token.columns.length; j < len; j++) {
  719. const col = token.columns[j];
  720. if (columns[col.colName] == null) {
  721. columns[col.colName] = col;
  722. }
  723. }
  724. request.emit('columnMetadata', columns);
  725. } else {
  726. request.emit('columnMetadata', token.columns);
  727. }
  728. }
  729. } else {
  730. this.emit('error', new Error("Received 'columnMetadata' when no sqlRequest is in progress"));
  731. this.close();
  732. }
  733. });
  734. tokenStreamParser.on('order', token => {
  735. const request = this.request;
  736. if (request) {
  737. if (!request.canceled) {
  738. request.emit('order', token.orderColumns);
  739. }
  740. } else {
  741. this.emit('error', new Error("Received 'order' when no sqlRequest is in progress"));
  742. this.close();
  743. }
  744. });
  745. tokenStreamParser.on('row', token => {
  746. const request = this.request;
  747. if (request) {
  748. if (!request.canceled) {
  749. if (this.config.options.rowCollectionOnRequestCompletion) {
  750. request.rows.push(token.columns);
  751. }
  752. if (this.config.options.rowCollectionOnDone) {
  753. request.rst.push(token.columns);
  754. }
  755. if (!(this.state === this.STATE.SENT_ATTENTION && request.paused)) {
  756. request.emit('row', token.columns);
  757. }
  758. }
  759. } else {
  760. this.emit('error', new Error("Received 'row' when no sqlRequest is in progress"));
  761. this.close();
  762. }
  763. });
  764. tokenStreamParser.on('returnStatus', token => {
  765. const request = this.request;
  766. if (request) {
  767. if (!request.canceled) {
  768. // Keep value for passing in 'doneProc' event.
  769. this.procReturnStatusValue = token.value;
  770. }
  771. }
  772. });
  773. tokenStreamParser.on('returnValue', token => {
  774. const request = this.request;
  775. if (request) {
  776. if (!request.canceled) {
  777. request.emit('returnValue', token.paramName, token.value, token.metadata);
  778. }
  779. }
  780. });
  781. tokenStreamParser.on('doneProc', token => {
  782. const request = this.request;
  783. if (request) {
  784. if (!request.canceled) {
  785. request.emit('doneProc', token.rowCount, token.more, this.procReturnStatusValue, request.rst);
  786. this.procReturnStatusValue = undefined;
  787. if (token.rowCount !== undefined) {
  788. request.rowCount += token.rowCount;
  789. }
  790. if (this.config.options.rowCollectionOnDone) {
  791. request.rst = [];
  792. }
  793. }
  794. }
  795. });
  796. tokenStreamParser.on('doneInProc', token => {
  797. const request = this.request;
  798. if (request) {
  799. if (!request.canceled) {
  800. request.emit('doneInProc', token.rowCount, token.more, request.rst);
  801. if (token.rowCount !== undefined) {
  802. request.rowCount += token.rowCount;
  803. }
  804. if (this.config.options.rowCollectionOnDone) {
  805. request.rst = [];
  806. }
  807. }
  808. }
  809. });
  810. tokenStreamParser.on('done', token => {
  811. const request = this.request;
  812. if (request) {
  813. if (token.attention) {
  814. this.dispatchEvent('attention');
  815. }
  816. if (request.canceled) {
  817. // If we received a `DONE` token with `DONE_ERROR`, but no previous `ERROR` token,
  818. // We assume this is the indication that an in-flight request was canceled.
  819. if (token.sqlError && !request.error) {
  820. this.clearCancelTimer();
  821. request.error = (0, _errors.RequestError)('Canceled.', 'ECANCEL');
  822. }
  823. } else {
  824. if (token.sqlError && !request.error) {
  825. // check if the DONE_ERROR flags was set, but an ERROR token was not sent.
  826. request.error = (0, _errors.RequestError)('An unknown error has occurred.', 'UNKNOWN');
  827. }
  828. request.emit('done', token.rowCount, token.more, request.rst);
  829. if (token.rowCount !== undefined) {
  830. request.rowCount += token.rowCount;
  831. }
  832. if (this.config.options.rowCollectionOnDone) {
  833. request.rst = [];
  834. }
  835. }
  836. }
  837. });
  838. tokenStreamParser.on('endOfMessage', () => {
  839. // EOM pseudo token received
  840. if (this.state === this.STATE.SENT_CLIENT_REQUEST) {
  841. this.dispatchEvent('endOfMessageMarkerReceived');
  842. }
  843. });
  844. tokenStreamParser.on('resetConnection', () => {
  845. this.emit('resetConnection');
  846. });
  847. tokenStreamParser.on('drain', () => {
  848. // Bridge the release of backpressure from the token stream parser
  849. // transform to the packet stream transform.
  850. this.messageIo.resume();
  851. });
  852. return tokenStreamParser;
  853. }
  854. connect() {
  855. if (this.config.options.port) {
  856. return this.connectOnPort(this.config.options.port, this.config.options.multiSubnetFailover);
  857. } else {
  858. return new _instanceLookup.InstanceLookup().instanceLookup({
  859. server: this.config.server,
  860. instanceName: this.config.options.instanceName,
  861. timeout: this.config.options.connectTimeout
  862. }, (message, port) => {
  863. if (this.state === this.STATE.FINAL) {
  864. return;
  865. }
  866. if (message) {
  867. this.emit('connect', (0, _errors.ConnectionError)(message, 'EINSTLOOKUP'));
  868. } else {
  869. this.connectOnPort(port, this.config.options.multiSubnetFailover);
  870. }
  871. });
  872. }
  873. }
  874. connectOnPort(port, multiSubnetFailover) {
  875. const connectOpts = {
  876. host: this.routingData ? this.routingData.server : this.config.server,
  877. port: this.routingData ? this.routingData.port : port,
  878. localAddress: this.config.options.localAddress
  879. };
  880. new _connector.Connector(connectOpts, multiSubnetFailover).execute((err, socket) => {
  881. if (err) {
  882. return this.socketError(err);
  883. }
  884. if (this.state === this.STATE.FINAL) {
  885. socket.destroy();
  886. return;
  887. }
  888. socket.on('error', error => {
  889. this.socketError(error);
  890. });
  891. socket.on('close', () => {
  892. this.socketClose();
  893. });
  894. socket.on('end', () => {
  895. this.socketEnd();
  896. });
  897. socket.setKeepAlive(true, KEEP_ALIVE_INITIAL_DELAY);
  898. this.messageIo = new _messageIo.default(socket, this.config.options.packetSize, this.debug);
  899. this.messageIo.on('data', data => {
  900. this.dispatchEvent('data', data);
  901. });
  902. this.messageIo.on('message', () => {
  903. this.dispatchEvent('message');
  904. });
  905. this.messageIo.on('secure', cleartext => {
  906. this.emit('secure', cleartext);
  907. });
  908. this.socket = socket;
  909. this.socketConnect();
  910. });
  911. }
  912. closeConnection() {
  913. if (this.socket) {
  914. this.socket.destroy();
  915. }
  916. }
  917. createConnectTimer() {
  918. this.connectTimer = setTimeout(() => {
  919. this.connectTimeout();
  920. }, this.config.options.connectTimeout);
  921. }
  922. createCancelTimer() {
  923. this.clearCancelTimer();
  924. const timeout = this.config.options.cancelTimeout;
  925. if (timeout > 0) {
  926. this.cancelTimer = setTimeout(() => {
  927. this.cancelTimeout();
  928. }, timeout);
  929. }
  930. }
  931. createRequestTimer() {
  932. this.clearRequestTimer(); // release old timer, just to be safe
  933. const request = this.request;
  934. const timeout = request.timeout !== undefined ? request.timeout : this.config.options.requestTimeout;
  935. if (timeout) {
  936. this.requestTimer = setTimeout(() => {
  937. this.requestTimeout();
  938. }, timeout);
  939. }
  940. }
  941. createRetryTimer() {
  942. this.clearRetryTimer();
  943. this.retryTimer = setTimeout(() => {
  944. this.retryTimeout();
  945. }, this.config.options.connectionRetryInterval);
  946. }
  947. connectTimeout() {
  948. const message = `Failed to connect to ${this.config.server}${this.config.options.port ? `:${this.config.options.port}` : `\\${this.config.options.instanceName}`} in ${this.config.options.connectTimeout}ms`;
  949. this.debug.log(message);
  950. this.emit('connect', (0, _errors.ConnectionError)(message, 'ETIMEOUT'));
  951. this.connectTimer = undefined;
  952. this.dispatchEvent('connectTimeout');
  953. }
  954. cancelTimeout() {
  955. const message = `Failed to cancel request in ${this.config.options.cancelTimeout}ms`;
  956. this.debug.log(message);
  957. this.dispatchEvent('socketError', (0, _errors.ConnectionError)(message, 'ETIMEOUT'));
  958. }
  959. requestTimeout() {
  960. this.requestTimer = undefined;
  961. const request = this.request;
  962. request.cancel();
  963. const timeout = request.timeout !== undefined ? request.timeout : this.config.options.requestTimeout;
  964. const message = 'Timeout: Request failed to complete in ' + timeout + 'ms';
  965. request.error = (0, _errors.RequestError)(message, 'ETIMEOUT');
  966. }
  967. retryTimeout() {
  968. this.retryTimer = undefined;
  969. this.emit('retry');
  970. this.transitionTo(this.STATE.CONNECTING);
  971. }
  972. clearConnectTimer() {
  973. if (this.connectTimer) {
  974. clearTimeout(this.connectTimer);
  975. }
  976. }
  977. clearCancelTimer() {
  978. if (this.cancelTimer) {
  979. clearTimeout(this.cancelTimer);
  980. }
  981. }
  982. clearRequestTimer() {
  983. if (this.requestTimer) {
  984. clearTimeout(this.requestTimer);
  985. this.requestTimer = undefined;
  986. }
  987. }
  988. clearRetryTimer() {
  989. if (this.retryTimer) {
  990. clearTimeout(this.retryTimer);
  991. this.retryTimer = undefined;
  992. }
  993. }
  994. transitionTo(newState) {
  995. if (this.state === newState) {
  996. this.debug.log('State is already ' + newState.name);
  997. return;
  998. }
  999. if (this.state && this.state.exit) {
  1000. this.state.exit.call(this, newState);
  1001. }
  1002. this.debug.log('State change: ' + (this.state ? this.state.name : 'undefined') + ' -> ' + newState.name);
  1003. this.state = newState;
  1004. if (this.state.enter) {
  1005. this.state.enter.apply(this);
  1006. }
  1007. }
  1008. getEventHandler(eventName) {
  1009. const handler = this.state.events[eventName];
  1010. if (!handler) {
  1011. throw new Error(`No event '${eventName}' in state '${this.state.name}'`);
  1012. }
  1013. return handler;
  1014. }
  1015. dispatchEvent(eventName, ...args) {
  1016. const handler = this.state.events[eventName];
  1017. if (handler) {
  1018. handler.apply(this, args);
  1019. } else {
  1020. this.emit('error', new Error(`No event '${eventName}' in state '${this.state.name}'`));
  1021. this.close();
  1022. }
  1023. }
  1024. socketError(error) {
  1025. if (this.state === this.STATE.CONNECTING || this.state === this.STATE.SENT_TLSSSLNEGOTIATION) {
  1026. const message = `Failed to connect to ${this.config.server}:${this.config.options.port} - ${error.message}`;
  1027. this.debug.log(message);
  1028. this.emit('connect', (0, _errors.ConnectionError)(message, 'ESOCKET'));
  1029. } else {
  1030. const message = `Connection lost - ${error.message}`;
  1031. this.debug.log(message);
  1032. this.emit('error', (0, _errors.ConnectionError)(message, 'ESOCKET'));
  1033. }
  1034. this.dispatchEvent('socketError', error);
  1035. }
  1036. socketConnect() {
  1037. this.closed = false;
  1038. this.debug.log('connected to ' + this.config.server + ':' + this.config.options.port);
  1039. this.dispatchEvent('socketConnect');
  1040. }
  1041. socketEnd() {
  1042. this.debug.log('socket ended');
  1043. if (this.state !== this.STATE.FINAL) {
  1044. const error = new Error('socket hang up');
  1045. error.code = 'ECONNRESET';
  1046. this.socketError(error);
  1047. }
  1048. }
  1049. socketClose() {
  1050. this.debug.log('connection to ' + this.config.server + ':' + this.config.options.port + ' closed');
  1051. if (this.state === this.STATE.REROUTING) {
  1052. this.debug.log('Rerouting to ' + this.routingData.server + ':' + this.routingData.port);
  1053. this.dispatchEvent('reconnect');
  1054. } else if (this.state === this.STATE.TRANSIENT_FAILURE_RETRY) {
  1055. const server = this.routingData ? this.routingData.server : this.config.server;
  1056. const port = this.routingData ? this.routingData.port : this.config.options.port;
  1057. this.debug.log('Retry after transient failure connecting to ' + server + ':' + port);
  1058. this.dispatchEvent('retry');
  1059. } else {
  1060. this.transitionTo(this.STATE.FINAL);
  1061. }
  1062. }
  1063. sendPreLogin() {
  1064. const payload = new _preloginPayload.default({
  1065. encrypt: this.config.options.encrypt
  1066. });
  1067. this.messageIo.sendMessage(_packet.TYPE.PRELOGIN, payload.data);
  1068. this.debug.payload(function () {
  1069. return payload.toString(' ');
  1070. });
  1071. }
  1072. emptyMessageBuffer() {
  1073. this.messageBuffer = Buffer.alloc(0);
  1074. }
  1075. addToMessageBuffer(data) {
  1076. this.messageBuffer = Buffer.concat([this.messageBuffer, data]);
  1077. }
  1078. sendLogin7Packet() {
  1079. const payload = new _login7Payload.default({
  1080. tdsVersion: _tdsVersions.versions[this.config.options.tdsVersion],
  1081. packetSize: this.config.options.packetSize,
  1082. clientProgVer: 0,
  1083. clientPid: process.pid,
  1084. connectionId: 0,
  1085. clientTimeZone: new Date().getTimezoneOffset(),
  1086. clientLcid: 0x00000409
  1087. });
  1088. const authentication = this.config.authentication;
  1089. switch (authentication.type) {
  1090. case 'azure-active-directory-password':
  1091. payload.fedAuth = {
  1092. type: 'ADAL',
  1093. echo: this.fedAuthRequired,
  1094. workflow: 'default'
  1095. };
  1096. break;
  1097. case 'azure-active-directory-access-token':
  1098. payload.fedAuth = {
  1099. type: 'SECURITYTOKEN',
  1100. echo: this.fedAuthRequired,
  1101. fedAuthToken: authentication.options.token
  1102. };
  1103. break;
  1104. case 'azure-active-directory-msi-vm':
  1105. case 'azure-active-directory-msi-app-service':
  1106. case 'azure-active-directory-service-principal-secret':
  1107. payload.fedAuth = {
  1108. type: 'ADAL',
  1109. echo: this.fedAuthRequired,
  1110. workflow: 'integrated'
  1111. };
  1112. break;
  1113. case 'ntlm':
  1114. payload.sspi = (0, _ntlm.createNTLMRequest)({
  1115. domain: authentication.options.domain
  1116. });
  1117. break;
  1118. default:
  1119. payload.userName = authentication.options.userName;
  1120. payload.password = authentication.options.password;
  1121. }
  1122. payload.hostname = _os.default.hostname();
  1123. payload.serverName = this.routingData ? this.routingData.server : this.config.server;
  1124. payload.appName = this.config.options.appName || 'Tedious';
  1125. payload.libraryName = _library.name;
  1126. payload.language = this.config.options.language;
  1127. payload.database = this.config.options.database;
  1128. payload.clientId = Buffer.from([1, 2, 3, 4, 5, 6]);
  1129. payload.readOnlyIntent = this.config.options.readOnlyIntent;
  1130. payload.initDbFatal = !this.config.options.fallbackToDefaultDb;
  1131. this.routingData = undefined;
  1132. this.messageIo.sendMessage(_packet.TYPE.LOGIN7, payload.toBuffer());
  1133. this.debug.payload(function () {
  1134. return payload.toString(' ');
  1135. });
  1136. }
  1137. sendFedAuthTokenMessage(token) {
  1138. const accessTokenLen = Buffer.byteLength(token, 'ucs2');
  1139. const data = Buffer.alloc(8 + accessTokenLen);
  1140. let offset = 0;
  1141. offset = data.writeUInt32LE(accessTokenLen + 4, offset);
  1142. offset = data.writeUInt32LE(accessTokenLen, offset);
  1143. data.write(token, offset, 'ucs2');
  1144. this.messageIo.sendMessage(_packet.TYPE.FEDAUTH_TOKEN, data); // sent the fedAuth token message, the rest is similar to standard login 7
  1145. this.transitionTo(this.STATE.SENT_LOGIN7_WITH_STANDARD_LOGIN);
  1146. } // Returns false to apply backpressure.
  1147. sendDataToTokenStreamParser(data) {
  1148. return this.tokenStreamParser.addBuffer(data);
  1149. } // This is an internal method that is called from Request.pause().
  1150. // It has to check whether the passed Request object represents the currently
  1151. // active request, because the application might have called Request.pause()
  1152. // on an old inactive Request object.
  1153. pauseRequest(request) {
  1154. if (this.isRequestActive(request)) {
  1155. this.tokenStreamParser.pause();
  1156. }
  1157. } // This is an internal method that is called from Request.resume().
  1158. resumeRequest(request) {
  1159. if (this.isRequestActive(request)) {
  1160. this.tokenStreamParser.resume();
  1161. }
  1162. } // Returns true if the passed request is the currently active request of the connection.
  1163. isRequestActive(request) {
  1164. return request === this.request && this.state === this.STATE.SENT_CLIENT_REQUEST;
  1165. }
  1166. sendInitialSql() {
  1167. const payload = new _sqlbatchPayload.default(this.getInitialSql(), this.currentTransactionDescriptor(), this.config.options);
  1168. payload.getData(data => {
  1169. return this.messageIo.sendMessage(_packet.TYPE.SQL_BATCH, data);
  1170. });
  1171. }
  1172. getInitialSql() {
  1173. const options = [];
  1174. if (this.config.options.enableAnsiNull === true) {
  1175. options.push('set ansi_nulls on');
  1176. } else if (this.config.options.enableAnsiNull === false) {
  1177. options.push('set ansi_nulls off');
  1178. }
  1179. if (this.config.options.enableAnsiNullDefault === true) {
  1180. options.push('set ansi_null_dflt_on on');
  1181. } else if (this.config.options.enableAnsiNullDefault === false) {
  1182. options.push('set ansi_null_dflt_on off');
  1183. }
  1184. if (this.config.options.enableAnsiPadding === true) {
  1185. options.push('set ansi_padding on');
  1186. } else if (this.config.options.enableAnsiPadding === false) {
  1187. options.push('set ansi_padding off');
  1188. }
  1189. if (this.config.options.enableAnsiWarnings === true) {
  1190. options.push('set ansi_warnings on');
  1191. } else if (this.config.options.enableAnsiWarnings === false) {
  1192. options.push('set ansi_warnings off');
  1193. }
  1194. if (this.config.options.enableArithAbort === true) {
  1195. options.push('set arithabort on');
  1196. } else if (this.config.options.enableArithAbort === false) {
  1197. options.push('set arithabort off');
  1198. }
  1199. if (this.config.options.enableConcatNullYieldsNull === true) {
  1200. options.push('set concat_null_yields_null on');
  1201. } else if (this.config.options.enableArithAbort === false) {
  1202. options.push('set concat_null_yields_null off');
  1203. }
  1204. if (this.config.options.enableCursorCloseOnCommit === true) {
  1205. options.push('set cursor_close_on_commit on');
  1206. } else if (this.config.options.enableCursorCloseOnCommit === false) {
  1207. options.push('set cursor_close_on_commit off');
  1208. }
  1209. if (this.config.options.datefirst !== null) {
  1210. options.push(`set datefirst ${this.config.options.datefirst}`);
  1211. }
  1212. if (this.config.options.dateFormat !== null) {
  1213. options.push(`set dateformat ${this.config.options.dateFormat}`);
  1214. }
  1215. if (this.config.options.enableImplicitTransactions === true) {
  1216. options.push('set implicit_transactions on');
  1217. } else if (this.config.options.enableImplicitTransactions === false) {
  1218. options.push('set implicit_transactions off');
  1219. }
  1220. if (this.config.options.language !== null) {
  1221. options.push(`set language ${this.config.options.language}`);
  1222. }
  1223. if (this.config.options.enableNumericRoundabort === true) {
  1224. options.push('set numeric_roundabort on');
  1225. } else if (this.config.options.enableNumericRoundabort === false) {
  1226. options.push('set numeric_roundabort off');
  1227. }
  1228. if (this.config.options.enableQuotedIdentifier === true) {
  1229. options.push('set quoted_identifier on');
  1230. } else if (this.config.options.enableQuotedIdentifier === false) {
  1231. options.push('set quoted_identifier off');
  1232. }
  1233. if (this.config.options.textsize !== null) {
  1234. options.push(`set textsize ${this.config.options.textsize}`);
  1235. }
  1236. if (this.config.options.connectionIsolationLevel !== null) {
  1237. options.push(`set transaction isolation level ${this.getIsolationLevelText(this.config.options.connectionIsolationLevel)}`);
  1238. }
  1239. if (this.config.options.abortTransactionOnError === true) {
  1240. options.push('set xact_abort on');
  1241. } else if (this.config.options.abortTransactionOnError === false) {
  1242. options.push('set xact_abort off');
  1243. }
  1244. return options.join('\n');
  1245. }
  1246. processedInitialSql() {
  1247. this.clearConnectTimer();
  1248. this.emit('connect');
  1249. }
  1250. execSqlBatch(request) {
  1251. this.makeRequest(request, _packet.TYPE.SQL_BATCH, new _sqlbatchPayload.default(request.sqlTextOrProcedure, this.currentTransactionDescriptor(), this.config.options));
  1252. }
  1253. execSql(request) {
  1254. request.transformIntoExecuteSqlRpc();
  1255. const error = request.error;
  1256. if (error != null) {
  1257. process.nextTick(() => {
  1258. this.debug.log(error.message);
  1259. request.callback(error);
  1260. });
  1261. return;
  1262. }
  1263. this.makeRequest(request, _packet.TYPE.RPC_REQUEST, new _rpcrequestPayload.default(request, this.currentTransactionDescriptor(), this.config.options));
  1264. }
  1265. /**
  1266. @function newBulkLoad
  1267. @param {string} table - Table's name.
  1268. @param {Object} [options] - BulkLoad options.
  1269. @param {boolean} [options.checkConstraints=false] - Honors constraints during bulk load, it is disabled by default.
  1270. @param {boolean} [options.fireTriggers=false] - Honors insert triggers during bulk load, it is disabled by default.
  1271. @param {boolean} [options.keepNulls=false] - Honors null value passed, ignores the default values set on table.
  1272. @param {boolean} [options.tableLock=false] - Places a bulk update(BU) lock on table while performing bulk load. Uses row locks by default.
  1273. @param {callback} callback - Function to call after BulkLoad executes.
  1274. */
  1275. newBulkLoad(table, callbackOrOptions, callback) {
  1276. let options;
  1277. if (callback === undefined) {
  1278. callback = callbackOrOptions;
  1279. options = {};
  1280. } else {
  1281. options = callbackOrOptions;
  1282. }
  1283. if (typeof options !== 'object') {
  1284. throw new TypeError('"options" argument must be an object');
  1285. }
  1286. return new _bulkLoad.default(table, this.config.options, options, callback);
  1287. }
  1288. execBulkLoad(bulkLoad) {
  1289. bulkLoad.executionStarted = true;
  1290. const request = new _request.default(bulkLoad.getBulkInsertSql(), error => {
  1291. if (error) {
  1292. if (error.code === 'UNKNOWN') {
  1293. error.message += ' This is likely because the schema of the BulkLoad does not match the schema of the table you are attempting to insert into.';
  1294. }
  1295. bulkLoad.error = error;
  1296. bulkLoad.callback(error);
  1297. return;
  1298. }
  1299. this.makeRequest(bulkLoad, _packet.TYPE.BULK_LOAD);
  1300. });
  1301. bulkLoad.once('cancel', () => {
  1302. request.cancel();
  1303. });
  1304. this.execSqlBatch(request);
  1305. }
  1306. prepare(request) {
  1307. request.transformIntoPrepareRpc();
  1308. this.makeRequest(request, _packet.TYPE.RPC_REQUEST, new _rpcrequestPayload.default(request, this.currentTransactionDescriptor(), this.config.options));
  1309. }
  1310. unprepare(request) {
  1311. request.transformIntoUnprepareRpc();
  1312. this.makeRequest(request, _packet.TYPE.RPC_REQUEST, new _rpcrequestPayload.default(request, this.currentTransactionDescriptor(), this.config.options));
  1313. }
  1314. execute(request, parameters) {
  1315. request.transformIntoExecuteRpc(parameters);
  1316. const error = request.error;
  1317. if (error != null) {
  1318. process.nextTick(() => {
  1319. this.debug.log(error.message);
  1320. request.callback(error);
  1321. });
  1322. return;
  1323. }
  1324. this.makeRequest(request, _packet.TYPE.RPC_REQUEST, new _rpcrequestPayload.default(request, this.currentTransactionDescriptor(), this.config.options));
  1325. }
  1326. callProcedure(request) {
  1327. request.validateParameters();
  1328. const error = request.error;
  1329. if (error != null) {
  1330. process.nextTick(() => {
  1331. this.debug.log(error.message);
  1332. request.callback(error);
  1333. });
  1334. return;
  1335. }
  1336. this.makeRequest(request, _packet.TYPE.RPC_REQUEST, new _rpcrequestPayload.default(request, this.currentTransactionDescriptor(), this.config.options));
  1337. }
  1338. beginTransaction(callback, name = '', isolationLevel = this.config.options.isolationLevel) {
  1339. const transaction = new _transaction.Transaction(name, isolationLevel);
  1340. if (this.config.options.tdsVersion < '7_2') {
  1341. return this.execSqlBatch(new _request.default('SET TRANSACTION ISOLATION LEVEL ' + transaction.isolationLevelToTSQL() + ';BEGIN TRAN ' + transaction.name, err => {
  1342. this.transactionDepth++;
  1343. if (this.transactionDepth === 1) {
  1344. this.inTransaction = true;
  1345. }
  1346. callback(err);
  1347. }));
  1348. }
  1349. const request = new _request.default(undefined, err => {
  1350. return callback(err, this.currentTransactionDescriptor());
  1351. });
  1352. return this.makeRequest(request, _packet.TYPE.TRANSACTION_MANAGER, transaction.beginPayload(this.currentTransactionDescriptor()));
  1353. }
  1354. commitTransaction(callback, name = '') {
  1355. const transaction = new _transaction.Transaction(name);
  1356. if (this.config.options.tdsVersion < '7_2') {
  1357. return this.execSqlBatch(new _request.default('COMMIT TRAN ' + transaction.name, err => {
  1358. this.transactionDepth--;
  1359. if (this.transactionDepth === 0) {
  1360. this.inTransaction = false;
  1361. }
  1362. callback(err);
  1363. }));
  1364. }
  1365. const request = new _request.default(undefined, callback);
  1366. return this.makeRequest(request, _packet.TYPE.TRANSACTION_MANAGER, transaction.commitPayload(this.currentTransactionDescriptor()));
  1367. }
  1368. rollbackTransaction(callback, name = '') {
  1369. const transaction = new _transaction.Transaction(name);
  1370. if (this.config.options.tdsVersion < '7_2') {
  1371. return this.execSqlBatch(new _request.default('ROLLBACK TRAN ' + transaction.name, err => {
  1372. this.transactionDepth--;
  1373. if (this.transactionDepth === 0) {
  1374. this.inTransaction = false;
  1375. }
  1376. callback(err);
  1377. }));
  1378. }
  1379. const request = new _request.default(undefined, callback);
  1380. return this.makeRequest(request, _packet.TYPE.TRANSACTION_MANAGER, transaction.rollbackPayload(this.currentTransactionDescriptor()));
  1381. }
  1382. saveTransaction(callback, name) {
  1383. const transaction = new _transaction.Transaction(name);
  1384. if (this.config.options.tdsVersion < '7_2') {
  1385. return this.execSqlBatch(new _request.default('SAVE TRAN ' + transaction.name, err => {
  1386. this.transactionDepth++;
  1387. callback(err);
  1388. }));
  1389. }
  1390. const request = new _request.default(undefined, callback);
  1391. return this.makeRequest(request, _packet.TYPE.TRANSACTION_MANAGER, transaction.savePayload(this.currentTransactionDescriptor()));
  1392. }
  1393. transaction(cb, isolationLevel) {
  1394. if (typeof cb !== 'function') {
  1395. throw new TypeError('`cb` must be a function');
  1396. }
  1397. const useSavepoint = this.inTransaction;
  1398. const name = '_tedious_' + _crypto.default.randomBytes(10).toString('hex');
  1399. const txDone = (err, done, ...args) => {
  1400. if (err) {
  1401. if (this.inTransaction && this.state === this.STATE.LOGGED_IN) {
  1402. this.rollbackTransaction(txErr => {
  1403. done(txErr || err, ...args);
  1404. }, name);
  1405. } else {
  1406. done(err, ...args);
  1407. }
  1408. } else if (useSavepoint) {
  1409. if (this.config.options.tdsVersion < '7_2') {
  1410. this.transactionDepth--;
  1411. }
  1412. done(null, ...args);
  1413. } else {
  1414. this.commitTransaction(txErr => {
  1415. done(txErr, ...args);
  1416. }, name);
  1417. }
  1418. };
  1419. if (useSavepoint) {
  1420. return this.saveTransaction(err => {
  1421. if (err) {
  1422. return cb(err);
  1423. }
  1424. if (isolationLevel) {
  1425. return this.execSqlBatch(new _request.default('SET transaction isolation level ' + this.getIsolationLevelText(isolationLevel), err => {
  1426. return cb(err, txDone);
  1427. }));
  1428. } else {
  1429. return cb(null, txDone);
  1430. }
  1431. }, name);
  1432. } else {
  1433. return this.beginTransaction(err => {
  1434. if (err) {
  1435. return cb(err);
  1436. }
  1437. return cb(null, txDone);
  1438. }, name, isolationLevel);
  1439. }
  1440. }
  1441. makeRequest(request, packetType, payload) {
  1442. if (this.state !== this.STATE.LOGGED_IN) {
  1443. const message = 'Requests can only be made in the ' + this.STATE.LOGGED_IN.name + ' state, not the ' + this.state.name + ' state';
  1444. this.debug.log(message);
  1445. request.callback((0, _errors.RequestError)(message, 'EINVALIDSTATE'));
  1446. } else if (request.canceled) {
  1447. process.nextTick(() => {
  1448. request.callback((0, _errors.RequestError)('Canceled.', 'ECANCEL'));
  1449. });
  1450. } else {
  1451. if (packetType === _packet.TYPE.SQL_BATCH) {
  1452. this.isSqlBatch = true;
  1453. } else {
  1454. this.isSqlBatch = false;
  1455. }
  1456. this.request = request;
  1457. request.connection = this;
  1458. request.rowCount = 0;
  1459. request.rows = [];
  1460. request.rst = [];
  1461. let message;
  1462. request.once('cancel', () => {
  1463. if (!this.isRequestActive(request)) {
  1464. // Cancel was called on a request that is no longer active on this connection
  1465. return;
  1466. } // There's three ways to handle request cancelation:
  1467. if (this.state === this.STATE.BUILDING_CLIENT_REQUEST) {
  1468. // The request was cancelled before buffering finished
  1469. this.request = undefined;
  1470. request.callback((0, _errors.RequestError)('Canceled.', 'ECANCEL'));
  1471. this.transitionTo(this.STATE.LOGGED_IN);
  1472. } else if (message.writable) {
  1473. // - if the message is still writable, we'll set the ignore bit
  1474. // and end the message.
  1475. message.ignore = true;
  1476. message.end();
  1477. } else {
  1478. // - but if the message has been ended (and thus has been fully sent off),
  1479. // we need to send an `ATTENTION` message to the server
  1480. this.messageIo.sendMessage(_packet.TYPE.ATTENTION);
  1481. this.transitionTo(this.STATE.SENT_ATTENTION);
  1482. }
  1483. this.clearRequestTimer();
  1484. this.createCancelTimer();
  1485. });
  1486. if (request instanceof _bulkLoad.default) {
  1487. message = request.getMessageStream(); // If the bulkload was not put into streaming mode by the user,
  1488. // we end the rowToPacketTransform here for them.
  1489. //
  1490. // If it was put into streaming mode, it's the user's responsibility
  1491. // to end the stream.
  1492. if (!request.streamingMode) {
  1493. request.rowToPacketTransform.end();
  1494. }
  1495. this.messageIo.outgoingMessageStream.write(message);
  1496. this.transitionTo(this.STATE.SENT_CLIENT_REQUEST);
  1497. if (request.paused) {
  1498. // Request.pause() has been called before the request was started
  1499. this.pauseRequest(request);
  1500. }
  1501. } else {
  1502. this.createRequestTimer(); // Transition to an intermediate state to ensure that no new requests
  1503. // are made on the connection while the buffer is being populated.
  1504. this.transitionTo(this.STATE.BUILDING_CLIENT_REQUEST);
  1505. payload.getData(data => {
  1506. if (this.state !== this.STATE.BUILDING_CLIENT_REQUEST) {
  1507. // Something else has happened on the connection since starting to
  1508. // build the request. That state change should have invoked the
  1509. // request handler so there is nothing to do at this point.
  1510. return;
  1511. }
  1512. message = this.messageIo.sendMessage(packetType, data, this.resetConnectionOnNextRequest);
  1513. this.resetConnectionOnNextRequest = false;
  1514. this.debug.payload(function () {
  1515. return payload.toString(' ');
  1516. });
  1517. this.transitionTo(this.STATE.SENT_CLIENT_REQUEST);
  1518. if (request.paused) {
  1519. // Request.pause() has been called before the request was started
  1520. this.pauseRequest(request);
  1521. }
  1522. });
  1523. }
  1524. }
  1525. }
  1526. cancel() {
  1527. if (!this.request) {
  1528. return false;
  1529. }
  1530. if (this.request.canceled) {
  1531. return false;
  1532. }
  1533. this.request.cancel();
  1534. return true;
  1535. }
  1536. reset(callback) {
  1537. const request = new _request.default(this.getInitialSql(), err => {
  1538. if (this.config.options.tdsVersion < '7_2') {
  1539. this.inTransaction = false;
  1540. }
  1541. callback(err);
  1542. });
  1543. this.resetConnectionOnNextRequest = true;
  1544. this.execSqlBatch(request);
  1545. }
  1546. currentTransactionDescriptor() {
  1547. return this.transactionDescriptors[this.transactionDescriptors.length - 1];
  1548. }
  1549. getIsolationLevelText(isolationLevel) {
  1550. switch (isolationLevel) {
  1551. case _transaction.ISOLATION_LEVEL.READ_UNCOMMITTED:
  1552. return 'read uncommitted';
  1553. case _transaction.ISOLATION_LEVEL.REPEATABLE_READ:
  1554. return 'repeatable read';
  1555. case _transaction.ISOLATION_LEVEL.SERIALIZABLE:
  1556. return 'serializable';
  1557. case _transaction.ISOLATION_LEVEL.SNAPSHOT:
  1558. return 'snapshot';
  1559. default:
  1560. return 'read committed';
  1561. }
  1562. }
  1563. }
  1564. var _default = Connection;
  1565. exports.default = _default;
  1566. module.exports = Connection;
  1567. Connection.prototype.STATE = {
  1568. CONNECTING: {
  1569. name: 'Connecting',
  1570. enter: function enter() {
  1571. this.initialiseConnection();
  1572. },
  1573. events: {
  1574. socketError: function socketError() {
  1575. this.transitionTo(this.STATE.FINAL);
  1576. },
  1577. connectTimeout: function connectTimeout() {
  1578. this.transitionTo(this.STATE.FINAL);
  1579. },
  1580. socketConnect: function socketConnect() {
  1581. this.sendPreLogin();
  1582. this.transitionTo(this.STATE.SENT_PRELOGIN);
  1583. }
  1584. }
  1585. },
  1586. SENT_PRELOGIN: {
  1587. name: 'SentPrelogin',
  1588. enter: function enter() {
  1589. this.emptyMessageBuffer();
  1590. },
  1591. events: {
  1592. socketError: function socketError() {
  1593. this.transitionTo(this.STATE.FINAL);
  1594. },
  1595. connectTimeout: function connectTimeout() {
  1596. this.transitionTo(this.STATE.FINAL);
  1597. },
  1598. data: function (_data) {
  1599. function data(_x) {
  1600. return _data.apply(this, arguments);
  1601. }
  1602. data.toString = function () {
  1603. return _data.toString();
  1604. };
  1605. return data;
  1606. }(function (data) {
  1607. this.addToMessageBuffer(data);
  1608. }),
  1609. message: function message() {
  1610. const preloginPayload = new _preloginPayload.default(this.messageBuffer);
  1611. this.debug.payload(function () {
  1612. return preloginPayload.toString(' ');
  1613. });
  1614. if (preloginPayload.fedAuthRequired === 1) {
  1615. this.fedAuthRequired = true;
  1616. }
  1617. if (preloginPayload.encryptionString === 'ON' || preloginPayload.encryptionString === 'REQ') {
  1618. if (!this.config.options.encrypt) {
  1619. this.emit('connect', (0, _errors.ConnectionError)("Server requires encryption, set 'encrypt' config option to true.", 'EENCRYPT'));
  1620. return this.close();
  1621. }
  1622. this.messageIo.startTls(this.secureContext, this.config.server, this.config.options.trustServerCertificate);
  1623. this.transitionTo(this.STATE.SENT_TLSSSLNEGOTIATION);
  1624. } else {
  1625. this.sendLogin7Packet();
  1626. const authentication = this.config.authentication;
  1627. if (authentication.type === 'ntlm') {
  1628. this.transitionTo(this.STATE.SENT_LOGIN7_WITH_NTLM);
  1629. } else {
  1630. this.transitionTo(this.STATE.SENT_LOGIN7_WITH_STANDARD_LOGIN);
  1631. }
  1632. }
  1633. }
  1634. }
  1635. },
  1636. REROUTING: {
  1637. name: 'ReRouting',
  1638. enter: function enter() {
  1639. this.cleanupConnection(CLEANUP_TYPE.REDIRECT);
  1640. },
  1641. events: {
  1642. message: function message() {},
  1643. socketError: function socketError() {
  1644. this.transitionTo(this.STATE.FINAL);
  1645. },
  1646. connectTimeout: function connectTimeout() {
  1647. this.transitionTo(this.STATE.FINAL);
  1648. },
  1649. reconnect: function reconnect() {
  1650. this.transitionTo(this.STATE.CONNECTING);
  1651. }
  1652. }
  1653. },
  1654. TRANSIENT_FAILURE_RETRY: {
  1655. name: 'TRANSIENT_FAILURE_RETRY',
  1656. enter: function enter() {
  1657. this.curTransientRetryCount++;
  1658. this.cleanupConnection(CLEANUP_TYPE.RETRY);
  1659. },
  1660. events: {
  1661. message: function message() {},
  1662. socketError: function socketError() {
  1663. this.transitionTo(this.STATE.FINAL);
  1664. },
  1665. connectTimeout: function connectTimeout() {
  1666. this.transitionTo(this.STATE.FINAL);
  1667. },
  1668. retry: function retry() {
  1669. this.createRetryTimer();
  1670. }
  1671. }
  1672. },
  1673. SENT_TLSSSLNEGOTIATION: {
  1674. name: 'SentTLSSSLNegotiation',
  1675. events: {
  1676. socketError: function socketError() {
  1677. this.transitionTo(this.STATE.FINAL);
  1678. },
  1679. connectTimeout: function connectTimeout() {
  1680. this.transitionTo(this.STATE.FINAL);
  1681. },
  1682. data: function (_data2) {
  1683. function data(_x2) {
  1684. return _data2.apply(this, arguments);
  1685. }
  1686. data.toString = function () {
  1687. return _data2.toString();
  1688. };
  1689. return data;
  1690. }(function (data) {
  1691. this.messageIo.tlsHandshakeData(data);
  1692. }),
  1693. message: function message() {
  1694. if (this.messageIo.tlsNegotiationComplete) {
  1695. this.sendLogin7Packet();
  1696. const authentication = this.config.authentication;
  1697. if (authentication.type === 'azure-active-directory-password' || authentication.type === 'azure-active-directory-msi-vm' || authentication.type === 'azure-active-directory-msi-app-service' || authentication.type === 'azure-active-directory-service-principal-secret') {
  1698. this.transitionTo(this.STATE.SENT_LOGIN7_WITH_FEDAUTH);
  1699. } else if (authentication.type === 'ntlm') {
  1700. this.transitionTo(this.STATE.SENT_LOGIN7_WITH_NTLM);
  1701. } else {
  1702. this.transitionTo(this.STATE.SENT_LOGIN7_WITH_STANDARD_LOGIN);
  1703. }
  1704. }
  1705. }
  1706. }
  1707. },
  1708. SENT_LOGIN7_WITH_STANDARD_LOGIN: {
  1709. name: 'SentLogin7WithStandardLogin',
  1710. events: {
  1711. socketError: function socketError() {
  1712. this.transitionTo(this.STATE.FINAL);
  1713. },
  1714. connectTimeout: function connectTimeout() {
  1715. this.transitionTo(this.STATE.FINAL);
  1716. },
  1717. data: function (_data3) {
  1718. function data(_x3) {
  1719. return _data3.apply(this, arguments);
  1720. }
  1721. data.toString = function () {
  1722. return _data3.toString();
  1723. };
  1724. return data;
  1725. }(function (data) {
  1726. this.sendDataToTokenStreamParser(data);
  1727. }),
  1728. routingChange: function routingChange() {
  1729. this.transitionTo(this.STATE.REROUTING);
  1730. },
  1731. featureExtAck: function featureExtAck(token) {
  1732. const authentication = this.config.authentication;
  1733. if (authentication.type === 'azure-active-directory-password' || authentication.type === 'azure-active-directory-access-token' || authentication.type === 'azure-active-directory-msi-vm' || authentication.type === 'azure-active-directory-msi-app-service' || authentication.type === 'azure-active-directory-service-principal-secret') {
  1734. if (token.fedAuth === undefined) {
  1735. this.loginError = (0, _errors.ConnectionError)('Did not receive Active Directory authentication acknowledgement');
  1736. this.loggedIn = false;
  1737. } else if (token.fedAuth.length !== 0) {
  1738. this.loginError = (0, _errors.ConnectionError)(`Active Directory authentication acknowledgment for ${authentication.type} authentication method includes extra data`);
  1739. this.loggedIn = false;
  1740. }
  1741. } else if (token.fedAuth === undefined) {
  1742. this.loginError = (0, _errors.ConnectionError)('Received acknowledgement for unknown feature');
  1743. this.loggedIn = false;
  1744. } else {
  1745. this.loginError = (0, _errors.ConnectionError)('Did not request Active Directory authentication, but received the acknowledgment');
  1746. this.loggedIn = false;
  1747. }
  1748. },
  1749. message: function message() {
  1750. if (this.loggedIn) {
  1751. this.transitionTo(this.STATE.LOGGED_IN_SENDING_INITIAL_SQL);
  1752. } else if (this.loginError) {
  1753. if (this.loginError.isTransient) {
  1754. this.debug.log('Initiating retry on transient error');
  1755. this.transitionTo(this.STATE.TRANSIENT_FAILURE_RETRY);
  1756. } else {
  1757. this.emit('connect', this.loginError);
  1758. this.transitionTo(this.STATE.FINAL);
  1759. }
  1760. } else {
  1761. this.emit('connect', (0, _errors.ConnectionError)('Login failed.', 'ELOGIN'));
  1762. this.transitionTo(this.STATE.FINAL);
  1763. }
  1764. }
  1765. }
  1766. },
  1767. SENT_LOGIN7_WITH_NTLM: {
  1768. name: 'SentLogin7WithNTLMLogin',
  1769. events: {
  1770. socketError: function socketError() {
  1771. this.transitionTo(this.STATE.FINAL);
  1772. },
  1773. connectTimeout: function connectTimeout() {
  1774. this.transitionTo(this.STATE.FINAL);
  1775. },
  1776. data: function (_data4) {
  1777. function data(_x4) {
  1778. return _data4.apply(this, arguments);
  1779. }
  1780. data.toString = function () {
  1781. return _data4.toString();
  1782. };
  1783. return data;
  1784. }(function (data) {
  1785. this.sendDataToTokenStreamParser(data);
  1786. }),
  1787. message: function message() {
  1788. if (this.ntlmpacket) {
  1789. const authentication = this.config.authentication;
  1790. const payload = new _ntlmPayload.default({
  1791. domain: authentication.options.domain,
  1792. userName: authentication.options.userName,
  1793. password: authentication.options.password,
  1794. ntlmpacket: this.ntlmpacket
  1795. });
  1796. this.messageIo.sendMessage(_packet.TYPE.NTLMAUTH_PKT, payload.data);
  1797. this.debug.payload(function () {
  1798. return payload.toString(' ');
  1799. });
  1800. this.ntlmpacket = undefined;
  1801. } else if (this.loggedIn) {
  1802. this.transitionTo(this.STATE.LOGGED_IN_SENDING_INITIAL_SQL);
  1803. } else if (this.loginError) {
  1804. if (this.loginError.isTransient) {
  1805. this.debug.log('Initiating retry on transient error');
  1806. this.transitionTo(this.STATE.TRANSIENT_FAILURE_RETRY);
  1807. } else {
  1808. this.emit('connect', this.loginError);
  1809. this.transitionTo(this.STATE.FINAL);
  1810. }
  1811. } else {
  1812. this.emit('connect', (0, _errors.ConnectionError)('Login failed.', 'ELOGIN'));
  1813. this.transitionTo(this.STATE.FINAL);
  1814. }
  1815. }
  1816. }
  1817. },
  1818. SENT_LOGIN7_WITH_FEDAUTH: {
  1819. name: 'SentLogin7Withfedauth',
  1820. events: {
  1821. socketError: function socketError() {
  1822. this.transitionTo(this.STATE.FINAL);
  1823. },
  1824. connectTimeout: function connectTimeout() {
  1825. this.transitionTo(this.STATE.FINAL);
  1826. },
  1827. data: function (_data5) {
  1828. function data(_x5) {
  1829. return _data5.apply(this, arguments);
  1830. }
  1831. data.toString = function () {
  1832. return _data5.toString();
  1833. };
  1834. return data;
  1835. }(function (data) {
  1836. this.sendDataToTokenStreamParser(data);
  1837. }),
  1838. routingChange: function routingChange() {
  1839. this.transitionTo(this.STATE.REROUTING);
  1840. },
  1841. fedAuthInfo: function fedAuthInfo(token) {
  1842. this.fedAuthInfoToken = token;
  1843. },
  1844. message: function message() {
  1845. const fedAuthInfoToken = this.fedAuthInfoToken;
  1846. if (fedAuthInfoToken && fedAuthInfoToken.stsurl && fedAuthInfoToken.spn) {
  1847. const authentication = this.config.authentication;
  1848. const getToken = callback => {
  1849. const getTokenFromCredentials = (err, credentials) => {
  1850. if (err) {
  1851. return callback(err);
  1852. }
  1853. credentials.getToken().then(tokenResponse => {
  1854. callback(null, tokenResponse.accessToken);
  1855. }, callback);
  1856. };
  1857. if (authentication.type === 'azure-active-directory-password') {
  1858. (0, _msRestNodeauth.loginWithUsernamePassword)(authentication.options.userName, authentication.options.password, {
  1859. clientId: '7f98cb04-cd1e-40df-9140-3bf7e2cea4db',
  1860. tokenAudience: fedAuthInfoToken.spn
  1861. }, getTokenFromCredentials);
  1862. } else if (authentication.type === 'azure-active-directory-msi-vm') {
  1863. (0, _msRestNodeauth.loginWithVmMSI)({
  1864. clientId: authentication.options.clientId,
  1865. msiEndpoint: authentication.options.msiEndpoint,
  1866. resource: fedAuthInfoToken.spn
  1867. }, getTokenFromCredentials);
  1868. } else if (authentication.type === 'azure-active-directory-msi-app-service') {
  1869. (0, _msRestNodeauth.loginWithAppServiceMSI)({
  1870. msiEndpoint: authentication.options.msiEndpoint,
  1871. msiSecret: authentication.options.msiSecret,
  1872. resource: fedAuthInfoToken.spn
  1873. }, getTokenFromCredentials);
  1874. } else if (authentication.type === 'azure-active-directory-service-principal-secret') {
  1875. (0, _msRestNodeauth.loginWithServicePrincipalSecret)(authentication.options.clientId, authentication.options.clientSecret, authentication.options.tenantId, {
  1876. tokenAudience: fedAuthInfoToken.spn
  1877. }, getTokenFromCredentials);
  1878. }
  1879. };
  1880. getToken((err, token) => {
  1881. if (err) {
  1882. this.loginError = (0, _errors.ConnectionError)('Security token could not be authenticated or authorized.', 'EFEDAUTH');
  1883. this.emit('connect', this.loginError);
  1884. this.transitionTo(this.STATE.FINAL);
  1885. return;
  1886. }
  1887. this.sendFedAuthTokenMessage(token);
  1888. });
  1889. } else if (this.loginError) {
  1890. if (this.loginError.isTransient) {
  1891. this.debug.log('Initiating retry on transient error');
  1892. this.transitionTo(this.STATE.TRANSIENT_FAILURE_RETRY);
  1893. } else {
  1894. this.emit('connect', this.loginError);
  1895. this.transitionTo(this.STATE.FINAL);
  1896. }
  1897. } else {
  1898. this.emit('connect', (0, _errors.ConnectionError)('Login failed.', 'ELOGIN'));
  1899. this.transitionTo(this.STATE.FINAL);
  1900. }
  1901. }
  1902. }
  1903. },
  1904. LOGGED_IN_SENDING_INITIAL_SQL: {
  1905. name: 'LoggedInSendingInitialSql',
  1906. enter: function enter() {
  1907. this.sendInitialSql();
  1908. },
  1909. events: {
  1910. socketError: function socketError() {
  1911. this.transitionTo(this.STATE.FINAL);
  1912. },
  1913. connectTimeout: function connectTimeout() {
  1914. this.transitionTo(this.STATE.FINAL);
  1915. },
  1916. data: function (_data6) {
  1917. function data(_x6) {
  1918. return _data6.apply(this, arguments);
  1919. }
  1920. data.toString = function () {
  1921. return _data6.toString();
  1922. };
  1923. return data;
  1924. }(function (data) {
  1925. this.sendDataToTokenStreamParser(data);
  1926. }),
  1927. message: function message() {
  1928. this.transitionTo(this.STATE.LOGGED_IN);
  1929. this.processedInitialSql();
  1930. }
  1931. }
  1932. },
  1933. LOGGED_IN: {
  1934. name: 'LoggedIn',
  1935. events: {
  1936. socketError: function socketError() {
  1937. this.transitionTo(this.STATE.FINAL);
  1938. }
  1939. }
  1940. },
  1941. BUILDING_CLIENT_REQUEST: {
  1942. name: 'BuildingClientRequest',
  1943. events: {
  1944. socketError: function socketError(err) {
  1945. const sqlRequest = this.request;
  1946. this.request = undefined;
  1947. this.transitionTo(this.STATE.FINAL);
  1948. sqlRequest.callback(err);
  1949. }
  1950. }
  1951. },
  1952. SENT_CLIENT_REQUEST: {
  1953. name: 'SentClientRequest',
  1954. exit: function exit(nextState) {
  1955. this.clearRequestTimer();
  1956. if (nextState !== this.STATE.FINAL) {
  1957. this.tokenStreamParser.resume();
  1958. }
  1959. },
  1960. events: {
  1961. socketError: function socketError(err) {
  1962. const sqlRequest = this.request;
  1963. this.request = undefined;
  1964. this.transitionTo(this.STATE.FINAL);
  1965. sqlRequest.callback(err);
  1966. },
  1967. data: function (_data7) {
  1968. function data(_x7) {
  1969. return _data7.apply(this, arguments);
  1970. }
  1971. data.toString = function () {
  1972. return _data7.toString();
  1973. };
  1974. return data;
  1975. }(function (data) {
  1976. this.clearRequestTimer(); // request timer is stopped on first data package
  1977. const ret = this.sendDataToTokenStreamParser(data);
  1978. if (ret === false) {
  1979. // Bridge backpressure from the token stream parser transform to the
  1980. // packet stream transform.
  1981. this.messageIo.pause();
  1982. }
  1983. }),
  1984. message: function message() {
  1985. // We have to channel the 'message' (EOM) event through the token stream
  1986. // parser transform, to keep it in line with the flow of the tokens, when
  1987. // the incoming data flow is paused and resumed.
  1988. this.tokenStreamParser.addEndOfMessageMarker();
  1989. },
  1990. endOfMessageMarkerReceived: function endOfMessageMarkerReceived() {
  1991. this.transitionTo(this.STATE.LOGGED_IN);
  1992. const sqlRequest = this.request;
  1993. this.request = undefined;
  1994. if (this.config.options.tdsVersion < '7_2' && sqlRequest.error && this.isSqlBatch) {
  1995. this.inTransaction = false;
  1996. }
  1997. sqlRequest.callback(sqlRequest.error, sqlRequest.rowCount, sqlRequest.rows);
  1998. }
  1999. }
  2000. },
  2001. SENT_ATTENTION: {
  2002. name: 'SentAttention',
  2003. enter: function enter() {
  2004. this.attentionReceived = false;
  2005. },
  2006. events: {
  2007. socketError: function socketError(err) {
  2008. const sqlRequest = this.request;
  2009. this.request = undefined;
  2010. this.transitionTo(this.STATE.FINAL);
  2011. sqlRequest.callback(err);
  2012. },
  2013. data: function (_data8) {
  2014. function data(_x8) {
  2015. return _data8.apply(this, arguments);
  2016. }
  2017. data.toString = function () {
  2018. return _data8.toString();
  2019. };
  2020. return data;
  2021. }(function (data) {
  2022. this.sendDataToTokenStreamParser(data);
  2023. }),
  2024. attention: function attention() {
  2025. this.attentionReceived = true;
  2026. },
  2027. message: function message() {
  2028. // 3.2.5.7 Sent Attention State
  2029. // Discard any data contained in the response, until we receive the attention response
  2030. if (this.attentionReceived) {
  2031. this.clearCancelTimer();
  2032. const sqlRequest = this.request;
  2033. this.request = undefined;
  2034. this.transitionTo(this.STATE.LOGGED_IN);
  2035. if (sqlRequest.error && sqlRequest.error instanceof _errors.RequestError && sqlRequest.error.code === 'ETIMEOUT') {
  2036. sqlRequest.callback(sqlRequest.error);
  2037. } else {
  2038. sqlRequest.callback((0, _errors.RequestError)('Canceled.', 'ECANCEL'));
  2039. }
  2040. }
  2041. }
  2042. }
  2043. },
  2044. FINAL: {
  2045. name: 'Final',
  2046. enter: function enter() {
  2047. this.cleanupConnection(CLEANUP_TYPE.NORMAL);
  2048. },
  2049. events: {
  2050. loginFailed: function loginFailed() {// Do nothing. The connection was probably closed by the client code.
  2051. },
  2052. connectTimeout: function connectTimeout() {// Do nothing, as the timer should be cleaned up.
  2053. },
  2054. message: function message() {// Do nothing
  2055. },
  2056. socketError: function socketError() {// Do nothing
  2057. }
  2058. }
  2059. }
  2060. };