├── .gitignore ├── lib ├── bin │ ├── 0.10-x64 │ │ └── sqlserver.node │ ├── 0.10-x86 │ │ └── sqlserver.node │ ├── 0.8-x64 │ │ └── sqlserver.node │ └── 0.8-x86 │ │ └── sqlserver.node ├── sqlserver.native.js └── sql.js ├── test ├── package.json └── server.js ├── package.json ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | *~ 3 | *.swp 4 | -------------------------------------------------------------------------------- /lib/bin/0.10-x64/sqlserver.node: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jorgeazevedo/node-sqlserver-unofficial/HEAD/lib/bin/0.10-x64/sqlserver.node -------------------------------------------------------------------------------- /lib/bin/0.10-x86/sqlserver.node: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jorgeazevedo/node-sqlserver-unofficial/HEAD/lib/bin/0.10-x86/sqlserver.node -------------------------------------------------------------------------------- /lib/bin/0.8-x64/sqlserver.node: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jorgeazevedo/node-sqlserver-unofficial/HEAD/lib/bin/0.8-x64/sqlserver.node -------------------------------------------------------------------------------- /lib/bin/0.8-x86/sqlserver.node: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jorgeazevedo/node-sqlserver-unofficial/HEAD/lib/bin/0.8-x86/sqlserver.node -------------------------------------------------------------------------------- /test/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "SanityTest", 3 | "version": "1.1.0", 4 | "engines": {"node": "0.10.25"}, 5 | "dependencies": {"node-sqlserver-unofficial": "*"} 6 | } 7 | -------------------------------------------------------------------------------- /test/server.js: -------------------------------------------------------------------------------- 1 | var sql = require('..'); 2 | var connectionString = ""; 3 | var testQuery = "SELECT 1"; 4 | 5 | if(!connectionString) { 6 | console.log("This script cannot run without a connection string"); 7 | return; 8 | } 9 | 10 | var http = require('http'); 11 | var port = process.env.PORT || 1337; 12 | var httpServer = http.createServer(function (req, res) { 13 | res.writeHead(200, {'Content-Type': 'text/plain'}); 14 | res.write("node " + process.version + " " + process.arch + ".\n"); 15 | 16 | sql.query(connectionString, testQuery, function(err, result) { 17 | if(err) 18 | res.end("Query Failed \n" + err); 19 | else 20 | res.end("Query result: " + result[0]['Column0'] + " \n"); 21 | }); 22 | }); 23 | 24 | httpServer.listen(port); 25 | console.log('Server running at localhost:'+port); 26 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-sqlserver-unofficial", 3 | "description": "Unofficial binary distribution of the msnodesql package.", 4 | "author": "Jorge Azevedo", 5 | "version": "1.4.0", 6 | "keywords": ["sql", "database", "mssql", "azure", "sqlserver", "tds", "microsoft", "msnodesql", "node-sqlserver"], 7 | "repository" : { 8 | "type" : "git", 9 | "url" : "https://github.com/jorgeazevedo/node-sqlserver-unofficial.git" 10 | }, 11 | "bugs" : { 12 | "url" : "https://github.com/jorgeazevedo/node-sqlserver-unofficial/issues" 13 | }, 14 | "licenses" : [ 15 | { 16 | "type" : "MIT", 17 | "url" : "https://github.com/jorgeazevedo/node-sqlserver-unofficial/raw/master/LICENSE" 18 | } 19 | ], 20 | "main": "./lib/sql.js", 21 | "engines": { 22 | "node": ">=0.8" 23 | }, 24 | "dependencies": {}, 25 | "devDependencies": {}, 26 | "os" : [ "win32" ] 27 | } 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013-2014 Jorge Azevedo 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following 10 | conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /lib/sqlserver.native.js: -------------------------------------------------------------------------------- 1 | //--------------------------------------------------------------------------------------------------------------------------------- 2 | // File: sqlserver.native.js 3 | // Contents: javascript which loads the native part of the Microsoft Driver for Node.js for SQL Server 4 | // 5 | // Copyright Microsoft Corporation and contributors 6 | // 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // you may not use this file except in compliance with the License. 9 | // 10 | // You may obtain a copy of the License at: 11 | // http://www.apache.org/licenses/LICENSE-2.0 12 | // 13 | // Unless required by applicable law or agreed to in writing, software 14 | // distributed under the License is distributed on an "AS IS" BASIS, 15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | // See the License for the specific language governing permissions and 17 | // limitations under the License. 18 | //--------------------------------------------------------------------------------------------------------------------------------- 19 | 20 | var binaryDir= __dirname + '/bin/'; 21 | 22 | files = require('fs').readdirSync(binaryDir); 23 | 24 | files.forEach(function(file){ 25 | if(noBinaryExported()) 26 | attemptToExportBinary(file); 27 | }); 28 | 29 | failIfNoBinaryExported(); 30 | 31 | // If the require fails, we can just ignore the exception and continue trying 32 | function attemptToExportBinary(filename) { 33 | try{ 34 | module.exports = require(binaryDir + filename + '/sqlserver.node'); 35 | } catch(e) { 36 | } 37 | } 38 | 39 | function failIfNoBinaryExported() { 40 | if(noBinaryExported()) 41 | throw new Error('None of the binaries loaded successfully. Is your node version either 0.8 or 0.10?'); 42 | } 43 | 44 | function noBinaryExported() { 45 | return ! module.exports.hasOwnProperty('Connection'); 46 | } 47 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Unofficial binary distribution of node-sqlserver 2 | 3 | [node-sqlserver](https://github.com/WindowsAzure/node-sqlserver) is a C++ 4 | Node.js module used to connect to MS SQL and Azure SQL databases developed by 5 | Microsoft. It can be found on `npm` under the name 6 | [msnodesql](https://www.npmjs.org/package/msnodesql). 7 | 8 | This is an unofficial binary distribution of that driver. Here's why you'd want 9 | to use it instead of the official one: 10 | 11 | * No need to compile from source (which requires Visual Studio and totally 12 | [confuses](https://github.com/WindowsAzure/node-sqlserver/issues/155) 13 | [people](https://github.com/WindowsAzure/node-sqlserver/issues/143)). 14 | * It runs on both x86 and x64 and with node versions 0.8 and 0.10. 15 | * No [weird 16 | workarounds](http://geekswithblogs.net/shaunxu/archive/2012/11/16/install-npm-packages-automatically-for-node.js-on-windows-azure-web.aspx) 17 | needed to run on Azure web sites. 18 | 19 | Use it on your projects via `npm` 20 | 21 | $ npm install node-sqlserver-unofficial 22 | 23 | ## Dependencies 24 | 25 | To try this out locally on your machine, you'll need 26 | 27 | * Node.JS Runtime 0.10.x or 0.8.x ([Azure 28 | Websites](http://www.windowsazure.com/en-us/documentation/articles/nodejs-specify-node-version-windows-azure-apps/) 29 | support versions [0.10.5](http://nodejs.org/dist/v0.10.5/) and 30 | [0.8.19](http://nodejs.org/dist/v0.8.19/)) 31 | * Microsoft SQL Server 2012 Native Client available in the [SQL Server 2012 32 | Feature Pack](http://www.microsoft.com/en-us/download/details.aspx?id=29065). 33 | 34 | ## Testing 35 | 36 | `test/` is a deployable Azure website that queries an Azure SQL 37 | database and displays the result like so 38 | 39 | node v0.10.25 ia32. 40 | Query result - 1 41 | 42 | Or, in case something goes wrong, an error message like so 43 | 44 | node v0.10.25 ia32. 45 | Query Failed 46 | Error: [Microsoft][SQL Server Native Client 11.0][SQL Server]Incorrect syntax near 'SELECT'. 47 | 48 | The environment is specified in `package.json` and `server.js` contains the code. 49 | 50 | Before running this, `connectionString` in `server.js` must be set to your 51 | SQL Azure login credentials. An example would be 52 | 53 | var connectionString = "Driver={SQL Server Native Client 11.0};Server=tcp:?.database.windows.net,1433;Database=?;Uid=?;Pwd=?"; 54 | 55 | I also recommend to run it locally before deploying it to Azure. Running 56 | 57 | $ npm install 58 | 59 | in `test/` will resolve the dependencies to `test/node_modules/`, after which running 60 | 61 | $ node server.js 62 | 63 | and accessing `http://localhost:1337` will display the result. 64 | 65 | ## Copyright and license 66 | 67 | This derivative work is hereby released under the MIT license, as made possible by the 68 | terms of the Apache 2.0 license of the original node-sqlserver. 69 | 70 | Terms available for review in LICENSE. 71 | 72 | This work is not affiliate with or endorsed by Microsoft in any way. 73 | -------------------------------------------------------------------------------- /lib/sql.js: -------------------------------------------------------------------------------- 1 | //--------------------------------------------------------------------------------------------------------------------------------- 2 | // File: sql.js 3 | // Contents: javascript interface to Microsoft Driver for Node.js for SQL Server 4 | // 5 | // Copyright Microsoft Corporation and contributors 6 | // 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // you may not use this file except in compliance with the License. 9 | // 10 | // You may obtain a copy of the License at: 11 | // http://www.apache.org/licenses/LICENSE-2.0 12 | // 13 | // Unless required by applicable law or agreed to in writing, software 14 | // distributed under the License is distributed on an "AS IS" BASIS, 15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | // See the License for the specific language governing permissions and 17 | // limitations under the License. 18 | //--------------------------------------------------------------------------------------------------------------------------------- 19 | 20 | var sql = require('./sqlserver.native'); 21 | var events = require('events'); 22 | var util = require('util'); 23 | 24 | function StreamEvents() { 25 | events.EventEmitter.call(this); 26 | } 27 | util.inherits(StreamEvents, events.EventEmitter); 28 | 29 | function routeStatementError(err, callback, notify) { 30 | 31 | if (callback) { 32 | callback(err); 33 | } 34 | else if (notify && notify.listeners('error').length > 0) { 35 | notify.emit('error', err); 36 | } 37 | else { 38 | throw new Error(err); 39 | } 40 | } 41 | 42 | function nextOp( q ) { 43 | 44 | q.shift(); 45 | 46 | if( q.length != 0 ) { 47 | 48 | var op = q[0]; 49 | 50 | op.fn.apply( op.fn, op.args ); 51 | } 52 | } 53 | 54 | function validateParameters( parameters, funcName ) { 55 | 56 | for( var p in parameters ) { 57 | 58 | if( typeof parameters[p].value != parameters[p].type ) { 59 | 60 | throw new Error( ["[msnodesql] Invalid ", parameters[p].name, " passed to function ", funcName, ". Type should be ", parameters[p].type, "." ].join('') ); 61 | } 62 | } 63 | } 64 | 65 | function query_internal(ext, query, params, callback) { 66 | 67 | function onQuery(err, results) { 68 | 69 | if( callback ) { 70 | callback(err, results); 71 | } 72 | } 73 | 74 | return ext.query(query, params, onQuery); 75 | } 76 | 77 | 78 | function getChunkyArgs(paramsOrCallback, callback) { 79 | 80 | if(( typeof paramsOrCallback == 'object' && Array.isArray( paramsOrCallback ) == true ) && 81 | typeof callback == 'function' ) { 82 | 83 | return { params: paramsOrCallback, callback: callback }; 84 | } 85 | 86 | if( paramsOrCallback == null && typeof callback == 'function' ) { 87 | 88 | return { params: [], callback: callback }; 89 | } 90 | 91 | if( typeof paramsOrCallback == 'function' && typeof callback == 'undefined' ) { 92 | 93 | return { params: [], callback: paramsOrCallback }; 94 | } 95 | 96 | if(( typeof paramsOrCallback == 'object' && Array.isArray( paramsOrCallback ) == true ) && 97 | typeof callback == 'undefined' ) { 98 | 99 | return { params: paramsOrCallback, callback: null }; 100 | } 101 | 102 | if(( paramsOrCallback == null || typeof paramsOrCallback == 'undefined' ) && typeof callback == 'undefined' ) { 103 | 104 | return { params: [], callback: null }; 105 | } 106 | 107 | throw new Error( "[msnodesql] Invalid parameter(s) passed to function query or queryRaw." ); 108 | } 109 | 110 | function objectify(results) { 111 | 112 | var names = {}; 113 | var name, idx; 114 | 115 | for (idx in results.meta) { 116 | var meta = results.meta[idx]; 117 | name = meta.name; 118 | if (name !== '' && names[name] === undefined) { 119 | names[name] = idx; 120 | } 121 | else { 122 | var extra = 0; 123 | var candidate = 'Column' + idx; 124 | while (names[candidate] !== undefined) { 125 | candidate = 'Column' + idx + '_' + extra++; 126 | } 127 | names[candidate] = idx; 128 | } 129 | } 130 | 131 | var rows = []; 132 | for (idx in results.rows) { 133 | var row = results.rows[idx]; 134 | var value = {}; 135 | for (name in names) { 136 | value[name] = row[names[name]]; 137 | } 138 | rows.push(value); 139 | } 140 | 141 | return rows; 142 | } 143 | 144 | // TODO: Simplify this to use only events, and then subscribe in Connection.query 145 | // and Connection.queryRaw to build callback results 146 | function readall(q, notify, ext, query, params, callback) { 147 | 148 | 149 | var meta; 150 | var column; 151 | var rows = []; 152 | var rowindex = 0; 153 | 154 | function onReadColumnMore( err, results ) { 155 | 156 | if (err) { 157 | routeStatementError(err, callback, notify); 158 | nextOp( q ); 159 | return; 160 | } 161 | 162 | var data = results.data; 163 | var more = results.more; 164 | 165 | notify.emit('column', column, data, more); 166 | 167 | if (callback) { 168 | rows[rows.length - 1][column] += data; 169 | } 170 | 171 | if (more) { 172 | ext.readColumn(column, onReadColumnMore); 173 | return; 174 | } 175 | 176 | column++; 177 | if (column >= meta.length) { 178 | ext.readRow(onReadRow); 179 | return; 180 | } 181 | 182 | ext.readColumn(column, onReadColumn); 183 | } 184 | 185 | function onReadColumn( err, results ) { 186 | 187 | if (err) { 188 | routeStatementError(err, callback, notify); 189 | nextOp(q); 190 | return; 191 | } 192 | 193 | var data = results.data; 194 | var more = results.more; 195 | 196 | notify.emit('column', column, data, more); 197 | 198 | if (callback) { 199 | rows[rows.length - 1][column] = data; 200 | } 201 | 202 | if (more) { 203 | ext.readColumn(column, onReadColumnMore); 204 | return; 205 | } 206 | 207 | column++; 208 | 209 | if (column >= meta.length) { 210 | ext.readRow(onReadRow); 211 | return; 212 | } 213 | 214 | ext.readColumn(column, onReadColumn); 215 | } 216 | 217 | function rowsCompleted( results, more ) { 218 | 219 | if( !more ) { 220 | notify.emit('done'); 221 | } 222 | 223 | if (callback) { 224 | callback( null, results, more ); 225 | } 226 | } 227 | 228 | function rowsAffected( moreResults ) { 229 | 230 | var rowCount = ext.readRowCount(); 231 | 232 | notify.emit('rowcount', rowCount ); 233 | 234 | rowsCompleted( { meta: null, rowcount: rowCount }, moreResults ); 235 | } 236 | 237 | function onNextResult( err, nextResultSetInfo ) { 238 | 239 | if( err ) { 240 | 241 | routeStatementError( err, callback, notify ); 242 | nextOp( q ); 243 | return; 244 | } 245 | 246 | // handle the just finished result reading 247 | if( meta.length == 0 ) { 248 | // if there was no metadata, then pass the row count (rows affected) 249 | rowsAffected( !nextResultSetInfo.endOfResults ); 250 | } 251 | else { 252 | // otherwise, pass the accumulated results 253 | rowsCompleted( { meta: meta, rows: rows }, !nextResultSetInfo.endOfResults ); 254 | } 255 | 256 | // reset for the next resultset 257 | meta = nextResultSetInfo.meta; 258 | rows = []; 259 | 260 | if( nextResultSetInfo.endOfResults ) { 261 | 262 | // TODO: What about closed connections due to more being false in the callback? See queryRaw below. 263 | nextOp( q ); 264 | } 265 | else { 266 | 267 | // if this is just a set of rows 268 | if( meta.length > 0 ) { 269 | notify.emit( 'meta', meta ); 270 | 271 | // kick off reading next set of rows 272 | ext.readRow( onReadRow ); 273 | } 274 | else { 275 | 276 | ext.nextResult( onNextResult ); 277 | } 278 | } 279 | } 280 | 281 | function onReadRow( err, endOfRows ) { 282 | 283 | if (err) { 284 | routeStatementError(err, callback, notify); 285 | nextOp(q); 286 | return; 287 | } 288 | // if there were rows and we haven't reached the end yet (like EOF) 289 | else if (meta.length > 0 && !endOfRows) { 290 | 291 | notify.emit('row', rowindex++); 292 | 293 | column = 0; 294 | if (callback) { 295 | rows[rows.length] = []; 296 | } 297 | 298 | ext.readColumn(column, onReadColumn); 299 | } 300 | // otherwise, go to the next result set 301 | else { 302 | 303 | ext.nextResult( onNextResult ); 304 | } 305 | } 306 | 307 | query_internal(ext, query, params, function (err, results) { 308 | 309 | if (err) { 310 | routeStatementError(err, callback, notify); 311 | nextOp(q); 312 | return; 313 | } 314 | 315 | meta = results; 316 | if (meta.length > 0) { 317 | 318 | notify.emit('meta', meta); 319 | ext.readRow( onReadRow ); 320 | } 321 | else { 322 | 323 | ext.nextResult( onNextResult ) 324 | } 325 | }); 326 | } 327 | 328 | function open(connectionString, callback) { 329 | 330 | validateParameters( [ { type: 'string', value: connectionString, name: 'connection string' }, 331 | { type: 'function', value: callback, name: 'callback' }], 'open' ); 332 | 333 | var ext = new sql.Connection(); 334 | 335 | var q = []; 336 | 337 | function defaultCallback( err ) { 338 | 339 | if( err ) { 340 | throw new Error( err ); 341 | } 342 | } 343 | 344 | function Connection() { 345 | 346 | this.close = function (callback) { 347 | 348 | function onClose( err ) { 349 | 350 | callback( err ); 351 | } 352 | 353 | callback = callback || defaultCallback; 354 | 355 | ext.close( onClose ); 356 | } 357 | 358 | this.queryRaw = function (query, paramsOrCallback, callback) { 359 | 360 | validateParameters( [ { type: 'string', value: query, name: 'query string' }], 'queryRaw' ); 361 | 362 | var notify = new StreamEvents(); 363 | 364 | var chunky = getChunkyArgs(paramsOrCallback, callback); 365 | 366 | var op = { fn: readall, args: [ q, notify, ext, query, chunky.params, chunky.callback ] }; 367 | q.push( op ); 368 | 369 | if( q.length == 1 ) { 370 | 371 | readall( q, notify, ext, query, chunky.params, chunky.callback ); 372 | } 373 | 374 | return notify; 375 | } 376 | 377 | this.query = function (query, paramsOrCallback, callback) { 378 | 379 | validateParameters( [ { type: 'string', value: query, name: 'query string' }], 'query' ); 380 | 381 | var chunky = getChunkyArgs(paramsOrCallback, callback); 382 | 383 | function onQueryRaw( err, results, more ) { 384 | 385 | if (chunky.callback) { 386 | if (err) chunky.callback(err); 387 | else chunky.callback(err, objectify(results), more); 388 | } 389 | } 390 | 391 | return this.queryRaw(query, chunky.params, onQueryRaw); 392 | } 393 | 394 | this.beginTransaction = function(callback) { 395 | 396 | function onBeginTxn( err ) { 397 | 398 | callback( err ); 399 | 400 | nextOp( q ); 401 | } 402 | 403 | callback = callback || defaultCallback; 404 | 405 | var op = { fn: function( callback ) { ext.beginTransaction( callback ) }, args: [ onBeginTxn ] }; 406 | q.push( op ); 407 | 408 | if( q.length == 1 ) { 409 | 410 | ext.beginTransaction( onBeginTxn ); 411 | } 412 | } 413 | 414 | this.commit = function (callback) { 415 | 416 | function onCommit( err ) { 417 | 418 | callback( err ); 419 | 420 | nextOp(q); 421 | } 422 | 423 | callback = callback || defaultCallback; 424 | 425 | var op = { fn: function (callback) { ext.commit(callback); }, args: [onCommit] }; 426 | q.push(op); 427 | 428 | if (q.length == 1) { 429 | 430 | ext.commit(onCommit); 431 | } 432 | } 433 | 434 | this.rollback = function(callback) { 435 | 436 | function onRollback( err ) { 437 | 438 | callback( err ); 439 | 440 | nextOp( q ); 441 | } 442 | 443 | callback = callback || defaultCallback; 444 | 445 | var op = { fn: function( callback ) { ext.rollback( callback ); }, args: [ onRollback ] }; 446 | q.push( op ); 447 | 448 | if( q.length == 1 ) { 449 | 450 | ext.rollback( onRollback ); 451 | } 452 | } 453 | } 454 | 455 | var connection = new Connection(); 456 | 457 | function onOpen( err ) { 458 | 459 | callback( err, connection ); 460 | } 461 | 462 | callback = callback || defaultCallback; 463 | 464 | ext.open(connectionString, onOpen); 465 | 466 | return connection; 467 | } 468 | 469 | function query(connectionString, query, paramsOrCallback, callback) { 470 | 471 | validateParameters( [ { type: 'string', value: connectionString, name: 'connection string' }, 472 | { type: 'string', value: query, name: 'query string' }], 'query' ); 473 | 474 | var chunky = getChunkyArgs(paramsOrCallback, callback); 475 | 476 | return queryRaw(connectionString, query, chunky.params, function (err, results, more) { 477 | if (chunky.callback) { 478 | if (err) chunky.callback(err); 479 | else chunky.callback(err, objectify(results), more); 480 | } 481 | }); 482 | } 483 | 484 | function queryRaw(connectionString, query, paramsOrCallback, callback) { 485 | 486 | validateParameters( [ { type: 'string', value: connectionString, name: 'connection string' }, 487 | { type: 'string', value: query, name: 'query string' }], 'queryRaw' ); 488 | 489 | var ext = new sql.Connection(); 490 | var notify = new StreamEvents(); 491 | var q = []; 492 | 493 | var chunky = getChunkyArgs(paramsOrCallback, callback); 494 | 495 | chunky.callback = chunky.callback || function( err ) { if( err ) { throw new Error( err ); } }; 496 | 497 | function onOpen( err, connection ) { 498 | 499 | if( err ) { 500 | chunky.callback( err ); 501 | return; 502 | } 503 | 504 | readall(q, notify, ext, query, chunky.params, function (err, results, more) { 505 | 506 | if (err) { 507 | routeStatementError(err, chunky.callback, notify); 508 | return; 509 | } 510 | 511 | if( chunky.callback ) { 512 | chunky.callback( err, results, more ); 513 | } 514 | 515 | if( !more ) { 516 | ext.close(); 517 | } 518 | }); 519 | 520 | } 521 | 522 | ext.open(connectionString, onOpen); 523 | 524 | return notify; 525 | } 526 | 527 | exports.open = open; 528 | exports.query = query; 529 | exports.queryRaw = queryRaw; 530 | --------------------------------------------------------------------------------