From fb6bf25062bbe257ae66c2d5cce9a4e1e4130964 Mon Sep 17 00:00:00 2001 From: "Timothy J. Warren" Date: Fri, 31 Oct 2014 11:55:26 -0400 Subject: [PATCH] Add modules for sqlite and firebird --- node_modules/dblite/.npmignore | 10 + node_modules/dblite/LICENSE.txt | 19 + node_modules/dblite/README.md | 413 +++ node_modules/dblite/package.json | 60 + node_modules/node-firebird/.npmignore | 2 + node_modules/node-firebird/LICENSE | 373 +++ node_modules/node-firebird/README.md | 360 +++ node_modules/node-firebird/lib/firebird.msg | Bin 0 -> 148556 bytes node_modules/node-firebird/lib/index.js | 2716 +++++++++++++++++++ node_modules/node-firebird/lib/long.js | 855 ++++++ node_modules/node-firebird/lib/messages.js | 162 ++ node_modules/node-firebird/lib/serialize.js | 361 +++ node_modules/node-firebird/package.json | 70 + node_modules/node-firebird/test/image.png | Bin 0 -> 5472 bytes node_modules/node-firebird/test/run.js | 441 +++ 15 files changed, 5842 insertions(+) create mode 100644 node_modules/dblite/.npmignore create mode 100644 node_modules/dblite/LICENSE.txt create mode 100644 node_modules/dblite/README.md create mode 100644 node_modules/dblite/package.json create mode 100644 node_modules/node-firebird/.npmignore create mode 100644 node_modules/node-firebird/LICENSE create mode 100644 node_modules/node-firebird/README.md create mode 100644 node_modules/node-firebird/lib/firebird.msg create mode 100644 node_modules/node-firebird/lib/index.js create mode 100644 node_modules/node-firebird/lib/long.js create mode 100644 node_modules/node-firebird/lib/messages.js create mode 100644 node_modules/node-firebird/lib/serialize.js create mode 100644 node_modules/node-firebird/package.json create mode 100644 node_modules/node-firebird/test/image.png create mode 100644 node_modules/node-firebird/test/run.js diff --git a/node_modules/dblite/.npmignore b/node_modules/dblite/.npmignore new file mode 100644 index 0000000..b361e47 --- /dev/null +++ b/node_modules/dblite/.npmignore @@ -0,0 +1,10 @@ +src/* +test/* +benchmark/* +template/* +node_modules/* +build/*.amd.js +Makefile +index.html +.gitignore +.travis.yml \ No newline at end of file diff --git a/node_modules/dblite/LICENSE.txt b/node_modules/dblite/LICENSE.txt new file mode 100644 index 0000000..468a071 --- /dev/null +++ b/node_modules/dblite/LICENSE.txt @@ -0,0 +1,19 @@ +Copyright (C) 2013 by WebReflection + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/node_modules/dblite/README.md b/node_modules/dblite/README.md new file mode 100644 index 0000000..9f84ae0 --- /dev/null +++ b/node_modules/dblite/README.md @@ -0,0 +1,413 @@ +dblite +====== +a zero hassle wrapper for sqlite +```javascript +var dblite = require('dblite'), + db = dblite('file.name'); + +// Asynchronous, fast, and ... +db.query('SELECT * FROM table', function(err, rows) { + // ... that easy! +}); +``` +More in [the related blogpost](http://webreflection.blogspot.com/2013/07/dblite-sqlite3-for-nodejs-made-easy.html) and here too :-) + +[![build status](https://secure.travis-ci.org/WebReflection/dblite.png)](http://travis-ci.org/WebReflection/dblite) + +[![NPM](https://nodei.co/npm/dblite.png?downloads=true)](https://nodei.co/npm/dblite/) + + +### Important +Starting from **sqlite3** version `3.8.6` you need a "_new line agnostic_" version of `dblite`, right now represented by the latest version `0.6.0`. This **will break** compatibility with older version of the database cli. + + +### The What And The Why +I've created `dblite` module because there's still not a simple and straight forward or standard way to have [sqlite](http://www.sqlite.org) in [node.js](http://nodejs.org) without requiring to re-compile, re-build, download sources a part or install dependencies instead of simply `apt-get install sqlite3` or `pacman -S sqlite3` in your \*nix system. + +`dblite` has been created with portability, simplicity, and reasonable performance for **embedded Hardware** such [Raspberry Pi](http://www.raspberrypi.org) and [Cubieboard](http://cubieboard.org) in mind. + +Generally speaking all linux based distributions like [Arch Linux](https://www.archlinux.org), where is not always that easy to `node-gyp` a module and add dependencies that work, can now use this battle tested wrap and perform basic to advanced sqlite operations. + + +### Bootstrap +To install dblite simply `npm install dblite` then in node: +```javascript +var dblite = require('dblite'), + db = dblite('/folder/to/file.sqlite'); + +// ready to go, i.e. +db.query('.databases'); +db.query( + 'SELECT * FROM users WHERE pass = ?', + [pass], + function (err, rows) { + var user = rows.length && rows[0]; + } +); +``` +By default the `dblite` function uses **sqlite3 as executable**. If you need to change the path simply update `dblite.bin = "/usr/local/bin/sqlite3";` before invoking the function. + + +### API +Right now a created `EventEmitter` `db` instance has 3 extra methods: `.query()`, `.lastRowID()`, and `.close()`. + +The `.lastRowID(table, callback(rowid))` helper simplifies a common operation with SQL tables after inserts, handful as shortcut for the following query: +`SELECT ROWID FROM ``table`` ORDER BY ROWID DESC LIMIT 1`. + +The method `.close()` does exactly what it suggests: it closes the database connection. +Please note that it is **not possible to perform other operations once it has been closed**. + +Being an `EventEmitter` instance, the database variable will be notified with the `close` listener, if any. + + +### Understanding The .query() Method +The main role in this module is played by the `db.query()` method, a method rich in overloads all with perfect and natural meaning. + +The amount of parameters goes from one to four, left to right, where left is the input going through the right which is the eventual output. + +All parameters are optionals except the SQL one. + +### db.query() Possible Combinations +```javascript +db.query(SQL) +db.query(SQL, callback:Function) +db.query(SQL, params:Array|Object) +db.query(SQL, fields:Array|Object) +db.query(SQL, params:Array|Object, callback:Function) +db.query(SQL, fields:Array|Object, callback:Function) +db.query(SQL, params:Array|Object, fields:Array|Object) +db.query(SQL, params:Array|Object, fields:Array|Object, callback:Function) +``` +All above combinations are [tested properly in this file](test/dblite.js) together with many other tests able to make `dblite` robust enough and ready to be used. + +Please note how `params` is always before `fields` and/or `callback` if `fields` is missing, just as reminder that order is left to right accordingly with what we are trying to do. + +Following detailed explanation per each parameter. + +#### The SQL:string +This string [accepts any query understood by SQLite](http://www.sqlite.org/lang.html) plus it accepts all commands that regular SQLite shell would accept such `.databases`, `.tables`, `.show` and all others passing through the specified `info` listener, if any, using just the console as fallback otherwise. +```javascript +var dblite = require('dblite'), + db = dblite('./db.sqlite'); + +// will call the implicit `info` console.log +db.query('.show'); +/* will console.log something like: + + echo: off + explain: off + headers: off + mode: csv +nullvalue: "" + output: stdout +separator: "," + stats: off + width: +*/ + +// normal query +db.query('CREATE TABLE IF NOT EXISTS test (id INTEGER PRIMARY KEY, value TEXT)'); +db.query('INSERT INTO test VALUES(null, ?)', ['some text']); +db.query('SELECT * FROM test'); +// will implicitly log the following +// [ [ '1', 'some text' ] ] +``` + +#### The params:Array|Object +If the SQL string **contains special chars** such `?`, `:key`, `$key`, or `@key` properties, these will be replaced accordingly with the `params` `Array` or `Object` that, in this case, MUST be present. +```javascript +// params as Array +db.query('SELECT * FROM test WHERE id = ?', [1]); + +// params as Object +db.query('SELECT * FROM test WHERE id = :id', {id:1}); +// same as +db.query('SELECT * FROM test WHERE id = $id', {id:1}); +// same as +db.query('SELECT * FROM test WHERE id = @id', {id:1}); +``` + +#### The fields:Array|Object +By default, results are returned as an `Array` where all rows are the outer `Array` and each single row is another `Array`. +```javascript +db.query('SELECT * FROM test'); +// will log something like: +[ + [ '1', 'some text' ], // row1 + [ '2', 'something else' ] // rowN +] +``` +If we specify a fields parameter we can have each row represented by an object, instead of an array. +```javascript +// same query using fields as Array +db.query('SELECT * FROM test', ['key', 'value']); +// will log something like: +[ + {key: '1', value: 'some text'}, // row1 + {key: '2', value: 'something else'} // rowN +] +``` + +#### Parsing Through The fields:Object +[SQLite Datatypes](http://www.sqlite.org/datatype3.html) are different from JavaScript plus SQLite works via affinity. +This module also parses sqlite3 output which is **always a string** and as string every result will always be returned **unless** we specify `fields` parameter as object, suggesting validation per each field. +```javascript +// same query using fields as Object +db.query('SELECT * FROM test', { + key: Number, + value: String +}); +// note the key as integer! +[ + {key: 1, value: 'some text'}, // row1 + {key: 2, value: 'something else'} // rowN +] +``` +More complex validators/transformers can be passed without problems: +```javascript +// same query using fields as Object +db.query('SELECT * FROM `table.users`', { + id: Number, + name: String, + adult: Boolean, + skills: JSON.parse, + birthday: Date, + cube: function (fieldValue) { + return fieldValue * 3; + } +}); +``` + +#### The params:Array|Object AND The fields:Array|Object +Not a surprise we can combine both params, using the left to right order input to output so **params first**! +```javascript +// same query using params AND fields +db.query('SELECT * FROM test WHERE id = :id', { + id: 1 +},{ + key: Number, + value: String +}); + +// same as... +db.query('SELECT * FROM test WHERE id = ?', [1], ['key', 'value']); +// same as... +db.query('SELECT * FROM test WHERE id = ?', [1], { + key: Number, + value: String +}); +// same as... +db.query('SELECT * FROM test WHERE id = :id', { + id: 1 +}, [ + 'key', 'value' +]); +``` + +#### The callback:Function +When a `SELECT` or a `PRAGMA` `SQL` is executed the module puts itself in a *waiting for results* state. + +**Update** - Starting from `0.4.0` the callback will be invoked with `err` and `data` if the callback length is greater than one. `function(err, data){}` VS `function(data){}`. However, latter mode will keep working in order to not break backward compatibility. +**Update** - Starting from `0.3.3` every other `SQL` statement will invoke the callback after the operation has been completed. + +As soon as results are fully pushed to the output the module parses this result, if any, and send it to the specified callback. + +The callback is **always the last specified parameter**, if any, or the implicit equivalent of `console.log.bind(console)`. +Latter case is simply helpful to operate directly via `node` **console** and see results without bothering writing a callback each `.query()` call. + +#### Extra Bonus: JSON Serialization With fields:Array|Object +If one field value is not scalar (boolean, number, string, null) `JSON.stringify` is performed in order to save data. +This helps lazy developers that don't want to pre parse every field and let `dblite` do the magic. +```javascript +// test has two fields, id and value +db.query('INSERT INTO test VALUES(?, ?)', [ + 123, + {name: 'dblite', rate: 'awesome'} // value serialized +]); + +// use the fields to parse back the object +db.query('SELECT * FROM test WHERE id = ?', [123], { + id: Number, + value: JSON.parse // value unserialized +}, function (err, rows) { + var record = rows[0]; + console.log(record.id); // 123 + console.log(record.value.name); // "dblite" + console.log(record.value.rate); // "awesome"" +}); +``` + +### Automatic Fields Through Headers +Since version `0.3.0` it is possible to enable automatic fields parsing either through initialization (suggested) or at runtime. +```javascript +var dblite = require('dblite'), + // passing extra argument at creation + db = dblite('file.name', '-header'); + +db.query('SELECT * FROM table', function(err, rows) { + rows[0]; // {header0: value0, headerN: valueN} +}); + +// at runtime +db + .query('.headers ON') + .query('SELECT * FROM table', function(err, rows) { + rows[0]; // {header0: value0, headerN: valueN} + }) + .query('.headers OFF') +; +``` + +In version `0.3.2` a smarter approach for combined _headers/fields_ is used where the right key order is granted by headers but it's possible to validate known fields too. + +```javascript +var db = require('dblite')('file.name', '-header'); + +db.query('SELECT 1 as one, 2 as two', {two:Number}, function(err, rows) { + rows[0]; // {one: "1", two: 2} // note "1" as String +}); +``` +In this way these two options can be supplementary when and if necessary. + + +### Handling Infos And Errors - Listeners +The `EventEmitter` will notify any listener attached to `info`, `error`, or `close` accordingly with the current status. +```javascript +db.on('info', function (data) { + // show data returned by special syntax + // such: .databases .tables .show and others + console.log(data); + // by default, it does the same +}); + +db.on('error', function (err) { + // same as `info` but for errors + console.error(err.toString()); + // by default, it does the same +}); + +db.on('close', function (code) { + // by default, it logs "bye bye" + // invoked once the database has been closed + // and every statement in the queue executed + // the code is the exit code returned via SQLite3 + // usually 0 if everything was OK + console.log('safe to get out of here ^_^_'); +}); +``` +Please **note** that error is invoked only if the callback is not handling it already via double argument. + +The `close` event ensures that all operations have been successfully performed and your app is ready to exit or move next. + +Please note that after invoking `db.close()` any other query will be ignored and the instance will be put in a _waiting to complete_ state which will invoke the `close` listener once operations have been completed. + + +### Raspberry Pi Performance +This is the output generated after a `make test` call in this repo folder within Arch Linux for RPi. +``` +npm test + +> dblite@0.1.2 test /home/dblite +> node test/.test.js + +/home/dblite/dblite.test.sqlite +------------------------------ +main +passes: 1, fails: 0, errors: 0 +------------------------------ +create table if not exists +passes: 1, fails: 0, errors: 0 +------------------------------ +100 sequential inserts +100 records in 3.067 seconds +passes: 1, fails: 0, errors: 0 +------------------------------ +1 transaction with 100 inserts +200 records in 0.178 seconds +passes: 1, fails: 0, errors: 0 +------------------------------ +auto escape +passes: 1, fails: 0, errors: 0 +------------------------------ +auto field +fetched 201 rows as objects in 0.029 seconds +passes: 1, fails: 0, errors: 0 +------------------------------ +auto parsing field +fetched 201 rows as normalized objects in 0.038 seconds +passes: 1, fails: 0, errors: 0 +------------------------------ +many selects at once +different selects in 0.608 seconds +passes: 1, fails: 0, errors: 0 +------------------------------ +db.query() arguments +[ [ '1' ] ] +[ [ '2' ] ] +[ { id: 1 } ] +[ { id: 2 } ] +passes: 5, fails: 0, errors: 0 +------------------------------ +utf-8 +¥ · £ · € · $ · ¢ · ₡ · ₢ · ₣ · ₤ · ₥ · ₦ · ₧ · ₨ · ₩ · ₪ · ₫ · ₭ · ₮ · ₯ · ₹ +passes: 1, fails: 0, errors: 0 +------------------------------ +erease file +passes: 1, fails: 0, errors: 0 + +------------------------------ + 15 Passes +------------------------------ +``` +If an SD card can do this good, I guess any other environment should not have problems here ;-) + +### F.A.Q. +Here a list of probably common Q&A about this module. Please do not hesitate to ask me more, if necessary, thanks. + + * **How Does It Work?** `dblite` uses a [spawned](http://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options) version of the `sqlite3` executable. It could theoretically work with any other SQL like database but it's tested with `sqlite3-shell` only + * **Does It Spawn Per Each Query?** this is a quick one: **NO**! `dblite` spawns once per each database file where usually there is only one database file opened per time. + * **How About Memory And Performance?** Accordingly with `node` manual: + + > These child Nodes are still whole new instances of V8. + > Assume at least 30ms startup and 10mb memory for each new Node. + > That is, you cannot create many thousands of them. + + Since `dblite` spawns only once, there is a little overhead during the database initialization but that's pretty much it, the amount of RAM increases with the amount of data we save or retrieve from the database. The above **Raspberry Pi Benchmark** should ensure that with most common operation, and using transactions where possible, latency and RAM aren't a real issue. + * **Why Not The Native One?** I had some difficulty installing this [node-sqlite3 module](https://github.com/developmentseed/node-sqlite3#name) due `node-gyp` incompatibilities with some **ARM** based device in both *Debian* and *ArchLinux*. Since I really needed an sqlite manager for the next version of [polpetta](https://github.com/WebReflection/polpetta#က-polpetta) which aim is to have a complete, lightweight, and super fast web server in many embedded hardware such RPi, Cubieboard, and others, and since I needed something able to work with multiple core too, I've decided to try this road wrapping the native, easy to install and update, `sqlite3` shell client and do everything I need. So far, so good I would say ;-) + * **Isn't `params` and `fields` an ambiguous choice?** At the very beginning I wasn't sure myself if that would have worked as API choice but later on I've changed my mind. First of all, it's very easy to spot special chars in the `SQL` statement. If present, params is mandatory and used, as easy as that. Secondly, if an object has functions as value, it's obviously a `fields` object, 'cause `params` cannot contains functions since these are not compatible with `JSON` serialization, neither meaningful for the database. The only case where `fields` might be confused with `params` is when no `params` has been specified, and `fields` is an `Array`. In this case I believe you are the same one that wrote the SQL too and know upfront if there are fields to retrieve from `params` or not so this is actually a *non real-world* problem and as soon as you try this API you'll realize it feels intuitive and right. + * **Are Transactions Supported?** ... **YES**, transactions are supported simply performing multiple queries as you would do in *sqlite3* shell: + ```javascript + db.query('BEGIN TRANSACTION'); + for(var i = 0; i < 100; i++) { + db.query('INSERT INTO table VALUES(?, ?)', [null, Math.random()]); + } + db.query('COMMIT'); + ``` + The test file has a transaction with 100 records in it, [have a look](test/dblite.js). + * **Can I Connect To A `:memory:` Database?** well, you can do anything you would do with `sqlite3` shell so **YES** + ```javascript + var db = dblite(':memory:'); // that's it! + ``` + +### License +The usual Mit Style, thinking about the [WTFPL](http://en.wikipedia.org/wiki/WTFPL) though ... stay tuned for updates. + + Copyright (C) 2013 by WebReflection + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. diff --git a/node_modules/dblite/package.json b/node_modules/dblite/package.json new file mode 100644 index 0000000..7890187 --- /dev/null +++ b/node_modules/dblite/package.json @@ -0,0 +1,60 @@ +{ + "version": "0.6.1", + "license": "MIT", + "engine": "node >= 0.6.0", + "name": "dblite", + "description": "a zero hassle wrapper for sqlite - requires sqlite3 3.8.6 or greater", + "homepage": "https://github.com/WebReflection/dblite", + "keywords": [ + "sqlite", + "sqlite3", + "shell", + "query", + "embedded", + "arch linux", + "raspberry pi", + "cubieboard", + "cubieboard2", + "simple", + "no gyp", + "no compile", + "no hassle", + "wrap", + "spawn" + ], + "author": { + "name": "Andrea Giammarchi", + "url": "http://webreflection.blogspot.com/" + }, + "repository": { + "type": "git", + "url": "git://github.com/WebReflection/dblite.git" + }, + "main": "./build/dblite.node.js", + "scripts": { + "test": "node test/.test.js" + }, + "bugs": { + "url": "https://github.com/WebReflection/dblite/issues" + }, + "_id": "dblite@0.6.1", + "_shasum": "18e6d3811f4031ff0119e8a7b13ef1558215376a", + "_from": "dblite@", + "_npmVersion": "1.4.9", + "_npmUser": { + "name": "webreflection", + "email": "andrea.giammarchi@gmail.com" + }, + "maintainers": [ + { + "name": "webreflection", + "email": "andrea.giammarchi@gmail.com" + } + ], + "dist": { + "shasum": "18e6d3811f4031ff0119e8a7b13ef1558215376a", + "tarball": "http://registry.npmjs.org/dblite/-/dblite-0.6.1.tgz" + }, + "directories": {}, + "_resolved": "https://registry.npmjs.org/dblite/-/dblite-0.6.1.tgz" +} diff --git a/node_modules/node-firebird/.npmignore b/node_modules/node-firebird/.npmignore new file mode 100644 index 0000000..47443cf --- /dev/null +++ b/node_modules/node-firebird/.npmignore @@ -0,0 +1,2 @@ + +*.fdb diff --git a/node_modules/node-firebird/LICENSE b/node_modules/node-firebird/LICENSE new file mode 100644 index 0000000..f4bbcd2 --- /dev/null +++ b/node_modules/node-firebird/LICENSE @@ -0,0 +1,373 @@ +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. \ No newline at end of file diff --git a/node_modules/node-firebird/README.md b/node_modules/node-firebird/README.md new file mode 100644 index 0000000..964aa35 --- /dev/null +++ b/node_modules/node-firebird/README.md @@ -0,0 +1,360 @@ +![Firebird Logo](https://www.totaljs.com/exports/firebird-logo.png) + +[![NPM version][npm-version-image]][npm-url] [![NPM downloads][npm-downloads-image]][npm-url] [![Mozilla License][license-image]][license-url] +# Pure JavaScript Firebird client for Node.js. + +Pure JavaScript and Asynchronous Firebird client for Node.js. [Firebird forum](https://groups.google.com/forum/#!forum/node-firebird) on Google Groups. Please share and follow Firebird database, it's a very good open-source product. + +__Firebird database on social networks__ + +- [Firebird on Google+](https://plus.google.com/111558763769231855886/posts) +- [Firebird on Twitter](https://twitter.com/firebirdsql/) +- [Firebird on Facebook](https://www.facebook.com/FirebirdSQL) + +__New version v0.2.0 supports__ + +- added auto-reconnect +- added [sequentially selects](https://github.com/hgourvest/node-firebird/wiki/What-is-sequentially-selects) +- events for connection (attach, detach, row, result, transaction, commit, rollback, error, etc.) +- performance improvements +- supports inserting/updating buffers and streams +- reading blobs (sequentially) +- pooling +- `database.detach()` waits for last command +- better unit-test +- best of use with [total.js - web application framework for node.js](http://www.totaljs.com) + +--- + +- [Firebird documentation](http://www.firebirdsql.org/en/documentation/) +- [Firebird limits and data types](http://www.firebirdsql.org/en/firebird-technical-specifications/) + +## Installation + +```bash +npm install node-firebird +``` + +## Usage + +```js +var Firebird = require('node-firebird'); +``` + +### Methods + +- `Firebird.escape(value) -> return {String}` - prevent for SQL Injections +- `Firebird.attach(options, function(err, db))` attach a database +- `Firebird.create(options, function(err, db))` create a database +- `Firebird.attachOrCreate(options, function(err, db))` attach or create database +- `Firebird.pool(maxSockets, options, function(err, db)) -> return {Object}` create a connection pooling + +## Connection types + +### Connection options + +```js +var options = {}; + +options.host = '127.0.0.1'; +// options.port = 3050; +options.database = 'database.fdb'; +options.user = 'SYSDBA'; +options.password = 'masterkey'; +``` + +### Classic + +```js +Firebird.attach(options, function(err, db) { + + if (err) + throw err; + + // db = DATABASE + db.query('SELECT * FROM TABLE', function(err, result) { + // IMPORTANT: close the connection + db.detach(); + }); + +}); +``` + +### Pooling + +```js +// 5 = the number is count of opened sockets +var pool = Firebird.pool(5, options); + +// Get a free pool +pool.get(function(err, db) { + + if (err) + throw err; + + // db = DATABASE + db.query('SELECT * FROM TABLE', function(err, result) { + // IMPORTANT: release the pool connection + db.detach(); + }); +}); + +// close all opened connections +pool.detach(); + +// Destroy pool +pool.destroy(); +``` + +## Database object (db) + +### Methods + +- `db.query(query, [params], function(err, result))` - classic query, returns Array of Object +- `db.execute(query, [params], function(err, result))` - classic query, returns Array of Array +- `db.sequentially(query, [params], function(row, index), function(err))` - sequentially query +- `db.detach(function(err))` detach a database +- `db.transaction(isolation, function(err, transaction))` create transaction + +### Transaction methods + +- `transaction.query(query, [params], function(err, result))` - classic query, returns Array of Object +- `transaction.execute(query, [params], function(err, result))` - classic query, returns Array of Array +- `transaction.commit(function(err))` commit current transaction +- `transaction.rollback(function(err))` rollback current transaction + +## Examples + +### PARAMETRIZED QUERIES + +### Parameters + +```js +Firebird.attach(options, function(err, db) { + + if (err) + throw err; + + // db = DATABASE + db.query('INSERT INTO USERS (ID, ALIAS, CREATED) VALUES(?, ?, ?) RETURNING ID', [1, 'Pe\'ter', new Date()] function(err, result) { + console.log(result[0].id); + db.query('SELECT * FROM USERS WHERE Alias=?', ['Peter'], function(err, result) { + console.log(result); + db.detach(); + }); + }); +}); +``` + +### BLOB (stream) + +```js +Firebird.attach(options, function(err, db) { + + if (err) + throw err; + + // db = DATABASE + // INSERT STREAM as BLOB + db.query('INSERT INTO USERS (ID, ALIAS, FILE) VALUES(?, ?, ?)', [1, 'Peter', fs.createReadStream('/users/image.jpg')] function(err, result) { + // IMPORTANT: close the connection + db.detach(); + }); +}); +``` + +### BLOB (buffer) + +```js +Firebird.attach(options, function(err, db) { + + if (err) + throw err; + + // db = DATABASE + // INSERT BUFFER as BLOB + db.query('INSERT INTO USERS (ID, ALIAS, FILE) VALUES(?, ?, ?)', [1, 'Peter', fs.readFileSync('/users/image.jpg')] function(err, result) { + // IMPORTANT: close the connection + db.detach(); + }); +}); +``` + +### READING BLOBS (ASYNCHRONOUS) + +```js +Firebird.attach(options, function(err, db) { + + if (err) + throw err; + + // db = DATABASE + db.query('SELECT ID, ALIAS, USERPICTURE FROM USER', function(err, rows) { + + if (err) + throw err; + + // first row + rows[0].userpicture(function(err, name, e) { + + if (err) + throw err; + + // e === EventEmitter + e.on('data', function(chunk) { + // reading data + }); + + e.on('end', function() { + // end reading + // IMPORTANT: close the connection + db.detach(); + }); + }); + + }); +}); +``` + +### STREAMING A BIG DATA + +```js +Firebird.attach(options, function(err, db) { + + if (err) + throw err; + + // db = DATABASE + db.sequentially('SELECT * FROM BIGTABLE', function(row, index) { + + // EXAMPLE + stream.write(JSON.stringify(row)); + + }, function(err) { + // END + // IMPORTANT: close the connection + db.detach(); + }); +}); +``` + +### TRANSACTIONS + +__Transaction types:__ + +- `Firebird.ISOLATION_READ_UNCOMMITTED` +- `Firebird.ISOLATION_READ_COMMITED` +- `Firebird.ISOLATION_REPEATABLE_READ` +- `Firebird.ISOLATION_SERIALIZABLE` +- `Firebird.ISOLATION_READ_COMMITED_READ_ONLY` + +```js +Firebird.attach(options, function(err, db) { + + if (err) + throw err; + + // db = DATABASE + db.transaction(Firebird.ISOLATION_READ_COMMITED, function(err, transaction) { + transaction.query('INSERT INTO users VALUE(?,?)', [1, 'Janko'], function(err, result) { + + if (err) { + transaction.rollback(); + return; + } + + transaction.commit(function(err) { + if (err) + transaction.rollback(); + else + db.detach(); + }); + }); + }); +}); +``` + +### EVENTS + +```js +Firebird.attach(options, function(err, db) { + + if (err) + throw err; + + db.on('row', function(row, index, isObject) { + // index === Number + // isObject === is row object or array? + }); + + db.on('result', function(result) { + // result === Array + }); + + db.on('attach', function() { + + }); + + db.on('detach', function(isPoolConnection) { + // isPoolConnection == Boolean + }); + + db.on('reconnect', function() { + + }); + + db.on('error', function(err) { + + }); + + db.on('transaction', function(isolation) { + // isolation === Number + }); + + db.on('commit', function() { + + }); + + db.on('rollback', function() { + + }); + + db.detach(); +}); +``` + +### Escaping query values + +```js +var sql1 = 'SELECT * FROM TBL_USER WHERE ID>' + Firebird.escape(1); +var sql2 = 'SELECT * FROM TBL_USER WHERE NAME=' + Firebird.escape('Pe\'er'); +var sql3 = 'SELECT * FROM TBL_USER WHERE CREATED<=' + Firebird.escape(new Date()); +var sql4 = 'SELECT * FROM TBL_USER WHERE NEWSLETTER=' + Firebird.escape(true); + +// or db.escape() + +console.log(sql1); +console.log(sql2); +console.log(sql3); +console.log(sql4); +``` + +### Charset for database connection is always UTF-8 + +node-firebird doesn't let you chose the charset connection, it will always use UTF8. +Node is unicode, no matter if your database is using another charset to store string or blob, Firebird will transliterate automatically. + +This is why you should use **Firebird 2.5** server at least. + +## Contributors + +- Henri Gourvest, +- Popa Marius Adrian, +- Peter Širka, + +[license-image]: http://img.shields.io/badge/license-MOZILLA-blue.svg?style=flat +[license-url]: LICENSE + +[npm-url]: https://npmjs.org/package/node-firebird +[npm-version-image]: http://img.shields.io/npm/v/node-firebird.svg?style=flat +[npm-downloads-image]: http://img.shields.io/npm/dm/node-firebird.svg?style=flat diff --git a/node_modules/node-firebird/lib/firebird.msg b/node_modules/node-firebird/lib/firebird.msg new file mode 100644 index 0000000000000000000000000000000000000000..90a737644ac3b5045f2dadfbe2b490e09c948b8e GIT binary patch literal 148556 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 In4PHn7hT|23jhEB literal 0 HcmV?d00001 diff --git a/node_modules/node-firebird/lib/index.js b/node_modules/node-firebird/lib/index.js new file mode 100644 index 0000000..b77e802 --- /dev/null +++ b/node_modules/node-firebird/lib/index.js @@ -0,0 +1,2716 @@ +var + net = require('net'), + os = require('os'), + Events = require('events'), + serialize = require('./serialize.js'), + XdrReader = serialize.XdrReader, + BlrReader = serialize.BlrReader, + XdrWriter = serialize.XdrWriter, + BlrWriter = serialize.BlrWriter, + messages = require('./messages.js'); + +if (typeof(setImmediate) === 'undefined') { + global.setImmediate = function(cb) { + process.nextTick(cb); + }; +} + +/** + * Parse date from string + * @return {Date} + */ +if (String.prototype.parseDate === undefined) { + String.prototype.parseDate = function() { + var self = this.trim(); + var arr = self.indexOf(' ') === -1 ? self.split('T') : self.split(' '); + var index = arr[0].indexOf(':'); + var length = arr[0].length; + + if (index !== -1) { + var tmp = arr[1]; + arr[1] = arr[0]; + arr[0] = tmp; + } + + if (arr[0] === undefined) + arr[0] = ''; + + var noTime = arr[1] === undefined ? true : arr[1].length === 0; + + for (var i = 0; i < length; i++) { + var c = arr[0].charCodeAt(i); + if (c > 47 && c < 58) + continue; + if (c === 45 || c === 46) + continue; + + if (noTime) + return new Date(self); + } + + if (arr[1] === undefined) + arr[1] = '00:00:00'; + + var firstDay = arr[0].indexOf('-') === -1; + + var date = (arr[0] || '').split(firstDay ? '.' : '-'); + var time = (arr[1] || '').split(':'); + var parsed = []; + + if (date.length < 4 && time.length < 2) + return new Date(self); + + index = (time[2] || '').indexOf('.'); + + // milliseconds + if (index !== -1) { + time[3] = time[2].substring(index + 1); + time[2] = time[2].substring(0, index); + } else + time[3] = '0'; + + parsed.push(parseInt(date[firstDay ? 2 : 0], 10)); // year + parsed.push(parseInt(date[1], 10)); // month + parsed.push(parseInt(date[firstDay ? 0 : 2], 10)); // day + parsed.push(parseInt(time[0], 10)); // hours + parsed.push(parseInt(time[1], 10)); // minutes + parsed.push(parseInt(time[2], 10)); // seconds + parsed.push(parseInt(time[3], 10)); // miliseconds + + var def = new Date(); + + for (var i = 0, length = parsed.length; i < length; i++) { + if (isNaN(parsed[i])) + parsed[i] = 0; + + var value = parsed[i]; + if (value !== 0) + continue; + + switch (i) { + case 0: + if (value <= 0) + parsed[i] = def.getFullYear(); + break; + case 1: + if (value <= 0) + parsed[i] = def.getMonth() + 1; + break; + case 2: + if (value <= 0) + parsed[i] = def.getDate(); + break; + } + } + + return new Date(parsed[0], parsed[1] - 1, parsed[2], parsed[3], parsed[4], parsed[5]); + }; +} + +function noop() {} + +const + op_void = 0, // Packet has been voided + op_connect = 1, // Connect to remote server + op_exit = 2, // Remote end has exitted + op_accept = 3, // Server accepts connection + op_reject = 4, // Server rejects connection + op_disconnect = 6, // Connect is going away + op_response = 9, // Generic response block + + // Full context server operations + + op_attach = 19, // Attach database + op_create = 20, // Create database + op_detach = 21, // Detach database + op_compile = 22, // Request based operations + op_start = 23, + op_start_and_send = 24, + op_send = 25, + op_receive = 26, + op_unwind = 27, // apparently unused, see protocol.cpp's case op_unwind + op_release = 28, + + op_transaction = 29, // Transaction operations + op_commit = 30, + op_rollback = 31, + op_prepare = 32, + op_reconnect = 33, + + op_create_blob = 34, // Blob operations + op_open_blob = 35, + op_get_segment = 36, + op_put_segment = 37, + op_cancel_blob = 38, + op_close_blob = 39, + + op_info_database = 40, // Information services + op_info_request = 41, + op_info_transaction = 42, + op_info_blob = 43, + + op_batch_segments = 44, // Put a bunch of blob segments + + op_que_events = 48, // Que event notification request + op_cancel_events = 49, // Cancel event notification request + op_commit_retaining = 50, // Commit retaining (what else) + op_prepare2 = 51, // Message form of prepare + op_event = 52, // Completed event request (asynchronous) + op_connect_request = 53, // Request to establish connection + op_aux_connect = 54, // Establish auxiliary connection + op_ddl = 55, // DDL call + op_open_blob2 = 56, + op_create_blob2 = 57, + op_get_slice = 58, + op_put_slice = 59, + op_slice = 60, // Successful response to op_get_slice + op_seek_blob = 61, // Blob seek operation + +// DSQL operations + + op_allocate_statement = 62, // allocate a statment handle + op_execute = 63, // execute a prepared statement + op_exec_immediate = 64, // execute a statement + op_fetch = 65, // fetch a record + op_fetch_response = 66, // response for record fetch + op_free_statement = 67, // free a statement + op_prepare_statement = 68, // prepare a statement + op_set_cursor = 69, // set a cursor name + op_info_sql = 70, + + op_dummy = 71, // dummy packet to detect loss of client + op_response_piggyback = 72, // response block for piggybacked messages + op_start_and_receive = 73, + op_start_send_and_receive = 74, + op_exec_immediate2 = 75, // execute an immediate statement with msgs + op_execute2 = 76, // execute a statement with msgs + op_insert = 77, + op_sql_response = 78, // response from execute, exec immed, insert + op_transact = 79, + op_transact_response = 80, + op_drop_database = 81, + op_service_attach = 82, + op_service_detach = 83, + op_service_info = 84, + op_service_start = 85, + op_rollback_retaining = 86, + op_partial = 89, // packet is not complete - delay processing + op_trusted_auth = 90, + op_cancel = 91, + op_cont_auth = 92, + op_ping = 93, + op_accept_data = 94, // Server accepts connection and returns some data to client + op_abort_aux_connection = 95, // Async operation - stop waiting for async connection to arrive + op_crypt = 96, + op_crypt_key_callback = 97, + op_cond_accept = 98; // Server accepts connection, returns some data to client + // and asks client to continue authentication before attach call + +const + CONNECT_VERSION2 = 2; + ARCHITECTURE_GENERIC = 1; + +const +// Protocol 10 includes support for warnings and removes the requirement for +// encoding and decoding status codes + PROTOCOL_VERSION10 = 10, + +// Since protocol 11 we must be separated from Borland Interbase. +// Therefore always set highmost bit in protocol version to 1. +// For unsigned protocol version this does not break version's compare. + + FB_PROTOCOL_FLAG = 0x8000, + +// Protocol 11 has support for user authentication related +// operations (op_update_account_info, op_authenticate_user and +// op_trusted_auth). When specific operation is not supported, +// we say "sorry". + + PROTOCOL_VERSION11 = (FB_PROTOCOL_FLAG | 11), + +// Protocol 12 has support for asynchronous call op_cancel. +// Currently implemented asynchronously only for TCP/IP. + + PROTOCOL_VERSION12 = (FB_PROTOCOL_FLAG | 12), + +// Protocol 13 has support for authentication plugins (op_cont_auth). + + PROTOCOL_VERSION13 = (FB_PROTOCOL_FLAG | 13); + + +const + DSQL_close = 1, + DSQL_drop = 2, + DSQL_unprepare = 4; // >= 2.5 + +const + ptype_batch_send = 3; + +const + SQL_TEXT = 452, // Array of char + SQL_VARYING = 448, + SQL_SHORT = 500, + SQL_LONG = 496, + SQL_FLOAT = 482, + SQL_DOUBLE = 480, + SQL_D_FLOAT = 530, + SQL_TIMESTAMP = 510, + SQL_BLOB = 520, + SQL_ARRAY = 540, + SQL_QUAD = 550, + SQL_TYPE_TIME = 560, + SQL_TYPE_DATE = 570, + SQL_INT64 = 580, + SQL_BOOLEAN = 32764, // >= 3.0 + SQL_NULL = 32766; // >= 2.5 + +/***********************/ +/* ISC Error Codes */ +/***********************/ +const + isc_arg_end = 0, // end of argument list + isc_arg_gds = 1, // generic DSRI status value + isc_arg_string = 2, // string argument + isc_arg_cstring = 3, // count & string argument + isc_arg_number = 4, // numeric argument (long) + isc_arg_interpreted = 5, // interpreted status code (string) + isc_arg_unix = 7, // UNIX error code + isc_arg_next_mach = 15, // NeXT/Mach error code + isc_arg_win32 = 17, // Win32 error code + isc_arg_warning = 18, // warning argument + isc_arg_sql_state = 19; // SQLSTATE + +const + isc_sqlerr = 335544436; + +/**********************************/ +/* Database parameter block stuff */ +/**********************************/ +const + isc_dpb_version1 = 1, + isc_dpb_version2 = 2, // >= FB30 + isc_dpb_cdd_pathname = 1, + isc_dpb_allocation = 2, + isc_dpb_journal = 3, + isc_dpb_page_size = 4, + isc_dpb_num_buffers = 5, + isc_dpb_buffer_length = 6, + isc_dpb_debug = 7, + isc_dpb_garbage_collect = 8, + isc_dpb_verify = 9, + isc_dpb_sweep = 10, + isc_dpb_enable_journal = 11, + isc_dpb_disable_journal = 12, + isc_dpb_dbkey_scope = 13, + isc_dpb_number_of_users = 14, + isc_dpb_trace = 15, + isc_dpb_no_garbage_collect = 16, + isc_dpb_damaged = 17, + isc_dpb_license = 18, + isc_dpb_sys_user_name = 19, + isc_dpb_encrypt_key = 20, + isc_dpb_activate_shadow = 21, + isc_dpb_sweep_interval = 22, + isc_dpb_delete_shadow = 23, + isc_dpb_force_write = 24, + isc_dpb_begin_log = 25, + isc_dpb_quit_log = 26, + isc_dpb_no_reserve = 27, + isc_dpb_user_name = 28, + isc_dpb_password = 29, + isc_dpb_password_enc = 30, + isc_dpb_sys_user_name_enc = 31, + isc_dpb_interp = 32, + isc_dpb_online_dump = 33, + isc_dpb_old_file_size = 34, + isc_dpb_old_num_files = 35, + isc_dpb_old_file = 36, + isc_dpb_old_start_page = 37, + isc_dpb_old_start_seqno = 38, + isc_dpb_old_start_file = 39, + isc_dpb_old_dump_id = 41, + isc_dpb_lc_messages = 47, + isc_dpb_lc_ctype = 48, + isc_dpb_cache_manager = 49, + isc_dpb_shutdown = 50, + isc_dpb_online = 51, + isc_dpb_shutdown_delay = 52, + isc_dpb_reserved = 53, + isc_dpb_overwrite = 54, + isc_dpb_sec_attach = 55, + isc_dpb_connect_timeout = 57, + isc_dpb_dummy_packet_interval = 58, + isc_dpb_gbak_attach = 59, + isc_dpb_sql_role_name = 60, + isc_dpb_set_page_buffers = 61, + isc_dpb_working_directory = 62, + isc_dpb_sql_dialect = 63, + isc_dpb_set_db_readonly = 64, + isc_dpb_set_db_sql_dialect = 65, + isc_dpb_gfix_attach = 66, + isc_dpb_gstat_attach = 67, + isc_dpb_set_db_charset = 68, + isc_dpb_gsec_attach = 69, + isc_dpb_address_path = 70, + isc_dpb_process_id = 71, + isc_dpb_no_db_triggers = 72, + isc_dpb_trusted_auth = 73, + isc_dpb_process_name = 74, + isc_dpb_trusted_role = 75, + isc_dpb_org_filename = 76, + isc_dpb_utf8_filename = 77, + isc_dpb_ext_call_depth = 78; + +/*************************************/ +/* Transaction parameter block stuff */ +/*************************************/ +const + isc_tpb_version1 = 1, + isc_tpb_version3 = 3, + isc_tpb_consistency = 1, + isc_tpb_concurrency = 2, + isc_tpb_shared = 3, // < FB21 + isc_tpb_protected = 4, // < FB21 + isc_tpb_exclusive = 5, // < FB21 + isc_tpb_wait = 6, + isc_tpb_nowait = 7, + isc_tpb_read = 8, + isc_tpb_write = 9, + isc_tpb_lock_read = 10, + isc_tpb_lock_write = 11, + isc_tpb_verb_time = 12, + isc_tpb_commit_time = 13, + isc_tpb_ignore_limbo = 14, + isc_tpb_read_committed = 15, + isc_tpb_autocommit = 16, + isc_tpb_rec_version = 17, + isc_tpb_no_rec_version = 18, + isc_tpb_restart_requests = 19, + isc_tpb_no_auto_undo = 20, + isc_tpb_lock_timeout = 21; // >= FB20 + +/****************************/ +/* Common, structural codes */ +/****************************/ +const + isc_info_end = 1, + isc_info_truncated = 2, + isc_info_error = 3, + isc_info_data_not_ready = 4, + isc_info_length = 126, + isc_info_flag_end = 127; + +/*************************/ +/* SQL information items */ +/*************************/ +const + isc_info_sql_select = 4, + isc_info_sql_bind = 5, + isc_info_sql_num_variables = 6, + isc_info_sql_describe_vars = 7, + isc_info_sql_describe_end = 8, + isc_info_sql_sqlda_seq = 9, + isc_info_sql_message_seq = 10, + isc_info_sql_type = 11, + isc_info_sql_sub_type = 12, + isc_info_sql_scale = 13, + isc_info_sql_length = 14, + isc_info_sql_null_ind = 15, + isc_info_sql_field = 16, + isc_info_sql_relation = 17, + isc_info_sql_owner = 18, + isc_info_sql_alias = 19, + isc_info_sql_sqlda_start = 20, + isc_info_sql_stmt_type = 21, + isc_info_sql_get_plan = 22, + isc_info_sql_records = 23, + isc_info_sql_batch_fetch = 24, + isc_info_sql_relation_alias = 25, // >= 2.0 + isc_info_sql_explain_plan = 26; // >= 3.0 + +/*******************/ +/* Blr definitions */ +/*******************/ +const + blr_text = 14, + blr_text2 = 15, + blr_short = 7, + blr_long = 8, + blr_quad = 9, + blr_float = 10, + blr_double = 27, + blr_d_float = 11, + blr_timestamp = 35, + blr_varying = 37, + blr_varying2 = 38, + blr_blob = 261, + blr_cstring = 40, + blr_cstring2 = 41, + blr_blob_id = 45, + blr_sql_date = 12, + blr_sql_time = 13, + blr_int64 = 16, + blr_blob2 = 17, // >= 2.0 + blr_domain_name = 18, // >= 2.1 + blr_domain_name2 = 19, // >= 2.1 + blr_not_nullable = 20, // >= 2.1 + blr_column_name = 21, // >= 2.5 + blr_column_name2 = 22, // >= 2.5 + blr_bool = 23, // >= 3.0 + + blr_version4 = 4, + blr_version5 = 5, // dialect 3 + blr_eoc = 76, + blr_end = 255, + + blr_assignment = 1, + blr_begin = 2, + blr_dcl_variable = 3, + blr_message = 4; + +const + isc_info_sql_stmt_select = 1, + isc_info_sql_stmt_insert = 2, + isc_info_sql_stmt_update = 3, + isc_info_sql_stmt_delete = 4, + isc_info_sql_stmt_ddl = 5, + isc_info_sql_stmt_get_segment = 6, + isc_info_sql_stmt_put_segment = 7, + isc_info_sql_stmt_exec_procedure = 8, + isc_info_sql_stmt_start_trans = 9, + isc_info_sql_stmt_commit = 10, + isc_info_sql_stmt_rollback = 11, + isc_info_sql_stmt_select_for_upd = 12, + isc_info_sql_stmt_set_generator = 13, + isc_info_sql_stmt_savepoint = 14; + +const + isc_blob_text = 1; + +const + DESCRIBE = + [isc_info_sql_stmt_type, + isc_info_sql_select, + isc_info_sql_describe_vars, + isc_info_sql_sqlda_seq, + isc_info_sql_type, + isc_info_sql_sub_type, + isc_info_sql_scale, + isc_info_sql_length, + isc_info_sql_field, + isc_info_sql_relation, + //isc_info_sql_owner, + isc_info_sql_alias, + isc_info_sql_describe_end, + isc_info_sql_bind, + isc_info_sql_describe_vars, + isc_info_sql_sqlda_seq, + isc_info_sql_type, + isc_info_sql_sub_type, + isc_info_sql_scale, + isc_info_sql_length, + isc_info_sql_describe_end]; + +const + ISOLATION_READ_UNCOMMITTED = [isc_tpb_version3, isc_tpb_write, isc_tpb_wait, isc_tpb_read_committed, isc_tpb_rec_version], + ISOLATION_READ_COMMITED = [isc_tpb_version3, isc_tpb_write, isc_tpb_wait, isc_tpb_read_committed, isc_tpb_no_rec_version], + ISOLATION_REPEATABLE_READ = [isc_tpb_version3, isc_tpb_write, isc_tpb_wait, isc_tpb_concurrency], + ISOLATION_SERIALIZABLE = [isc_tpb_version3, isc_tpb_write, isc_tpb_wait, isc_tpb_consistency], + ISOLATION_READ_COMMITED_READ_ONLY = [isc_tpb_version3, isc_tpb_read, isc_tpb_wait, isc_tpb_read_committed, isc_tpb_no_rec_version]; + +const + DEFAULT_HOST = '127.0.0.1', + DEFAULT_PORT = 3050, + DEFAULT_USER = 'SYSDBA', + DEFAULT_PASSWORD = 'masterkey', + DEFAULT_PAGE_SIZE = 4096; + +exports.ISOLATION_READ_UNCOMMITTED = ISOLATION_READ_UNCOMMITTED; +exports.ISOLATION_READ_COMMITED = ISOLATION_READ_COMMITED; +exports.ISOLATION_REPEATABLE_READ = ISOLATION_REPEATABLE_READ; +exports.ISOLATION_SERIALIZABLE = ISOLATION_SERIALIZABLE; +exports.ISOLATION_READ_COMMITED_READ_ONLY = ISOLATION_READ_COMMITED_READ_ONLY; + +if (!String.prototype.padLeft) { + String.prototype.padLeft = function(max, c) { + var self = this; + return new Array(Math.max(0, max - self.length + 1)).join(c || ' ') + self; + }; +} + +/** + * Escape value + * @param {Object} value + * @return {String} + */ +exports.escape = function(value) { + + if (value === null || value === undefined) + return 'NULL'; + + switch (typeof(value)) { + case 'boolean': + return value ? '1' : '0'; + case 'number': + return value.toString(); + case 'string': + return "'" + value.replace(/'/g, "''").replace(/\\/g, '\\\\') + "'"; + } + + if (value instanceof Date) + return "'" + value.getFullYear() + '-' + value.getMonth().toString().padLeft(2, '0') + '-' + value.getDate().toString().padLeft(2, '0') + ' ' + value.getHours().toString().padLeft(2, '0') + ':' + value.getMinutes().toString().padLeft(2, '0') + ':' + value.getSeconds().toString().padLeft(2, '0') + "'"; + + throw new Error('Escape supports only primitive values.'); +}; + +const + DEFAULT_ENCODING = 'utf8'; + DEFAULT_FETCHSIZE = 200; + +const + MAX_INT = Math.pow(2, 31) - 1; + MIN_INT = - Math.pow(2, 31); + +/*************************************** + * + * SQLVar + * + ***************************************/ + + +const + ScaleDivisor = [1,10,100,1000,10000,100000,1000000,10000000,100000000,1000000000,10000000000, 100000000000,1000000000000,10000000000000,100000000000000,1000000000000000]; +const + DateOffset = 40587, + TimeCoeff = 86400000; + MsPerMinute = 60000; + +//------------------------------------------------------ + +function SQLVarText() {} + +SQLVarText.prototype.decode = function(data) { + var ret; + if (this.subType > 1) { + ret = data.readText(this.length, DEFAULT_ENCODING); + } else { + ret = data.readBuffer(this.length); + } + + if (!data.readInt()) { + return ret; + } + return null; +}; + +SQLVarText.prototype.calcBlr = function(blr) { + blr.addByte(blr_text); + blr.addWord(this.length); +}; + +//------------------------------------------------------ + +function SQLVarNull() {} +SQLVarNull.prototype = new SQLVarText(); +SQLVarNull.prototype.constructor = SQLVarNull; + +//------------------------------------------------------ + +function SQLVarString() {} + +SQLVarString.prototype.decode = function(data) { + var ret; + if (this.subType > 1) { + ret = data.readString(DEFAULT_ENCODING) + } else { + ret = data.readBuffer() + } + if (!data.readInt()) { + return ret; + } + return null; +}; + +SQLVarString.prototype.calcBlr = function(blr) { + blr.addByte(blr_varying); + blr.addWord(this.length); +}; + +//------------------------------------------------------ + +function SQLVarQuad() {} + +SQLVarQuad.prototype.decode = function(data) { + var ret = data.readQuad(); + if (!data.readInt()) { + return ret; + } + return null; +}; + +SQLVarQuad.prototype.calcBlr = function(blr) { + blr.addByte(blr_quad); + blr.addShort(this.scale); +}; + +//------------------------------------------------------ + +function SQLVarBlob() {} +SQLVarBlob.prototype = new SQLVarQuad(); +SQLVarBlob.prototype.constructor = SQLVarBlob; + +SQLVarBlob.prototype.calcBlr = function(blr) { + blr.addByte(blr_quad); + blr.addShort(0); +}; + +//------------------------------------------------------ + +function SQLVarArray() {} +SQLVarArray.prototype = new SQLVarQuad(); +SQLVarArray.prototype.constructor = SQLVarArray; + +SQLVarArray.prototype.calcBlr = function(blr) { + blr.addByte(blr_quad); + blr.addShort(0); +}; + +//------------------------------------------------------ + +function SQLVarInt() {} + +SQLVarInt.prototype.decode = function(data) { + var ret = data.readInt(); + if (!data.readInt()) { + if (this.scale) { + ret = ret / ScaleDivisor[Math.abs(this.scale)]; + } + return ret; + } + return null; +}; + +SQLVarInt.prototype.calcBlr = function(blr) { + blr.addByte(blr_long); + blr.addShort(this.scale); +}; + +//------------------------------------------------------ + +function SQLVarShort() {} +SQLVarShort.prototype = new SQLVarInt(); +SQLVarShort.prototype.constructor = SQLVarShort; + +SQLVarShort.prototype.calcBlr = function(blr) { + blr.addByte(blr_short); + blr.addShort(this.scale); +}; + +//------------------------------------------------------ + +function SQLVarInt64() {} + +SQLVarInt64.prototype.decode = function(data) { + var ret = data.readInt64(); + if (!data.readInt()) { + if (this.scale) { + ret = ret / ScaleDivisor[Math.abs(this.scale)]; + } + return ret; + } + return null; +}; + +SQLVarInt64.prototype.calcBlr = function(blr) { + blr.addByte(blr_int64); + blr.addShort(this.scale); +}; + +//------------------------------------------------------ + +function SQLVarFloat() {} + +SQLVarFloat.prototype.decode = function(data) { + var ret = data.readFloat(); + if (!data.readInt()) { + return ret; + } + return null; +}; + +SQLVarFloat.prototype.calcBlr = function(blr) { + blr.addByte(blr_float); +}; + +//------------------------------------------------------ + +function SQLVarDouble() {} + +SQLVarDouble.prototype.decode = function(data) { + var ret = data.readDouble(); + if (!data.readInt()) { + return ret; + } + return null; +}; + +SQLVarDouble.prototype.calcBlr = function(blr) { + blr.addByte(blr_double); +}; + +//------------------------------------------------------ + +function SQLVarDate() {} + +SQLVarDate.prototype.decode = function(data) { + var ret = data.readInt(); + if (!data.readInt()) { + var d = new Date(0); + d.setMilliseconds((ret - DateOffset) * TimeCoeff + d.getTimezoneOffset() * MsPerMinute); + return d; + } + return null; +}; + +SQLVarDate.prototype.calcBlr = function(blr) { + blr.addByte(blr_sql_date); +}; + +//------------------------------------------------------ + +function SQLVarTime() {} + +SQLVarTime.prototype.decode = function(data) { + var ret = data.readUInt(); + if (!data.readInt()) { + var d = new Date(0); + d.setMilliseconds(Math.floor(ret / 10) + d.getTimezoneOffset() * MsPerMinute); + return d; + } + return null; +}; + +SQLVarTime.prototype.calcBlr = function(blr) { + blr.addByte(blr_sql_time); +}; + +//------------------------------------------------------ + +function SQLVarTimeStamp() {} + +SQLVarTimeStamp.prototype.decode = function(data) { + var date = data.readInt(); + var time = data.readUInt(); + if (!data.readInt()) { + var d = new Date(0); + d.setMilliseconds((date - DateOffset) * TimeCoeff + Math.floor(time / 10) + d.getTimezoneOffset() * MsPerMinute); + return d; + } + return null; +}; + +SQLVarTimeStamp.prototype.calcBlr = function(blr) { + blr.addByte(blr_timestamp); +}; + +//------------------------------------------------------ + +// todo: test it +function SQLVarBoolean() {} + +SQLVarBoolean.prototype.decode = function(data) { + var ret = data.readInt(); + if (!data.readInt()) { + return Boolean(ret); + } + return null; +}; + +SQLVarBoolean.prototype.calcBlr = function(blr) { + blr.addByte(blr_bool); +}; + +//------------------------------------------------------ + +function SQLParamInt(value){ + this.value = value; +} + +SQLParamInt.prototype.calcBlr = function(blr) { + blr.addByte(blr_long); + blr.addShort(0); +}; + +SQLParamInt.prototype.encode = function(data) { + if (this.value != null) { + data.addInt(this.value); + data.addInt(0); + } else { + data.addInt(0); + data.addInt(1); + } +}; + +//------------------------------------------------------ + +function SQLParamInt64(value){ + this.value = value; +} + +SQLParamInt64.prototype.calcBlr = function(blr) { + blr.addByte(blr_int64); + blr.addShort(0); +}; + +SQLParamInt64.prototype.encode = function(data) { + if (this.value != null) { + data.addInt64(this.value); + data.addInt(0); + } else { + data.addInt64(0); + data.addInt(1); + } +}; + +//------------------------------------------------------ + +function SQLParamDouble(value) { + this.value = value; +} + +SQLParamDouble.prototype.encode = function(data) { + if (this.value != null) { + data.addDouble(this.value); + data.addInt(0); + } else { + data.addDouble(0); + data.addInt(1); + } +}; + +SQLParamDouble.prototype.calcBlr = function(blr) { + blr.addByte(blr_double); +}; + +//------------------------------------------------------ + +function SQLParamString(value) { + this.value = value; +} + +SQLParamString.prototype.encode = function(data) { + if (this.value != null) { + data.addText(this.value, DEFAULT_ENCODING); + data.addInt(0); + } else { + data.addInt(1); + } +}; + +SQLParamString.prototype.calcBlr = function(blr) { + blr.addByte(blr_text); + var len = this.value ? Buffer.byteLength(this.value, DEFAULT_ENCODING) : 0; + blr.addWord(len); +}; + +//------------------------------------------------------ + +function SQLParamQuad(value) { + this.value = value; +} + +SQLParamQuad.prototype.encode = function(data) { + if (this.value != null) { + data.addInt(this.value.high); + data.addInt(this.value.low); + data.addInt(0); + } else { + data.addInt(0); + data.addInt(0); + data.addInt(1); + } +}; + +SQLParamQuad.prototype.calcBlr = function(blr) { + blr.addByte(blr_quad); + blr.addShort(0); +}; + +//------------------------------------------------------ + +function SQLParamDate(value) { + this.value = value; +} + +SQLParamDate.prototype.encode = function(data) { + if (this.value != null) { + + var value = this.value.getTime() - this.value.getTimezoneOffset() * MsPerMinute; + var time = value % TimeCoeff; + var date = (value - time) / TimeCoeff + DateOffset; + time *= 10; + data.addInt(date); + data.addUInt(time); + data.addInt(0); + } else { + data.addInt(0); + data.addUInt(0); + data.addInt(1); + } +}; + +SQLParamDate.prototype.calcBlr = function(blr) { + blr.addByte(blr_timestamp); +}; + +//------------------------------------------------------ + +function SQLParamBool(value) { + this.value = value; +} + +SQLParamBool.prototype.encode = function(data) { + if (this.value != null) { + data.addInt(this.value ? 1 : 0); + data.addInt(0); + } else { + data.addInt(0); + data.addInt(1); + } +}; + +SQLParamBool.prototype.calcBlr = function(blr) { + blr.addByte(blr_short); + blr.addShort(0); +}; + + +/*************************************** + * + * Error handling + * + ***************************************/ + +function isError(obj) { + return (obj instanceof Object && obj.status); +} + +function doCallback(obj, callback) { + + if (!callback) + return; + + if (isError(obj)) { + callback(new Error(obj.message)); + return; + } + + callback(undefined, obj); + +} + +function doError(obj, callback) { + if (callback) + callback(obj) +} + +/*************************************** + * + * Statement + * + ***************************************/ + +function Statement(connection) { + this.connection = connection; +} + +Statement.prototype.close = function(callback) { + this.connection.closeStatement(this, callback); +}; + +Statement.prototype.drop = function(callback) { + this.connection.dropStatement(this, callback); +}; + +Statement.prototype.execute = function(transaction, params, callback, custom) { + + if (params instanceof Function) { + custom = callback; + callback = params; + params = undefined; + } + + this.custom = custom; + this.connection.executeStatement(transaction, this, params, callback, custom); +}; + +Statement.prototype.fetch = function(transaction, count, callback) { + this.connection.fetch(this, transaction, count, callback); +}; + +Statement.prototype.fetchAll = function(transaction, callback) { + this.connection.fetchAll(this, transaction, callback); +}; + +/*************************************** + * + * Transaction + * + ***************************************/ + +function Transaction(connection) { + this.connection = connection; + this.db = connection.db; +} + +Transaction.prototype.newStatement = function(query, callback) { + var cnx = this.connection; + var self = this; + + cnx.allocateStatement(function(err, statement) { + if (err) { + doError(err, callback); + return; + } + cnx.prepareStatement(self, statement, query, false, callback); + }); +}; + +Transaction.prototype.execute = function(query, params, callback, custom) { + + if (params instanceof Function) { + callback = params; + params = undefined; + } + + var self = this; + + this.newStatement(query, function(err, statement) { + + if (err) { + doError(err, callback); + return; + } + + function dropError(err) { + statement.drop(); + doCallback(err, callback); + } + + statement.execute(self, params, function(err) { + + if (err) { + dropError(err); + return; + } + + switch (statement.type) { + + case isc_info_sql_stmt_select: + statement.fetchAll(self, function(err, ret) { + + if (err) { + dropError(err); + return; + } + + statement.drop(); + + if (callback) + callback(undefined, ret, statement.output, true); + + }); + + break; + + case isc_info_sql_stmt_exec_procedure: + if (statement.output.length) { + statement.fetch(self, 1, function(err, ret) { + if (err) { + dropError(err); + return; + } + + statement.drop(); + + if (callback) + callback(undefined, ret.data[0], statement.output, false); + }); + + break; + } + + // Fall through is normal + default: + statement.drop(); + if (callback) + callback() + break; + } + + }, custom); + }); +}; + +Transaction.prototype.query = function(query, params, callback) { + + if (params instanceof Function) { + callback = params; + params = undefined; + } + + if (callback === undefined) + callback = noop; + + this.execute(query, params, callback, { asObject: true, asStream: callback === undefined || callback === null }); + +}; + +Transaction.prototype.commit = function(callback) { + this.connection.commit(this, callback); +}; + +Transaction.prototype.rollback = function(callback) { + this.connection.rollback(this, callback); +}; + +Transaction.prototype.commitRetaining = function(callback) { + this.connection.commitRetaining(this, callback); +}; + +Transaction.prototype.rollbackRetaining = function(callback) { + this.connection.rollbackRetaining(this, callback); +}; + +/*************************************** + * + * Database + * + ***************************************/ + +function Database(connection) { + this.connection = connection; + connection.db = this; +} + +Database.prototype.__proto__ = new Events.EventEmitter(); + +Database.prototype.escape = function(value) { + return exports.escape(value); +}; + +Database.prototype.detach = function(callback, force) { + + var self = this; + + if (!force && self.connection._pending.length > 0) { + self.connection._detachAuto = true; + self.connection._detachCallback = callback; + return self; + } + + self.connection.detach(function(err, obj) { + + self.connection.disconnect(); + self.emit('detach', false); + + if (callback) + callback(err, obj); + + }, force); + + return self; +}; + +Database.prototype.transaction = function(isolation, callback) { + return this.startTransaction(isolation, callback); +}; + +Database.prototype.startTransaction = function(isolation, callback) { + this.connection.startTransaction(isolation, callback); + return this; +}; + +Database.prototype.newStatement = function (query, callback) { + + this.startTransaction(function(err, transaction) { + + if (err) { + callback(err); + return; + } + + transaction.newStatement(query, function(err, statement) { + + if (err) { + callback(err); + return; + } + + transaction.commit(function(err) { + callback(err, statement); + }); + }); + }); + + return this; +}; + +Database.prototype.execute = function(query, params, callback, custom) { + + if (params instanceof Function) { + callback = params; + params = undefined; + } + + var self = this; + + self.connection.startTransaction(function(err, transaction) { + + if (err) { + doError(err, callback); + return; + } + + transaction.execute(query, params, function(err, result, meta, isSelect) { + + if (err) { + transaction.rollback(function() { + doError(err, callback); + }); + return; + } + + transaction.commit(function(err) { + if (callback) + callback(err, result, meta, isSelect); + }); + + }, custom); + }); + + return self; +}; + +Database.prototype.sequentially = function(query, params, on, callback, asArray) { + + if (params instanceof Function) { + asArray = callback; + callback = on; + on = params; + params = undefined; + } + + if (on === undefined) + throw new Error('Expected "on" delegate.'); + + var self = this; + self.execute(query, params, callback, { asObject: !asArray, asStream: true, on: on }); + return self; +}; + +Database.prototype.query = function(query, params, callback) { + + if (params instanceof Function) { + callback = params; + params = undefined; + } + + var self = this; + self.execute(query, params, callback, { asObject: true, asStream: callback === undefined || callback === null }); + return self; +}; + +exports.attach = function(options, callback) { + + var host = options.host || DEFAULT_HOST; + var port = options.port || DEFAULT_PORT; + + var cnx = this.connection = new Connection(host, port, function(err) { + + if (err) { + doError(err, callback); + return; + } + + cnx.connect(options.database || options.filename, function(err) { + if (err) + doError(err, callback); + else + cnx.attach(options, callback); + }); + + }, options); +}; + +exports.create = function(options, callback) { + var host = options.host || DEFAULT_HOST; + var port = options.port || DEFAULT_PORT; + var cnx = this.connection = new Connection(host, port, function(err) { + cnx.connect(options.database || options.filename, function(err) { + + if (err) { + self.db.emit('error', err); + doError(err, callback); + return; + } + + cnx.createDatabase(options, callback); + }); + }, options); +}; + +exports.attachOrCreate = function(options, callback) { + + var host = options.host || DEFAULT_HOST; + var port = options.port || DEFAULT_PORT; + + var cnx = this.connection = new Connection(host, port, function(err) { + + var self = cnx; + + if (err) { + callback({ error: err, message: "Connect error" }); + return; + } + + cnx.connect(options.database || options.filename, function(err) { + + if (err) { + doError(err, callback); + return; + } + + cnx.attach(options, function(err, ret) { + + if (!err) { + if (self.db) + self.db.emit('connect', ret); + doCallback(ret, callback); + return; + } + + cnx.createDatabase(options, callback); + }); + }); + + }, options); +}; + +// Pooling +exports.pool = function(max, options, callback) { + + var pool = new Pool(); + + options.isPool = true; + + function create(max) { + exports.attach(options, function(err, db) { + + if (err) + throw err; + + max--; + + pool.db.push(db); + poolEvents(db, pool); + + if (max <= 0) { + pool.isReady = true; + pool.check(); + if (callback) + callback(null, pool); + return; + } + + create(max); + }); + }; + + create(max); + + return pool; +}; + +function poolEvents(db, pool) { + db.on('detach', function(is) { + + if (!is) + return; + + db.connection._queue = []; + db.connection._pending = []; + db.connection._isUsed = false; + + setImmediate(function() { + pool.check(); + }); + }); +} + +/*************************************** + * + * Simple Pooling + * + ***************************************/ + +function Pool() { + this.db = []; + this.pending = []; + this.isReady = false; + this.isDestroy = false; +} + +Pool.prototype.get = function(callback) { + + var self = this; + if (self.isDestroy) + return self; + + self.pending.push(callback); + self.check(); + return self; +}; + +Pool.prototype.check = function() { + + var self = this; + + for (var i = 0, length = self.db.length; i < length; i++) { + + var db = self.db[i]; + if (db.connection._isUsed) + continue; + + db.removeAllListeners(); + poolEvents(db, self); + + var cb = self.pending.shift(); + if (cb) { + db.connection._isUsed = true; + cb(null, db); + } + + return self; + } + + return self; +}; + +Pool.prototype.detach = function() { + + var self = this; + var count = self.db.length; + + var fn = function() { + count--; + if (count > 0 || !self.isDestroy) + return; + self.db = null; + self.pending = null; + }; + + for (var i = 0; i < self.db.length; i++) + self.db[i].detach(fn, true); + + return self; +}; + +Pool.prototype.destroy = function() { + var self = this; + self.detach(); + self.isDestroy = true; + return self; +}; + +/*************************************** + * + * Connection + * + ***************************************/ + +var Connection = exports.Connection = function (host, port, callback, options, db) { + var self = this; + this.db = db; + this._msg = new XdrWriter(32); + this._blr = new BlrWriter(32); + this._queue = []; + this._detachTimeout; + this._detachCallback; + this._detachAuto; + this._socket = net.createConnection(port, host); + this._pending = []; + this._isClosed = false; + this._isDetach = false; + this._isUsed = false; + this.options = options; + this._bind_events(host, port, callback); + this.error; +}; + +exports.Connection.prototype._bind_events = function(host, port, callback) { + + var self = this; + + self._socket.on('close', function() { + + self._isClosed = true; + + if (self._isDetach) + return; + + if (!self.db) { + if (callback) + callback(self.error); + return; + } + + setImmediate(function() { + + self._socket = null; + self._msg = null; + self._blr = null; + + var ctx = new Connection(host, port, function(err) { + ctx.connect(self.options.filename, function(err) { + + if (err) { + self.emit('error', err); + return; + } + + ctx.attach(self.options, function(err) { + + if (err) { + self.emit('error', err); + return; + } + + ctx._queue = ctx._queue.concat(self._queue); + ctx._pending = ctx._pending.concat(self._pending); + self.db.emit('reconnect'); + + }, self.db); + }); + + }, self.options, self.db); + }); + + }); + + self._socket.on('error', function(e) { + + self.error = e; + + if (self.db) + self.db.emit('error', e) + + if (callback) + callback(e); + + }); + + self._socket.on('connect', function() { + self._isClosed = false; + self._isOpened = true; + if (callback) + callback(); + }); + + self._socket.on('data', function(data) { + + var obj, cb, pos, xdr, buf; + + if (!self._xdr) { + xdr = new XdrReader(data); + } else { + xdr = self._xdr; + delete(self._xdr); + buf = new Buffer(data.length + xdr.buffer.length); + xdr.buffer.copy(buf); + data.copy(buf, xdr.buffer.length); + xdr.buffer = buf; + } + + + while (xdr.pos < xdr.buffer.length) { + + pos = xdr.pos; + + try { + cb = self._queue[0]; + obj = decodeResponse(xdr, cb, self.db); + } catch(err) { + buf = new Buffer(xdr.buffer.length - pos); + xdr.buffer.copy(buf, 0, pos); + xdr.buffer = buf; + xdr.pos = 0; + self._xdr = xdr; + return; + } + + self._queue.shift(); + self._pending.shift(); + + if (obj && obj.status) { + + messages.lookupMessages(obj.status, function(message) { + obj.message = message; + doCallback(obj, cb); + }); + + } else + doCallback(obj, cb); + } + + if (!self._detachAuto || self._pending.length !== 0) + return; + + clearTimeout(self._detachTimeout); + self._detachTimeout = setTimeout(function() { + self.db.detach(self._detachCallback); + self._detachAuto = false; + }, 100); + + }); +} + +exports.Connection.prototype.disconnect = function() { + this._socket.end(); +}; + +function decodeResponse(data, callback, db){ + + do { + var r = data.readInt(); + } while (r === op_dummy); + + var item, op; + switch (r) { + case op_response: + + var response; + + if (callback) + response = callback.response || {}; + else + response = {}; + + response.handle = data.readInt(); + var oid = data.readQuad(); + if (oid.low || oid.high) + response.oid = oid + + var buf = data.readArray(); + if (buf) + response.buffer = buf; + + var num; + while (true) { + op = data.readInt(); + switch (op){ + case isc_arg_end: + return response; + case isc_arg_gds: + num = data.readInt(); + if (!num) + break; + item = { gdscode: num }; + if (response.status) + response.status.push(item); + else + response.status = [item]; + break; + case isc_arg_string: + case isc_arg_interpreted: + case isc_arg_sql_state: + + if (item.params) { + var str = data.readString(DEFAULT_ENCODING); + item.params.push(str); + } else + item.params = [data.readString(DEFAULT_ENCODING)]; + + break; + + case isc_arg_number: + num = data.readInt(); + + if (item.params) + item.params.push(num); + else + item.params = [num]; + + if (item.gdscode === isc_sqlerr) + response.sqlcode = num; + + break; + + default: + throw new Error('Unexpected: ' + op); + } + } + break; + + case op_fetch_response: + + var status = data.readInt(); + var count = data.readInt(); + var statement = callback.statement; + var output = statement.output; + var custom = statement.custom || {}; + var cols = null; + var rows = custom.asStream ? null : []; + var index = 0; + + if (custom.asObject) { + cols = []; + for (var i = 0, length = output.length; i < length; i++) + cols.push(output[i].alias.toLowerCase()); + } + + while (count && (status !== 100)) { + + var row = custom.asObject ? {} : new Array(output.length); + + for (var i = 0, length = output.length; i < length; i++) { + + item = output[i]; + var value = item.decode(data); + + if (item.type === 580 && value !== null) + value = value.low_; + + if (custom.asObject) { + if (item.type === SQL_BLOB) + value = fetch_blob_async(statement, value, cols[i]); + row[cols[i]] = value; + } + else { + if (item.type === SQL_BLOB) + value = fetch_blob_async(statement, value, i); + row[i] = value; + } + } + + statement.connection.db.emit('row', row, index, custom.asObject); + + op = data.readInt(); // ?? + status = data.readInt(); + count = data.readInt(); + + if (!custom.asStream) + rows.push(row); + + if (custom.on) + custom.on(row, index); + + index++; + } + + statement.connection.db.emit('result', rows); + return { data: rows, fetched: Boolean(status === 100) }; + + case op_accept: + if (data.readInt() !== PROTOCOL_VERSION10 || data.readInt() !== ARCHITECTURE_GENERIC || data.readInt() !== ptype_batch_send) + throw new Error('Invalid connect result'); + return {}; + + default: + throw new Error('Unexpected:' + r); + } +} + +Connection.prototype._queueEvent = function(callback){ + var self = this; + + if (self._isClosed) { + if (callback) + callback(new Error('Connection is closed.')); + return; + } + + self._queue.push(callback); + self._socket.write(self._msg.getData()); +}; + +Connection.prototype.connect = function (database, callback) { + + var msg = this._msg; + var blr = this._blr; + + msg.pos = 0; + blr.pos = 0; + + msg.addInt(op_connect); + msg.addInt(op_attach); + msg.addInt(CONNECT_VERSION2); + msg.addInt(ARCHITECTURE_GENERIC); + msg.addString(database || '', DEFAULT_ENCODING); + msg.addInt(1); // Protocol version understood count. + + blr.addString(1, process.env['USER'] || process.env['USERNAME'] || 'Unknown', DEFAULT_ENCODING); + var hostname = os.hostname(); + blr.addString(4, hostname, DEFAULT_ENCODING); + blr.addBytes([6, 0]); + msg.addBlr(this._blr); + + msg.addInt(PROTOCOL_VERSION10); + msg.addInt(ARCHITECTURE_GENERIC); + msg.addInt(2); // Min type + msg.addInt(3); // Max type + msg.addInt(2); // Preference weight + + this._queueEvent(callback); +}; + +Connection.prototype.attach = function (options, callback, db) { + + var database = options.database || options.filename; + var user = options.user || DEFAULT_USER; + var password = options.password || DEFAULT_PASSWORD; + var role = options.role; + var self = this; + var msg = this._msg; + var blr = this._blr; + msg.pos = 0; + blr.pos = 0; + + blr.addByte(1); + blr.addString(isc_dpb_lc_ctype, 'UTF8', DEFAULT_ENCODING); + blr.addString(isc_dpb_user_name, user, DEFAULT_ENCODING); + blr.addString(isc_dpb_password, password, DEFAULT_ENCODING); + + if (role) + blr.addString(isc_dpb_sql_role_name, role, DEFAULT_ENCODING); + + msg.addInt(op_attach); + msg.addInt(0); // Database Object ID + msg.addString(database, DEFAULT_ENCODING); + msg.addBlr(this._blr); + + var self = this; + + function cb(err, ret) { + + if (err) { + doError(err, callback); + return; + } + + self.dbhandle = ret.handle; + if (callback) + callback(undefined, ret); + } + + // For reconnect + if (db) { + db.connection = this; + cb.response = db; + } else { + cb.response = new Database(this); + cb.response.on('error', noop); + } + + this._queueEvent(cb); +}; + +Connection.prototype.detach = function (callback, force) { + + var self = this; + + if (self._isClosed) + return; + + if (self.options.isPool && !force) { + self._isUsed = false; + // self._queue = []; + // self._pending = []; + self.db.emit('detach', true); + return; + } + + self._isUsed = false; + self._isDetach = true; + + var msg = self._msg; + + msg.pos = 0; + msg.addInt(op_detach); + msg.addInt(0); // Database Object ID + + self._queueEvent(function(err, ret) { + delete(self.dbhandle); + if (callback) + callback(err, ret); + }); +}; + +Connection.prototype.createDatabase = function (options, callback) { + + var database = options.database || options.filename; + var user = options.user || DEFAULT_USER; + var password = options.password || DEFAULT_PASSWORD; + var pageSize = options.pageSize || DEFAULT_PAGE_SIZE; + var role = options.role; + var blr = this._blr; + + blr.pos = 0; + blr.addByte(1); + blr.addString(isc_dpb_set_db_charset, 'UTF8', DEFAULT_ENCODING); + blr.addString(isc_dpb_lc_ctype, 'UTF8', DEFAULT_ENCODING); + blr.addString(isc_dpb_user_name, user, DEFAULT_ENCODING); + blr.addString(isc_dpb_password, password, DEFAULT_ENCODING); + + if (role) + blr.addString(isc_dpb_sql_role_name, role, DEFAULT_ENCODING); + + blr.addNumeric(isc_dpb_sql_dialect, 3); + blr.addNumeric(isc_dpb_force_write, 1); + blr.addNumeric(isc_dpb_overwrite, 1); + blr.addNumeric(isc_dpb_page_size, pageSize); + + var msg = this._msg; + msg.pos = 0; + msg.addInt(op_create); // op_create + msg.addInt(0); // Database Object ID + msg.addString(database, DEFAULT_ENCODING); + msg.addBlr(blr); + + var self = this; + + function cb(err, ret) { + + if (ret) + self.dbhandle = ret.handle; + + setImmediate(function() { + if (self.db) + self.db.emit('attach', ret); + }); + + if (callback) + callback(err, ret); + } + + cb.response = new Database(this); + this._queueEvent(cb); +}; + +Connection.prototype.throwClosed = function(callback) { + var err = new Error('Connection is closed.'); + this.db.emit('error', err); + if (callback) + callback(err); + return this; +}; + +Connection.prototype.startTransaction = function(isolation, callback) { + + if (typeof(isolation) === 'function') { + var tmp = isolation; + isolation = callback; + callback = tmp; + } + + if (this._isClosed) + return this.throwClosed(callback); + + // for auto detach + this._pending.push('startTransaction'); + + var blr = this._blr; + var msg = this._msg; + + blr.pos = 0; + msg.pos = 0; + + if (isolation instanceof Function) { + callback = isolation; + isolation = null; + } + + blr.addBytes(isolation || ISOLATION_REPEATABLE_READ); + msg.addInt(op_transaction); + msg.addInt(this.dbhandle); + msg.addBlr(blr); + callback.response = new Transaction(this); + + this.db.emit('transaction', isolation); + this._queueEvent(callback); +}; + +Connection.prototype.commit = function (transaction, callback) { + + if (this._isClosed) + return this.throwClosed(callback); + + // for auto detach + this._pending.push('commit'); + + var msg = this._msg; + msg.pos = 0; + msg.addInt(op_commit); + msg.addInt(transaction.handle); + this.db.emit('commit'); + this._queueEvent(callback); +}; + +Connection.prototype.rollback = function (transaction, callback) { + + if (this._isClosed) + return this.throwClosed(callback); + + // for auto detach + this._pending.push('rollback'); + + var msg = this._msg; + msg.pos = 0; + msg.addInt(op_rollback); + msg.addInt(transaction.handle); + this.db.emit('rollback'); + this._queueEvent(callback); +}; + +Connection.prototype.commitRetaining = function (transaction, callback) { + + if (this._isClosed) + throw new Error('Connection is closed.'); + + // for auto detach + this._pending.push('commitRetaining'); + + var msg = this._msg; + msg.pos = 0; + msg.addInt(op_commit_retaining); + msg.addInt(transaction.handle); + this._queueEvent(callback); +}; + +Connection.prototype.rollbackRetaining = function (transaction, callback) { + + if (this._isClosed) + return this.throwClosed(callback); + + // for auto detach + this._pending.push('rollbackRetaining'); + + var msg = this._msg; + msg.pos = 0; + msg.addInt(op_rollback_retaining); + msg.addInt(transaction.handle); + this._queueEvent(callback); +}; + +Connection.prototype.allocateStatement = function (callback) { + + if (this._isClosed) + return this.throwClosed(callback); + + // for auto detach + this._pending.push('allocateStatement'); + + var msg = this._msg; + msg.pos = 0; + msg.addInt(op_allocate_statement); + msg.addInt(this.dbhandle); + callback.response = new Statement(this); + this._queueEvent(callback); +}; + +Connection.prototype.dropStatement = function (statement, callback) { + + if (this._isClosed) + return this.throwClosed(callback); + + // for auto detach + this._pending.push('dropStatement'); + + var msg = this._msg; + msg.pos = 0; + msg.addInt(op_free_statement); + msg.addInt(statement.handle); + msg.addInt(DSQL_drop); + this._queueEvent(callback); +}; + +Connection.prototype.closeStatement = function (statement, callback) { + + if (this._isClosed) + return this.throwClosed(callback); + + // for auto detach + this._pending.push('closeStatement'); + + var msg = this._msg; + msg.pos = 0; + msg.addInt(op_free_statement); + msg.addInt(statement.handle); + msg.addInt(DSQL_close); + this._queueEvent(callback); +}; + +function describe(ret, statement){ + + var br = new BlrReader(ret.buffer); + var parameters = null; + var type, param; + + while (br.pos < br.buffer.length) { + switch (br.readByteCode()) { + case isc_info_sql_stmt_type: + statement.type = br.readInt(); + break; + case isc_info_sql_get_plan: + statement.plan = br.readString(DEFAULT_ENCODING); + break; + case isc_info_sql_select: + statement.output = parameters = []; + break; + case isc_info_sql_bind: + statement.input = parameters = []; + break; + case isc_info_sql_num_variables: + br.readInt(); // eat int + break; + case isc_info_sql_describe_vars: + if (!parameters) {return} + br.readInt(); // eat int ? + var finishDescribe = false; + param = null; + while (!finishDescribe){ + switch (br.readByteCode()) { + case isc_info_sql_describe_end: + break; + case isc_info_sql_sqlda_seq: + var num = br.readInt(); + break; + case isc_info_sql_type: + type = br.readInt(); + switch (type&~1) { + case SQL_VARYING: param = new SQLVarString(); break; + case SQL_NULL: param = new SQLVarNull(); break; + case SQL_TEXT: param = new SQLVarText(); break; + case SQL_DOUBLE: param = new SQLVarDouble(); break; + case SQL_FLOAT: + case SQL_D_FLOAT: param = new SQLVarFloat(); break; + case SQL_TYPE_DATE: param = new SQLVarDate(); break; + case SQL_TYPE_TIME: param = new SQLVarTime(); break; + case SQL_TIMESTAMP: param = new SQLVarTimeStamp(); break; + case SQL_BLOB: param = new SQLVarBlob(); break; + case SQL_ARRAY: param = new SQLVarArray(); break; + case SQL_QUAD: param = new SQLVarQuad(); break; + case SQL_LONG: param = new SQLVarInt(); break; + case SQL_SHORT: param = new SQLVarShort(); break; + case SQL_INT64: param = new SQLVarInt64(); break; + case SQL_BOOLEAN: param = new SQLVarBoolean(); break; + default: + throw new Error('Unexpected'); + } + parameters[num-1] = param; + param.type = type; + param.nullable = Boolean(param.type & 1); + param.type &= ~1; + break; + case isc_info_sql_sub_type: + param.subType = br.readInt(); + break; + case isc_info_sql_scale: + param.scale = br.readInt(); + break; + case isc_info_sql_length: + param.length = br.readInt(); + break; + case isc_info_sql_null_ind: + param.nullable = Boolean(br.readInt()); + break; + case isc_info_sql_field: + param.field = br.readString(DEFAULT_ENCODING); + break; + case isc_info_sql_relation: + param.relation = br.readString(DEFAULT_ENCODING); + break; + case isc_info_sql_owner: + param.owner = br.readString(DEFAULT_ENCODING); + break; + case isc_info_sql_alias: + param.alias = br.readString(DEFAULT_ENCODING); + break; + case isc_info_sql_relation_alias: + param.relationAlias = br.readString(DEFAULT_ENCODING); + break; + case isc_info_truncated: + throw new Error('Truncated'); + default: + finishDescribe = true; + br.pos--; + } + } + } + } +} + +Connection.prototype.prepareStatement = function (transaction, statement, query, plan, callback) { + + if (this._isClosed) + return this.throwClosed(callback); + + var msg = this._msg; + var blr = this._blr; + + msg.pos = 0; + blr.pos = 0; + + if (plan instanceof Function) { + callback = plan; + plan = false; + } + + blr.addBytes(DESCRIBE); + + if (plan) + blr.addByte(isc_info_sql_get_plan); + + msg.addInt(op_prepare_statement); + msg.addInt(transaction.handle); + msg.addInt(statement.handle); + msg.addInt(3); // dialect = 3 + msg.addString(query, DEFAULT_ENCODING); + msg.addBlr(blr); + msg.addInt(65535); // buffer_length + + var self = this; + + this._queueEvent(function(err, ret) { + + if (!err) { + describe(ret, statement); + statement.query = query; + self.db.emit('query', query); + ret = statement; + } + + if (callback) + callback(err, ret); + }); + +}; + +function CalcBlr(blr, xsqlda) { + blr.addBytes([blr_version5, blr_begin, blr_message, 0]); // + message number + blr.addWord(xsqlda.length * 2); + + for (var i = 0, length = xsqlda.length; i < length; i++) { + xsqlda[i].calcBlr(blr); + blr.addByte(blr_short); + blr.addByte(0); + } + + blr.addByte(blr_end); + blr.addByte(blr_eoc); +} + +Connection.prototype.executeStatement = function(transaction, statement, params, callback, custom) { + + if (this._isClosed) + return this.throwClosed(callback); + + // for auto detach + this._pending.push('executeStatement'); + + if (params instanceof Function) { + callback = params; + params = undefined; + } + + var self = this; + + function PrepareParams(params, input, callback) { + + var value, meta; + var ret = new Array(params.length); + var wait = params.length; + + function done() { + wait--; + if (wait === 0) + callback(ret); + } + + function putBlobData(index, value, callback) { + + self.createBlob2(transaction, function(err, blob) { + + var b; + var isStream = value.Readable; + + if (Buffer.isBuffer(value)) + b = value; + else if (typeof(value) === 'string') + b = new Buffer(value, DEFAULT_ENCODING) + else if (!isStream) + b = new Buffer(JSON.stringify(value), DEFAULT_ENCODING) + + if (Buffer.isBuffer(value)) { + bufferReader(b, 1024, function(b, next) { + self.batchSegments(blob, b, next); + }, function() { + ret[index] = new SQLParamQuad(blob.oid); + self.closeBlob(blob, callback); + }); + return; + } + + var isReading = false; + var isEnd = false; + + value.on('data', function(chunk) { + value.pause(); + isReading = true; + bufferReader(chunk, 1024, function(b, next) { + self.batchSegments(blob, b, next); + }, function() { + isReading = false; + + if (isEnd) { + ret[index] = new SQLParamQuad(blob.oid); + self.closeBlob(blob, callback); + } else + value.resume(); + }); + }); + + value.on('end', function() { + isEnd = true; + if (isReading) + return; + ret[index] = new SQLParamQuad(blob.oid); + self.closeBlob(blob, callback); + }); + }); + } + + for (var i = 0, length = params.length; i < length; i++) { + value = params[i]; + meta = input[i]; + + if (value === null) { + switch (meta.type) { + case SQL_VARYING: + case SQL_NULL: + case SQL_TEXT: + ret[i] = new SQLParamString(null); + break; + case SQL_DOUBLE: + case SQL_FLOAT: + case SQL_D_FLOAT: + ret[i] = new SQLParamDouble(null); + break; + case SQL_TYPE_DATE: + case SQL_TYPE_TIME: + case SQL_TIMESTAMP: + ret[i] = new SQLParamDate(null); + break; + case SQL_BLOB: + case SQL_ARRAY: + case SQL_QUAD: + ret[i] = new SQLParamQuad(null); + break; + case SQL_LONG: + case SQL_SHORT: + case SQL_INT64: + case SQL_BOOLEAN: + ret[i] = new SQLParamInt(null); + break; + default: + ret[i] = null; + } + done(); + } else { + switch (meta.type) { + case SQL_BLOB: + putBlobData(i, value, done); + break; + + case SQL_TIMESTAMP: + case SQL_TYPE_DATE: + case SQL_TYPE_TIME: + + if (value instanceof Date) + ret[i] = new SQLParamDate(value); + else if (typeof(value) === 'string') + ret[i] = new SQLParamDate(value.parseDate()); + else + ret[i] = new SQLParamDate(new Date(value)); + + done(); + break; + + default: + switch (typeof value) { + case 'number': + if (value % 1 === 0) { + if (value >= MIN_INT && value <= MAX_INT) + ret[i] = new SQLParamInt(value); + else + ret[i] = new SQLParamInt64(value); + } else + ret[i] = new SQLParamDouble(value); + break; + case 'string': + ret[i] = new SQLParamString(value); + break; + case 'boolean': + ret[i] = new SQLParamBool(value); + break; + default: + throw new Error('Unexpected parametter'); + } + done(); + } + } + } + } + + var input = statement.input; + + if (input.length) { + + if (!(params instanceof Array)) { + if (params !== undefined) + params = [params]; + else + params = []; + } + + if (params === undefined || params.length !== input.length) + throw new Error('Expected parameters: ' + input.length); + + PrepareParams(params, input, function(prms) { + + var msg = self._msg; + var blr = self._blr; + msg.pos = 0; + blr.pos = 0; + CalcBlr(blr, prms); + + msg.addInt(op_execute); + msg.addInt(statement.handle); + msg.addInt(transaction.handle); + msg.addBlr(blr); + msg.addInt(0); // message number + msg.addInt(1); // param count + + for(var i = 0, length = prms.length; i < length; i++) + prms[i].encode(msg); + + self._queueEvent(callback); + }); + + return; + } + + var msg = this._msg; + var blr = this._blr; + msg.pos = 0; + blr.pos = 0; + + msg.addInt(op_execute); + msg.addInt(statement.handle); + msg.addInt(transaction.handle); + + msg.addBlr(blr); // empty + msg.addInt(0); // message number + msg.addInt(0); // param count + + this._queueEvent(callback); +}; + +function fetch_blob_async(statement, id, name) { + + if (!id) + return null; + + return function(callback) { + // callback(err, buffer, name); + statement.connection.startTransaction(ISOLATION_READ_UNCOMMITTED, function(err, transaction) { + + if (err) { + callback(err); + return; + } + + statement.connection._pending.push('openBlob'); + statement.connection.openBlob(id, transaction, function(err, blob) { + + var e = new Events.EventEmitter(); + + if (err) { + callback(err, name, e); + return; + } + + function read() { + statement.connection.getSegment(blob, function(err, ret) { + + if (err) { + e.emit('error', err); + return; + } + + var blr = new BlrReader(ret.buffer); + var data = blr.readSegment(); + + e.emit('data', data); + + if (ret.handle !== 2) { + read(); + return; + } + + e.emit('end'); + e = null; + statement.connection.closeBlob(blob); + + }); + } + + callback(err, name, e); + read(); + + }); + }); + }; +} + +Connection.prototype.fetch = function(statement, transaction, count, callback) { + + var msg = this._msg; + var blr = this._blr; + + msg.pos = 0; + blr.pos = 0; + + if (count instanceof Function) { + callback = count; + count = DEFAULT_FETCHSIZE; + } + + msg.addInt(op_fetch); + msg.addInt(statement.handle); + CalcBlr(blr, statement.output); + msg.addBlr(blr); + msg.addInt(0); // message number + msg.addInt(count || DEFAULT_FETCHSIZE); // fetch count + + if (!transaction) { + callback.statement = statement; + this._queueEvent(callback); + return; + } + + callback.statement = statement; + this._queueEvent(callback); +}; + +Connection.prototype.fetchAll = function(statement, transaction, callback) { + + var self = this; + var data; + var loop = function(err, ret) { + + if (err) { + callback(err); + return; + } + + if (!data) { + data = ret.data; + } else { + for (var i = 0, length = ret.data.length; i < length; i++) + data.push(ret.data[i]); + } + + if (ret.fetched) + callback(undefined, data); + else + self.fetch(statement, transaction, DEFAULT_FETCHSIZE, loop); + } + + this.fetch(statement, transaction, DEFAULT_FETCHSIZE, loop); +}; + +Connection.prototype.openBlob = function(blob, transaction, callback) { + var msg = this._msg; + msg.pos = 0; + msg.addInt(op_open_blob); + msg.addInt(transaction.handle); + msg.addQuad(blob); + this._queueEvent(callback); +}; + +Connection.prototype.closeBlob = function(blob, callback) { + var msg = this._msg; + msg.pos = 0; + msg.addInt(op_close_blob); + msg.addInt(blob.handle); + this._queueEvent(callback); +}; + +Connection.prototype.getSegment = function(blob, callback) { + var msg = this._msg; + msg.pos = 0; + msg.addInt(op_get_segment); + msg.addInt(blob.handle); + msg.addInt(1024); // buffer length + msg.addInt(0); // ??? + this._queueEvent(callback); +}; + +Connection.prototype.createBlob2 = function (transaction, callback) { + var msg = this._msg; + msg.pos = 0; + msg.addInt(op_create_blob2); + msg.addInt(0); + msg.addInt(transaction.handle); + msg.addInt(0); + msg.addInt(0); + this._queueEvent(callback); +}; + +Connection.prototype.batchSegments = function(blob, buffer, callback){ + var msg = this._msg; + var blr = this._blr; + msg.pos = 0; + blr.pos = 0; + msg.addInt(op_batch_segments); + msg.addInt(blob.handle); + msg.addInt(buffer.length + 2); + blr.addBuffer(buffer); + msg.addBlr(blr); + this._queueEvent(callback); +}; + +function bufferReader(buffer, max, writer, cb, beg, end) { + + if (!beg) + beg = 0; + + if (!end) + end = max; + + if (end >= buffer.length) + end = undefined; + + var b = buffer.slice(beg, end); + + writer(b, function() { + + if (end === undefined) { + cb(); + return; + } + + bufferReader(buffer, max, writer, cb, beg + max, end + max); + }); +} \ No newline at end of file diff --git a/node_modules/node-firebird/lib/long.js b/node_modules/node-firebird/lib/long.js new file mode 100644 index 0000000..43e0b79 --- /dev/null +++ b/node_modules/node-firebird/lib/long.js @@ -0,0 +1,855 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Copyright 2009 Google Inc. All Rights Reserved + +/** + * Defines a Long class for representing a 64-bit two's-complement + * integer value, which faithfully simulates the behavior of a Java "Long". This + * implementation is derived from LongLib in GWT. + * + * Constructs a 64-bit two's-complement integer, given its low and high 32-bit + * values as *signed* integers. See the from* functions below for more + * convenient ways of constructing Longs. + * + * The internal representation of a Long is the two given signed, 32-bit values. + * We use 32-bit pieces because these are the size of integers on which + * Javascript performs bit-operations. For operations like addition and + * multiplication, we split each number into 16-bit pieces, which can easily be + * multiplied within Javascript's floating-point representation without overflow + * or change in sign. + * + * In the algorithms below, we frequently reduce the negative case to the + * positive case by negating the input(s) and then post-processing the result. + * Note that we must ALWAYS check specially whether those values are MIN_VALUE + * (-2^63) because -MIN_VALUE == MIN_VALUE (since 2^63 cannot be represented as + * a positive number, it overflows back into a negative). Not handling this + * case would often result in infinite recursion. + * + * @class Represents the BSON Long type. + * @param {Number} low the low (signed) 32 bits of the Long. + * @param {Number} high the high (signed) 32 bits of the Long. + */ +function Long(low, high) { + + if (!(this instanceof Long)) + return new Long(low, high); + + /** + * @type {number} + * @api private + */ + this.low_ = low | 0; // force into 32 signed bits. + + /** + * @type {number} + * @api private + */ + this.high_ = high | 0; // force into 32 signed bits. +}; + +/** + * Return the int value. + * + * @return {Number} the value, assuming it is a 32-bit integer. + * @api public + */ +Long.prototype.toInt = function() { + return this.low_; +}; + +/** + * Return the Number value. + * + * @return {Number} the closest floating-point representation to this value. + * @api public + */ +Long.prototype.toNumber = function() { + return this.high_ * Long.TWO_PWR_32_DBL_ + + this.getLowBitsUnsigned(); +}; + +/** + * Return the JSON value. + * + * @return {String} the JSON representation. + * @api public + */ +Long.prototype.toJSON = function() { + return this.toString(); +} + +/** + * Return the String value. + * + * @param {Number} [opt_radix] the radix in which the text should be written. + * @return {String} the textual representation of this value. + * @api public + */ +Long.prototype.toString = function(opt_radix) { + var radix = opt_radix || 10; + if (radix < 2 || 36 < radix) + throw Error('radix out of range: ' + radix); + + if (this.isZero()) + return '0'; + + if (this.isNegative()) { + if (this.equals(Long.MIN_VALUE)) { + // We need to change the Long value before it can be negated, so we remove + // the bottom-most digit in this base and then recurse to do the rest. + var radixLong = Long.fromNumber(radix); + var div = this.div(radixLong); + var rem = div.multiply(radixLong).subtract(this); + return div.toString(radix) + rem.toInt().toString(radix); + } else { + return '-' + this.negate().toString(radix); + } + } + + // Do several (6) digits each time through the loop, so as to + // minimize the calls to the very expensive emulated div. + var radixToPower = Long.fromNumber(Math.pow(radix, 6)); + + var rem = this; + var result = ''; + while (true) { + var remDiv = rem.div(radixToPower); + var intval = rem.subtract(remDiv.multiply(radixToPower)).toInt(); + var digits = intval.toString(radix); + + rem = remDiv; + if (rem.isZero()) { + return digits + result; + } else { + while (digits.length < 6) { + digits = '0' + digits; + } + result = '' + digits + result; + } + } +}; + +/** + * Return the high 32-bits value. + * + * @return {Number} the high 32-bits as a signed value. + * @api public + */ +Long.prototype.getHighBits = function() { + return this.high_; +}; + +/** + * Return the low 32-bits value. + * + * @return {Number} the low 32-bits as a signed value. + * @api public + */ +Long.prototype.getLowBits = function() { + return this.low_; +}; + +/** + * Return the low unsigned 32-bits value. + * + * @return {Number} the low 32-bits as an unsigned value. + * @api public + */ +Long.prototype.getLowBitsUnsigned = function() { + return (this.low_ >= 0) ? + this.low_ : Long.TWO_PWR_32_DBL_ + this.low_; +}; + +/** + * Returns the number of bits needed to represent the absolute value of this Long. + * + * @return {Number} Returns the number of bits needed to represent the absolute value of this Long. + * @api public + */ +Long.prototype.getNumBitsAbs = function() { + if (this.isNegative()) { + if (this.equals(Long.MIN_VALUE)) { + return 64; + } else { + return this.negate().getNumBitsAbs(); + } + } else { + var val = this.high_ != 0 ? this.high_ : this.low_; + for (var bit = 31; bit > 0; bit--) { + if ((val & (1 << bit)) != 0) { + break; + } + } + return this.high_ != 0 ? bit + 33 : bit + 1; + } +}; + +/** + * Return whether this value is zero. + * + * @return {Boolean} whether this value is zero. + * @api public + */ +Long.prototype.isZero = function() { + return this.high_ == 0 && this.low_ == 0; +}; + +/** + * Return whether this value is negative. + * + * @return {Boolean} whether this value is negative. + * @api public + */ +Long.prototype.isNegative = function() { + return this.high_ < 0; +}; + +/** + * Return whether this value is odd. + * + * @return {Boolean} whether this value is odd. + * @api public + */ +Long.prototype.isOdd = function() { + return (this.low_ & 1) == 1; +}; + +/** + * Return whether this Long equals the other + * + * @param {Long} other Long to compare against. + * @return {Boolean} whether this Long equals the other + * @api public + */ +Long.prototype.equals = function(other) { + return (this.high_ == other.high_) && (this.low_ == other.low_); +}; + +/** + * Return whether this Long does not equal the other. + * + * @param {Long} other Long to compare against. + * @return {Boolean} whether this Long does not equal the other. + * @api public + */ +Long.prototype.notEquals = function(other) { + return (this.high_ != other.high_) || (this.low_ != other.low_); +}; + +/** + * Return whether this Long is less than the other. + * + * @param {Long} other Long to compare against. + * @return {Boolean} whether this Long is less than the other. + * @api public + */ +Long.prototype.lessThan = function(other) { + return this.compare(other) < 0; +}; + +/** + * Return whether this Long is less than or equal to the other. + * + * @param {Long} other Long to compare against. + * @return {Boolean} whether this Long is less than or equal to the other. + * @api public + */ +Long.prototype.lessThanOrEqual = function(other) { + return this.compare(other) <= 0; +}; + +/** + * Return whether this Long is greater than the other. + * + * @param {Long} other Long to compare against. + * @return {Boolean} whether this Long is greater than the other. + * @api public + */ +Long.prototype.greaterThan = function(other) { + return this.compare(other) > 0; +}; + +/** + * Return whether this Long is greater than or equal to the other. + * + * @param {Long} other Long to compare against. + * @return {Boolean} whether this Long is greater than or equal to the other. + * @api public + */ +Long.prototype.greaterThanOrEqual = function(other) { + return this.compare(other) >= 0; +}; + +/** + * Compares this Long with the given one. + * + * @param {Long} other Long to compare against. + * @return {Boolean} 0 if they are the same, 1 if the this is greater, and -1 if the given one is greater. + * @api public + */ +Long.prototype.compare = function(other) { + if (this.equals(other)) { + return 0; + } + + var thisNeg = this.isNegative(); + var otherNeg = other.isNegative(); + if (thisNeg && !otherNeg) { + return -1; + } + if (!thisNeg && otherNeg) { + return 1; + } + + // at this point, the signs are the same, so subtraction will not overflow + if (this.subtract(other).isNegative()) { + return -1; + } else { + return 1; + } +}; + +/** + * The negation of this value. + * + * @return {Long} the negation of this value. + * @api public + */ +Long.prototype.negate = function() { + if (this.equals(Long.MIN_VALUE)) { + return Long.MIN_VALUE; + } else { + return this.not().add(Long.ONE); + } +}; + +/** + * Returns the sum of this and the given Long. + * + * @param {Long} other Long to add to this one. + * @return {Long} the sum of this and the given Long. + * @api public + */ +Long.prototype.add = function(other) { + // Divide each number into 4 chunks of 16 bits, and then sum the chunks. + + var a48 = this.high_ >>> 16; + var a32 = this.high_ & 0xFFFF; + var a16 = this.low_ >>> 16; + var a00 = this.low_ & 0xFFFF; + + var b48 = other.high_ >>> 16; + var b32 = other.high_ & 0xFFFF; + var b16 = other.low_ >>> 16; + var b00 = other.low_ & 0xFFFF; + + var c48 = 0, c32 = 0, c16 = 0, c00 = 0; + c00 += a00 + b00; + c16 += c00 >>> 16; + c00 &= 0xFFFF; + c16 += a16 + b16; + c32 += c16 >>> 16; + c16 &= 0xFFFF; + c32 += a32 + b32; + c48 += c32 >>> 16; + c32 &= 0xFFFF; + c48 += a48 + b48; + c48 &= 0xFFFF; + return Long.fromBits((c16 << 16) | c00, (c48 << 16) | c32); +}; + +/** + * Returns the difference of this and the given Long. + * + * @param {Long} other Long to subtract from this. + * @return {Long} the difference of this and the given Long. + * @api public + */ +Long.prototype.subtract = function(other) { + return this.add(other.negate()); +}; + +/** + * Returns the product of this and the given Long. + * + * @param {Long} other Long to multiply with this. + * @return {Long} the product of this and the other. + * @api public + */ +Long.prototype.multiply = function(other) { + if (this.isZero()) { + return Long.ZERO; + } else if (other.isZero()) { + return Long.ZERO; + } + + if (this.equals(Long.MIN_VALUE)) { + return other.isOdd() ? Long.MIN_VALUE : Long.ZERO; + } else if (other.equals(Long.MIN_VALUE)) { + return this.isOdd() ? Long.MIN_VALUE : Long.ZERO; + } + + if (this.isNegative()) { + if (other.isNegative()) { + return this.negate().multiply(other.negate()); + } else { + return this.negate().multiply(other).negate(); + } + } else if (other.isNegative()) { + return this.multiply(other.negate()).negate(); + } + + // If both Longs are small, use float multiplication + if (this.lessThan(Long.TWO_PWR_24_) && + other.lessThan(Long.TWO_PWR_24_)) { + return Long.fromNumber(this.toNumber() * other.toNumber()); + } + + // Divide each Long into 4 chunks of 16 bits, and then add up 4x4 products. + // We can skip products that would overflow. + + var a48 = this.high_ >>> 16; + var a32 = this.high_ & 0xFFFF; + var a16 = this.low_ >>> 16; + var a00 = this.low_ & 0xFFFF; + + var b48 = other.high_ >>> 16; + var b32 = other.high_ & 0xFFFF; + var b16 = other.low_ >>> 16; + var b00 = other.low_ & 0xFFFF; + + var c48 = 0, c32 = 0, c16 = 0, c00 = 0; + c00 += a00 * b00; + c16 += c00 >>> 16; + c00 &= 0xFFFF; + c16 += a16 * b00; + c32 += c16 >>> 16; + c16 &= 0xFFFF; + c16 += a00 * b16; + c32 += c16 >>> 16; + c16 &= 0xFFFF; + c32 += a32 * b00; + c48 += c32 >>> 16; + c32 &= 0xFFFF; + c32 += a16 * b16; + c48 += c32 >>> 16; + c32 &= 0xFFFF; + c32 += a00 * b32; + c48 += c32 >>> 16; + c32 &= 0xFFFF; + c48 += a48 * b00 + a32 * b16 + a16 * b32 + a00 * b48; + c48 &= 0xFFFF; + return Long.fromBits((c16 << 16) | c00, (c48 << 16) | c32); +}; + +/** + * Returns this Long divided by the given one. + * + * @param {Long} other Long by which to divide. + * @return {Long} this Long divided by the given one. + * @api public + */ +Long.prototype.div = function(other) { + if (other.isZero()) { + throw Error('division by zero'); + } else if (this.isZero()) { + return Long.ZERO; + } + + if (this.equals(Long.MIN_VALUE)) { + if (other.equals(Long.ONE) || + other.equals(Long.NEG_ONE)) { + return Long.MIN_VALUE; // recall that -MIN_VALUE == MIN_VALUE + } else if (other.equals(Long.MIN_VALUE)) { + return Long.ONE; + } else { + // At this point, we have |other| >= 2, so |this/other| < |MIN_VALUE|. + var halfThis = this.shiftRight(1); + var approx = halfThis.div(other).shiftLeft(1); + if (approx.equals(Long.ZERO)) { + return other.isNegative() ? Long.ONE : Long.NEG_ONE; + } else { + var rem = this.subtract(other.multiply(approx)); + var result = approx.add(rem.div(other)); + return result; + } + } + } else if (other.equals(Long.MIN_VALUE)) { + return Long.ZERO; + } + + if (this.isNegative()) { + if (other.isNegative()) { + return this.negate().div(other.negate()); + } else { + return this.negate().div(other).negate(); + } + } else if (other.isNegative()) { + return this.div(other.negate()).negate(); + } + + // Repeat the following until the remainder is less than other: find a + // floating-point that approximates remainder / other *from below*, add this + // into the result, and subtract it from the remainder. It is critical that + // the approximate value is less than or equal to the real value so that the + // remainder never becomes negative. + var res = Long.ZERO; + var rem = this; + while (rem.greaterThanOrEqual(other)) { + // Approximate the result of division. This may be a little greater or + // smaller than the actual value. + var approx = Math.max(1, Math.floor(rem.toNumber() / other.toNumber())); + + // We will tweak the approximate result by changing it in the 48-th digit or + // the smallest non-fractional digit, whichever is larger. + var log2 = Math.ceil(Math.log(approx) / Math.LN2); + var delta = (log2 <= 48) ? 1 : Math.pow(2, log2 - 48); + + // Decrease the approximation until it is smaller than the remainder. Note + // that if it is too large, the product overflows and is negative. + var approxRes = Long.fromNumber(approx); + var approxRem = approxRes.multiply(other); + while (approxRem.isNegative() || approxRem.greaterThan(rem)) { + approx -= delta; + approxRes = Long.fromNumber(approx); + approxRem = approxRes.multiply(other); + } + + // We know the answer can't be zero... and actually, zero would cause + // infinite recursion since we would make no progress. + if (approxRes.isZero()) { + approxRes = Long.ONE; + } + + res = res.add(approxRes); + rem = rem.subtract(approxRem); + } + return res; +}; + +/** + * Returns this Long modulo the given one. + * + * @param {Long} other Long by which to mod. + * @return {Long} this Long modulo the given one. + * @api public + */ +Long.prototype.modulo = function(other) { + return this.subtract(this.div(other).multiply(other)); +}; + +/** + * The bitwise-NOT of this value. + * + * @return {Long} the bitwise-NOT of this value. + * @api public + */ +Long.prototype.not = function() { + return Long.fromBits(~this.low_, ~this.high_); +}; + +/** + * Returns the bitwise-AND of this Long and the given one. + * + * @param {Long} other the Long with which to AND. + * @return {Long} the bitwise-AND of this and the other. + * @api public + */ +Long.prototype.and = function(other) { + return Long.fromBits(this.low_ & other.low_, this.high_ & other.high_); +}; + +/** + * Returns the bitwise-OR of this Long and the given one. + * + * @param {Long} other the Long with which to OR. + * @return {Long} the bitwise-OR of this and the other. + * @api public + */ +Long.prototype.or = function(other) { + return Long.fromBits(this.low_ | other.low_, this.high_ | other.high_); +}; + +/** + * Returns the bitwise-XOR of this Long and the given one. + * + * @param {Long} other the Long with which to XOR. + * @return {Long} the bitwise-XOR of this and the other. + * @api public + */ +Long.prototype.xor = function(other) { + return Long.fromBits(this.low_ ^ other.low_, this.high_ ^ other.high_); +}; + +/** + * Returns this Long with bits shifted to the left by the given amount. + * + * @param {Number} numBits the number of bits by which to shift. + * @return {Long} this shifted to the left by the given amount. + * @api public + */ +Long.prototype.shiftLeft = function(numBits) { + numBits &= 63; + if (numBits == 0) { + return this; + } else { + var low = this.low_; + if (numBits < 32) { + var high = this.high_; + return Long.fromBits( + low << numBits, + (high << numBits) | (low >>> (32 - numBits))); + } else { + return Long.fromBits(0, low << (numBits - 32)); + } + } +}; + +/** + * Returns this Long with bits shifted to the right by the given amount. + * + * @param {Number} numBits the number of bits by which to shift. + * @return {Long} this shifted to the right by the given amount. + * @api public + */ +Long.prototype.shiftRight = function(numBits) { + numBits &= 63; + if (numBits == 0) { + return this; + } else { + var high = this.high_; + if (numBits < 32) { + var low = this.low_; + return Long.fromBits( + (low >>> numBits) | (high << (32 - numBits)), + high >> numBits); + } else { + return Long.fromBits( + high >> (numBits - 32), + high >= 0 ? 0 : -1); + } + } +}; + +/** + * Returns this Long with bits shifted to the right by the given amount, with the new top bits matching the current sign bit. + * + * @param {Number} numBits the number of bits by which to shift. + * @return {Long} this shifted to the right by the given amount, with zeros placed into the new leading bits. + * @api public + */ +Long.prototype.shiftRightUnsigned = function(numBits) { + numBits &= 63; + if (numBits == 0) { + return this; + } else { + var high = this.high_; + if (numBits < 32) { + var low = this.low_; + return Long.fromBits( + (low >>> numBits) | (high << (32 - numBits)), + high >>> numBits); + } else if (numBits == 32) { + return Long.fromBits(high, 0); + } else { + return Long.fromBits(high >>> (numBits - 32), 0); + } + } +}; + +/** + * Returns a Long representing the given (32-bit) integer value. + * + * @param {Number} value the 32-bit integer in question. + * @return {Long} the corresponding Long value. + * @api public + */ +Long.fromInt = function(value) { + if (-128 <= value && value < 128) { + var cachedObj = Long.INT_CACHE_[value]; + if (cachedObj) { + return cachedObj; + } + } + + var obj = new Long(value | 0, value < 0 ? -1 : 0); + if (-128 <= value && value < 128) { + Long.INT_CACHE_[value] = obj; + } + return obj; +}; + +/** + * Returns a Long representing the given value, provided that it is a finite number. Otherwise, zero is returned. + * + * @param {Number} value the number in question. + * @return {Long} the corresponding Long value. + * @api public + */ +Long.fromNumber = function(value) { + if (isNaN(value) || !isFinite(value)) { + return Long.ZERO; + } else if (value <= -Long.TWO_PWR_63_DBL_) { + return Long.MIN_VALUE; + } else if (value + 1 >= Long.TWO_PWR_63_DBL_) { + return Long.MAX_VALUE; + } else if (value < 0) { + return Long.fromNumber(-value).negate(); + } else { + return new Long( + (value % Long.TWO_PWR_32_DBL_) | 0, + (value / Long.TWO_PWR_32_DBL_) | 0); + } +}; + +/** + * Returns a Long representing the 64-bit integer that comes by concatenating the given high and low bits. Each is assumed to use 32 bits. + * + * @param {Number} lowBits the low 32-bits. + * @param {Number} highBits the high 32-bits. + * @return {Long} the corresponding Long value. + * @api public + */ +Long.fromBits = function(lowBits, highBits) { + return new Long(lowBits, highBits); +}; + +/** + * Returns a Long representation of the given string, written using the given radix. + * + * @param {String} str the textual representation of the Long. + * @param {Number} opt_radix the radix in which the text is written. + * @return {Long} the corresponding Long value. + * @api public + */ +Long.fromString = function(str, opt_radix) { + if (str.length == 0) { + throw Error('number format error: empty string'); + } + + var radix = opt_radix || 10; + if (radix < 2 || 36 < radix) { + throw Error('radix out of range: ' + radix); + } + + if (str.charAt(0) == '-') { + return Long.fromString(str.substring(1), radix).negate(); + } else if (str.indexOf('-') >= 0) { + throw Error('number format error: interior "-" character: ' + str); + } + + // Do several (8) digits each time through the loop, so as to + // minimize the calls to the very expensive emulated div. + var radixToPower = Long.fromNumber(Math.pow(radix, 8)); + + var result = Long.ZERO; + for (var i = 0; i < str.length; i += 8) { + var size = Math.min(8, str.length - i); + var value = parseInt(str.substring(i, i + size), radix); + if (size < 8) { + var power = Long.fromNumber(Math.pow(radix, size)); + result = result.multiply(power).add(Long.fromNumber(value)); + } else { + result = result.multiply(radixToPower); + result = result.add(Long.fromNumber(value)); + } + } + return result; +}; + +// NOTE: Common constant values ZERO, ONE, NEG_ONE, etc. are defined below the +// from* methods on which they depend. + + +/** + * A cache of the Long representations of small integer values. + * @type {Object} + * @api private + */ +Long.INT_CACHE_ = {}; + +// NOTE: the compiler should inline these constant values below and then remove +// these variables, so there should be no runtime penalty for these. + +/** + * Number used repeated below in calculations. This must appear before the + * first call to any from* function below. + * @type {number} + * @api private + */ +Long.TWO_PWR_16_DBL_ = 1 << 16; + +/** + * @type {number} + * @api private + */ +Long.TWO_PWR_24_DBL_ = 1 << 24; + +/** + * @type {number} + * @api private + */ +Long.TWO_PWR_32_DBL_ = Long.TWO_PWR_16_DBL_ * Long.TWO_PWR_16_DBL_; + +/** + * @type {number} + * @api private + */ +Long.TWO_PWR_31_DBL_ = Long.TWO_PWR_32_DBL_ / 2; + +/** + * @type {number} + * @api private + */ +Long.TWO_PWR_48_DBL_ = Long.TWO_PWR_32_DBL_ * Long.TWO_PWR_16_DBL_; + +/** + * @type {number} + * @api private + */ +Long.TWO_PWR_64_DBL_ = Long.TWO_PWR_32_DBL_ * Long.TWO_PWR_32_DBL_; + +/** + * @type {number} + * @api private + */ +Long.TWO_PWR_63_DBL_ = Long.TWO_PWR_64_DBL_ / 2; + +/** @type {Long} */ +Long.ZERO = Long.fromInt(0); + +/** @type {Long} */ +Long.ONE = Long.fromInt(1); + +/** @type {Long} */ +Long.NEG_ONE = Long.fromInt(-1); + +/** @type {Long} */ +Long.MAX_VALUE = + Long.fromBits(0xFFFFFFFF | 0, 0x7FFFFFFF | 0); + +/** @type {Long} */ +Long.MIN_VALUE = Long.fromBits(0, 0x80000000 | 0); + +/** + * @type {Long} + * @api private + */ +Long.TWO_PWR_24_ = Long.fromInt(1 << 24); + +/** + * Expose. + */ +if(typeof window === 'undefined') { + exports.Long = Long; +} \ No newline at end of file diff --git a/node_modules/node-firebird/lib/messages.js b/node_modules/node-firebird/lib/messages.js new file mode 100644 index 0000000..3348a2a --- /dev/null +++ b/node_modules/node-firebird/lib/messages.js @@ -0,0 +1,162 @@ +var fs = require('fs'); + +const + //ISC_MASK = 0x14000000, // Defines the code as a valid ISC code + FAC_MASK = 0x00FF0000, // Specifies the facility where the code is located + CODE_MASK = 0x0000FFFF, // Specifies the code in the message file + CLASS_MASK = 0xF0000000; // Defines the code as warning, error, info, or other + +var msgNumber = exports.msgNumber = function(facility, code) { + return (facility * 10000 + code); +}; + +var getCode = exports.getCode = function(code) { + return (code & CODE_MASK) +}; + +var getFacility = exports.getFacility = function(code) { + return (code & FAC_MASK) >> 16; +}; + +exports.getClass = function(code) { + return (code & CLASS_MASK) >> 30 +}; + +exports.lookupMessages = function(status, callback){ + + var handle; + var bucket_size; + var top_tree; + var levels; + var buffer; + + function lookup(item, callback) { + + var code = msgNumber(getFacility(item.gdscode), getCode(item.gdscode)); + + function readIndex(stackSize, position) { + + function readNode(from) { + var ret = {}; + ret.code = buffer.readUInt32LE(from); + ret.seek = buffer.readUInt32LE(from + 4); + return ret; + } + + fs.read(handle, buffer, 0, bucket_size, position, function(err, bufferSize) { + + if (bufferSize <= 0) { + callback(); + return; + } + + if (stackSize === levels) { + search(); + return; + } + + var from = 0; + var node = readNode(from); + + while (true) { + + if (node.code >= code) + { + readIndex(stackSize + 1, node.seek); + break; + } + + from += 8; + if (from >= bufferSize) + { + callback(); + break; + } + + node = readNode(from); + } + }); + } + + function search() { + + function readRec(from) { + + function align(v) { + return (v + 3) & ~3; + } + + var ret = {}; + ret.code = buffer.readUInt32LE(from); + ret.length = buffer.readUInt16LE(from + 4); + + if (ret.code == code){ + from += 8; + ret.text = buffer.toString(null, from, from + ret.length); + } else + ret.seek = from + align(8 + ret.length, 4); + + return ret; + } + + var rec = readRec(0); + + while (rec.seek) { + if (rec.seek >= buffer.length) + break; + else + rec = readRec(rec.seek); + } + + var str = rec.text; + if (item.params) { + for (var i = 0; i < item.params.length; i++) + str = str.replace('@' + String(i+1), item.params[i]); + } + + callback(str); + } + + readIndex(1, top_tree); + } + + fs.open(__dirname + "/firebird.msg", 'r', function(err, h) { + + if (!h) { + callback(); + return; + } + + buffer = new Buffer(14); + fs.read(h, buffer, 0, 14, 0, function(){ + + handle = h; + bucket_size = buffer.readUInt16LE(2); + top_tree = buffer.readUInt32LE(4); + levels = buffer.readUInt16LE(12); + buffer = new Buffer(bucket_size); + + var i = 0; + var text; + + function loop() { + lookup(status[i], function(line) { + if (text) + text = text + ', ' + line + else + text = line; + + if (i === status.length - 1) { + fs.close(handle); + callback(text); + } else { + i++; + loop(); + } + }); + } + + loop(0); + }); + }); +}; \ No newline at end of file diff --git a/node_modules/node-firebird/lib/serialize.js b/node_modules/node-firebird/lib/serialize.js new file mode 100644 index 0000000..f4013fe --- /dev/null +++ b/node_modules/node-firebird/lib/serialize.js @@ -0,0 +1,361 @@ + +var Long = require('./long.js').Long; + +function align(n) { + return (n + 3) & ~3; +} + +/*************************************** + * + * BLR Writer + * + ***************************************/ + +const + MAX_STRING_SIZE = 255; + +var BlrWriter = exports.BlrWriter = function(size){ + this.buffer = new Buffer(size || 32); + this.pos = 0; +}; + +BlrWriter.prototype.addByte = function (b) { + this.ensure(1); + this.buffer.writeUInt8(b, this.pos); + this.pos++; +}; + +BlrWriter.prototype.addShort = function (b) { + this.ensure(1); + this.buffer.writeInt8(b, this.pos); + this.pos++; +}; + +BlrWriter.prototype.addSmall = function (b) { + this.ensure(2); + this.buffer.writeInt16LE(b, this.pos); + this.pos += 2; +}; + +BlrWriter.prototype.addWord = function (b) { + this.ensure(2); + this.buffer.writeUInt16LE(b, this.pos); + this.pos += 2; +}; + +BlrWriter.prototype.addNumeric = function (c, v) { + + if (v < 256){ + this.ensure(3); + this.buffer.writeUInt8(c, this.pos); + this.pos++; + this.buffer.writeUInt8(1, this.pos); + this.pos++; + this.buffer.writeUInt8(v, this.pos); + this.pos++; + return; + } + + this.ensure(6); + this.buffer.writeUInt8(c, this.pos); + this.pos++; + this.buffer.writeUInt8(4, this.pos); + this.pos++; + this.buffer.writeInt32BE(v, this.pos); + this.pos += 4; + +}; + +BlrWriter.prototype.addBytes = function (b) { + + this.ensure(b.length); + for (var i = 0, length = b.length; i < length; i++) { + this.buffer.writeUInt8(b[i], this.pos); + this.pos++; + } +}; + +BlrWriter.prototype.addString = function (c, s, encoding) { + this.addByte(c); + + var len = Buffer.byteLength(s, encoding); + if (len > MAX_STRING_SIZE) + throw new Error('blr string is too big'); + + this.ensure(len + 1); + this.buffer.writeUInt8(len, this.pos); + this.pos++; + this.buffer.write(s, this.pos, s.length, encoding); + this.pos += len; +}; + +BlrWriter.prototype.addBuffer = function (b) { + this.addSmall(b.length); + this.ensure(b.length); + b.copy(this.buffer, this.pos); + this.pos += b.length; +}; + +/*************************************** + * + * BLR Reader + * + ***************************************/ + +var BlrReader = exports.BlrReader = function(buffer) { + this.buffer = buffer; + this.pos = 0; +}; + +BlrReader.prototype.readByteCode = function(){ + return this.buffer.readUInt8(this.pos++); +}; + +BlrReader.prototype.readInt = function(){ + var len = this.buffer.readUInt16LE(this.pos); + this.pos += 2; + var value; + switch (len) { + case 1: + value = this.buffer.readInt8(this.pos); + break; + case 2: + value = this.buffer.readInt16LE(this.pos); + break; + case 4: + value = this.buffer.readInt32LE(this.pos) + } + this.pos += len; + return value; +}; + +BlrReader.prototype.readString = function(encoding){ + + var len = this.buffer.readUInt16LE(this.pos); + var str; + + this.pos += 2; + if (len <= 0) + return ''; + + str = this.buffer.toString(encoding, this.pos, this.pos + len); + this.pos += len; + return str; +}; + +BlrReader.prototype.readSegment = function() { + + var ret, tmp; + var len = this.buffer.readUInt16LE(this.pos); + + this.pos += 2; + + while (len > 0) { + + if (ret) { + tmp = ret; + ret = new Buffer(tmp.length + len); + tmp.copy(ret); + this.buffer.copy(ret, tmp.length, this.pos, this.pos + len); + } else { + ret = new Buffer(len); + this.buffer.copy(ret, 0, this.pos, this.pos + len); + } + + this.pos += len; + + if (this.pos === this.buffer.length) + break; + + len = this.buffer.readUInt16LE(this.pos); + this.pos += 2; + } + + return ret; +}; + +/*************************************** + * + * XDR Writer + * + ***************************************/ + +var XdrWriter = exports.XdrWriter = function(size){ + this.buffer = new Buffer(size || 32); + this.pos = 0; +}; + +XdrWriter.prototype.ensure = BlrWriter.prototype.ensure = function (len) { + var newlen = this.buffer.length; + + while (newlen < this.pos + len) + newlen *= 2 + + if (this.buffer.length >= newlen) + return; + + var b = new Buffer(newlen); + this.buffer.copy(b); + delete(this.buffer); + this.buffer = b; +}; + +XdrWriter.prototype.addInt = function (value) { + this.ensure(4); + this.buffer.writeInt32BE(value, this.pos); + this.pos += 4; +}; + +XdrWriter.prototype.addInt64 = function (value) { + this.ensure(8); + var l = new Long(value); + this.buffer.writeInt32BE(l.high_, this.pos); + this.pos += 4; + this.buffer.writeInt32BE(l.low_, this.pos); + this.pos += 4; +}; + +XdrWriter.prototype.addUInt = function (value) { + this.ensure(4); + this.buffer.writeUInt32BE(value, this.pos); + this.pos += 4; +}; + +XdrWriter.prototype.addString = function(s, encoding) { + var len = Buffer.byteLength(s, encoding); + var alen = align(len); + this.ensure(alen + 4); + this.buffer.writeInt32BE(len, this.pos); + this.pos += 4; + this.buffer.write(s, this.pos, len, encoding); + this.pos += alen; +}; + +XdrWriter.prototype.addText = function(s, encoding) { + var len = Buffer.byteLength(s, encoding); + var alen = align(len); + this.ensure(alen); + this.buffer.write(s, this.pos, len, encoding); + this.pos += alen; +}; + +XdrWriter.prototype.addBlr = function(blr) { + var alen = align(blr.pos); + this.ensure(alen + 4); + this.buffer.writeInt32BE(blr.pos, this.pos); + this.pos += 4; + blr.buffer.copy(this.buffer, this.pos); + this.pos += alen; +}; + +XdrWriter.prototype.getData = function() { + return this.buffer.slice(0, this.pos); +}; + +XdrWriter.prototype.addDouble = function(value) { + this.ensure(8); + this.buffer.writeDoubleBE(value, this.pos); + this.pos += 8; +}; + +XdrWriter.prototype.addQuad = function(quad) { + this.ensure(8); + var b = this.buffer; + b.writeInt32BE(quad.high, this.pos); + this.pos += 4; + b.writeInt32BE(quad.low, this.pos); + this.pos += 4; +}; + +/*************************************** + * + * XDR Reader + * + ***************************************/ + +var XdrReader = exports.XdrReader = function(buffer){ + this.buffer = buffer; + this.pos = 0; +}; + +XdrReader.prototype.readInt = function () { + var r = this.buffer.readInt32BE(this.pos); + this.pos += 4; + return r; +}; + +XdrReader.prototype.readUInt = function () { + var r = this.buffer.readUInt32BE(this.pos); + this.pos += 4; + return r; +}; + +XdrReader.prototype.readInt64 = function () { + var high = this.buffer.readInt32BE(this.pos); + this.pos += 4; + var low = this.buffer.readInt32BE(this.pos); + this.pos += 4; + return new Long(low, high); +}; + +XdrReader.prototype.readShort = function () { + var r = this.buffer.readInt16BE(this.pos); + this.pos += 2; + return r; +}; + +XdrReader.prototype.readQuad = function () { + var b = this.buffer; + var high = b.readInt32BE(this.pos); + this.pos += 4; + var low = b.readInt32BE(this.pos); + this.pos += 4; + return {low: low, high: high} +}; + +XdrReader.prototype.readFloat = function () { + var r = this.buffer.readFloatBE(this.pos); + this.pos += 4; + return r; +}; + +XdrReader.prototype.readDouble = function () { + var r = this.buffer.readDoubleBE(this.pos); + this.pos += 8; + return r; +}; + +XdrReader.prototype.readArray = function () { + var len = this.readInt(); + if (!len) + return; + var r = this.buffer.slice(this.pos, this.pos + len); + this.pos += align(len); + return r; +}; + +XdrReader.prototype.readBuffer = function (len) { + if (!arguments.length) + len = this.readInt(); + + if (!len) + return; + + var r = this.buffer.slice(this.pos, this.pos + len); + this.pos += align(len); + return r; +}; + +XdrReader.prototype.readString = function (encoding) { + var len = this.readInt(); + return this.readText(len, encoding); +}; + +XdrReader.prototype.readText = function (len, encoding) { + if (len <= 0) + return ''; + + var r = this.buffer.toString(encoding, this.pos, this.pos + len); + this.pos += align(len); + return r; +}; \ No newline at end of file diff --git a/node_modules/node-firebird/package.json b/node_modules/node-firebird/package.json new file mode 100644 index 0000000..624305e --- /dev/null +++ b/node_modules/node-firebird/package.json @@ -0,0 +1,70 @@ +{ + "name": "node-firebird", + "version": "0.2.3", + "description": "Pure JavaScript and Asynchronous Firebird client for Node.js.", + "keywords": [ + "firebird", + "database", + "rdbms", + "sql" + ], + "homepage": "https://github.com/hgourvest/node-firebird", + "repository": { + "type": "git", + "url": "https://github.com/hgourvest/node-firebird" + }, + "author": { + "name": "Henri Gourvest", + "email": "hgourvest@gmail.com" + }, + "contributors": [ + { + "name": "Popa Marius Adrian", + "email": "mapopa@gmail.com" + }, + { + "name": "Peter Širka", + "email": "petersirka@gmail.com" + } + ], + "main": "./lib", + "licenses": [ + { + "type": "MPL-2.0", + "url": "https://raw.githubusercontent.com/hgourvest/node-firebird/master/LICENSE" + } + ], + "gitHead": "39dadf20e203a8300eb766a24deecbfe3757954a", + "bugs": { + "url": "https://github.com/hgourvest/node-firebird/issues" + }, + "_id": "node-firebird@0.2.3", + "scripts": {}, + "_shasum": "5af05dc7575543188b5005a59bd3e10537cff160", + "_from": "node-firebird@", + "_npmVersion": "1.4.28", + "_npmUser": { + "name": "mariuz", + "email": "mapopa@gmail.com" + }, + "maintainers": [ + { + "name": "hgourvest", + "email": "hgourvest@gmail.com" + }, + { + "name": "mariuz", + "email": "mapopa@gmail.com" + }, + { + "name": "petersirka", + "email": "petersirka@gmail.com" + } + ], + "dist": { + "shasum": "5af05dc7575543188b5005a59bd3e10537cff160", + "tarball": "http://registry.npmjs.org/node-firebird/-/node-firebird-0.2.3.tgz" + }, + "directories": {}, + "_resolved": "https://registry.npmjs.org/node-firebird/-/node-firebird-0.2.3.tgz" +} diff --git a/node_modules/node-firebird/test/image.png b/node_modules/node-firebird/test/image.png new file mode 100644 index 0000000000000000000000000000000000000000..1f6799ade830e49d23db26f67ac0b471b910df98 GIT binary patch literal 5472 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 0, name + ': pool pending'); + }); + + query.push(function(next) { + setTimeout(function() { + pool.destroy(); + console.timeEnd(name); + }, 500); + next(); + }); + + query.async(next); +}