├── .gitignore ├── .gitmodules ├── src ├── oracle_bindings.cc ├── query.h ├── oracle.h ├── connection.h ├── result.h ├── query.cc ├── connection.cc ├── oracle.cc └── result.cc ├── tests.js ├── package.json ├── db-oracle.js ├── wscript └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | /build/* 2 | *.node 3 | *.sh 4 | *.swp 5 | .lock* 6 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lib/node-db"] 2 | path = lib/node-db 3 | url = git://github.com/mariano/node-db.git 4 | -------------------------------------------------------------------------------- /src/oracle_bindings.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Mariano Iglesias 2 | #include "./node-db/binding.h" 3 | #include "./oracle.h" 4 | #include "./query.h" 5 | 6 | extern "C" { 7 | void init(v8::Handle target) { 8 | node_db::EventEmitter::Init(); 9 | node_db_oracle::Oracle::Init(target); 10 | node_db_oracle::Query::Init(target); 11 | } 12 | 13 | NODE_MODULE(oracle_bindings, init); 14 | } 15 | -------------------------------------------------------------------------------- /src/query.h: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Mariano Iglesias 2 | #ifndef SRC_QUERY_H_ 3 | #define SRC_QUERY_H_ 4 | 5 | #include "./node-db/node_defs.h" 6 | #include "./node-db/query.h" 7 | 8 | namespace node_db_oracle { 9 | class Query : public node_db::Query { 10 | public: 11 | static v8::Persistent constructorTemplate; 12 | static void Init(v8::Handle target); 13 | 14 | protected: 15 | static v8::Handle New(const v8::Arguments& args); 16 | static v8::Handle Limit(const v8::Arguments& args); 17 | }; 18 | } 19 | 20 | #endif // SRC_QUERY_H_ 21 | -------------------------------------------------------------------------------- /tests.js: -------------------------------------------------------------------------------- 1 | /* Escape & Query building tests */ 2 | 3 | var settings = JSON.parse(require('fs').readFileSync('./tests-settings.json','utf8')); 4 | 5 | var client = require("./db-oracle"); 6 | var tests = require("./lib/node-db/tests.js").get(function() { 7 | new client.Database(settings).connect(function(err) { 8 | if (err) { 9 | throw new Error('Could not connect to test DB'); 10 | } 11 | callback(this); 12 | }); 13 | }, '"'); 14 | 15 | for(var test in tests) { 16 | exports[test] = tests[test]; 17 | } 18 | 19 | delete exports["Client"]["escape()"]; 20 | delete exports["Query"]["select markers"]; 21 | delete exports["Query"]["insert markers"]; 22 | delete exports["Query"]["select values"]; 23 | -------------------------------------------------------------------------------- /src/oracle.h: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Mariano Iglesias 2 | #ifndef SRC_ORACLE_H_ 3 | #define SRC_ORACLE_H_ 4 | 5 | #include "./node-db/node_defs.h" 6 | #include "./node-db/binding.h" 7 | #include "./connection.h" 8 | #include "./query.h" 9 | 10 | namespace node_db_oracle { 11 | class Oracle : public node_db::Binding { 12 | public: 13 | static void Init(v8::Handle target); 14 | 15 | protected: 16 | static v8::Persistent constructorTemplate; 17 | 18 | Oracle(); 19 | ~Oracle(); 20 | static v8::Handle New(const v8::Arguments& args); 21 | v8::Handle set(const v8::Local options); 22 | v8::Persistent createQuery() const; 23 | }; 24 | } 25 | 26 | #endif // SRC_ORACLE_H_ 27 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { "name" : "db-oracle" 2 | , "description" : "Oracle database bindings for Node.JS" 3 | , "keywords": ["database","db","native","binding","library","plugin","client","oracle","oci","occi"] 4 | , "homepage" : "http://nodejsdb.org/db-oracle" 5 | , "version" : "0.2.3" 6 | , "engines" : { "node" : ">=0.4.1" } 7 | , "maintainers" : 8 | [ { "name": "Mariano Iglesias" 9 | , "email": "mgiglesias@gmail.com" 10 | } 11 | ] 12 | , "bugs" : { "url" : "http://github.com/mariano/node-db-oracle/issues" } 13 | , "licenses" : [ { "type" : "MIT" } ] 14 | , "repositories" : 15 | [ { "type" : "git" 16 | , "url" : "https://github.com/mariano/node-db-oracle.git" 17 | } 18 | ] 19 | , "main" : "./db-oracle" 20 | , "scripts" : 21 | { "install": "node-waf configure build" 22 | , "preuninstall": "rm -rf build/*" 23 | , "test" : "node-waf test" 24 | , "doc" : "node-waf doc" 25 | } 26 | , "devDependencies" : 27 | { "nodeunit" : "*" 28 | , "nodelint" : "*" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/connection.h: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Mariano Iglesias 2 | #ifndef SRC_CONNECTION_H_ 3 | #define SRC_CONNECTION_H_ 4 | 5 | #include 6 | #include 7 | #include 8 | #include "./node-db/connection.h" 9 | #include "./result.h" 10 | 11 | namespace node_db_oracle { 12 | class Connection : public node_db::Connection { 13 | public: 14 | Connection(); 15 | ~Connection(); 16 | void setCharset(const std::string& charset) throw(); 17 | void setNCharset(const std::string& charset) throw(); 18 | bool isAlive(bool ping) throw(); 19 | void open() throw(node_db::Exception&); 20 | void close(); 21 | std::string escape(const std::string& string) const throw(node_db::Exception&); 22 | std::string version() const; 23 | node_db::Result* query(const std::string& query) const throw(node_db::Exception&); 24 | 25 | protected: 26 | std::string charset; 27 | std::string ncharset; 28 | 29 | private: 30 | oracle::occi::Environment* environment; 31 | oracle::occi::Connection* connection; 32 | }; 33 | } 34 | 35 | #endif // SRC_CONNECTION_H_ 36 | -------------------------------------------------------------------------------- /db-oracle.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Copyright by Mariano Iglesias 3 | * 4 | * See license text in LICENSE file 5 | */ 6 | 7 | /** 8 | * Require bindings native binary 9 | * 10 | * @ignore 11 | */ 12 | var EventEmitter = require('events').EventEmitter, 13 | binding; 14 | 15 | try { 16 | binding = require("./build/default/oracle_bindings"); 17 | } catch(error) { 18 | binding = require("./build/Release/oracle_bindings"); 19 | } 20 | 21 | function extend(target, source) { 22 | for (var k in source.prototype) { 23 | target.prototype[k] = source.prototype[k]; 24 | } 25 | return target; 26 | } 27 | 28 | var BaseEventEmitter = extend(function() {}, EventEmitter); 29 | BaseEventEmitter.prototype.emit = function() { 30 | var type = arguments[0]; 31 | if (type === 'error' && (!this._events || !this._events.error || (Array.isArray(this._events.error) && !this._events.error.length))) { 32 | // Silently allow unattached error events 33 | return; 34 | } 35 | return EventEmitter.prototype.emit.apply(this, arguments); 36 | } 37 | 38 | exports.Query = extend(binding.Query, BaseEventEmitter); 39 | exports.Database = extend(binding.Oracle, BaseEventEmitter); 40 | -------------------------------------------------------------------------------- /src/result.h: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Mariano Iglesias 2 | #ifndef SRC_RESULT_H_ 3 | #define SRC_RESULT_H_ 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "./node-db/exception.h" 10 | #include "./node-db/result.h" 11 | 12 | namespace node_db_oracle { 13 | class Result : public node_db::Result { 14 | public: 15 | class Column : public node_db::Result::Column { 16 | public: 17 | explicit Column(oracle::occi::MetaData& column); 18 | ~Column(); 19 | bool isBinary() const; 20 | std::string getName() const; 21 | node_db::Result::Column::type_t getType() const; 22 | 23 | protected: 24 | std::string name; 25 | type_t type; 26 | bool binary; 27 | }; 28 | 29 | explicit Result(oracle::occi::Statement* statement) throw(node_db::Exception&); 30 | ~Result(); 31 | void release() throw(); 32 | bool hasNext() const throw(); 33 | char** next() throw(node_db::Exception&); 34 | unsigned long* columnLengths() throw(node_db::Exception&); 35 | uint64_t index() const throw(std::out_of_range&); 36 | Column* column(uint16_t i) const throw(std::out_of_range&); 37 | uint16_t columnCount() const throw(); 38 | uint64_t affectedCount() const throw(); 39 | uint64_t insertId() const throw(node_db::Exception&); 40 | uint16_t warningCount() const throw(node_db::Exception&); 41 | bool isBuffered() const throw(); 42 | bool isEmpty() const throw(); 43 | 44 | protected: 45 | Column** columns; 46 | uint16_t totalColumns; 47 | uint64_t rowNumber; 48 | bool empty; 49 | 50 | char** row(unsigned long* rowColumnLengths) throw(node_db::Exception&); 51 | void free() throw(); 52 | 53 | private: 54 | oracle::occi::Statement* statement; 55 | oracle::occi::ResultSet* resultSet; 56 | unsigned long* previousColumnLengths; 57 | char** previousRow; 58 | unsigned long* nextColumnLengths; 59 | char** nextRow; 60 | 61 | void freeRow(char** row) throw(); 62 | }; 63 | } 64 | 65 | #endif // SRC_RESULT_H_ 66 | -------------------------------------------------------------------------------- /src/query.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Mariano Iglesias 2 | #include "./query.h" 3 | 4 | v8::Persistent node_db_oracle::Query::constructorTemplate; 5 | 6 | void node_db_oracle::Query::Init(v8::Handle target) { 7 | v8::HandleScope scope; 8 | 9 | v8::Local t = v8::FunctionTemplate::New(New); 10 | 11 | constructorTemplate = v8::Persistent::New(t); 12 | constructorTemplate->InstanceTemplate()->SetInternalFieldCount(1); 13 | 14 | node_db::Query::Init(target, constructorTemplate); 15 | 16 | NODE_ADD_PROTOTYPE_METHOD(constructorTemplate, "limit", Limit); 17 | 18 | target->Set(v8::String::NewSymbol("Query"), constructorTemplate->GetFunction()); 19 | } 20 | 21 | v8::Handle node_db_oracle::Query::New(const v8::Arguments& args) { 22 | v8::HandleScope scope; 23 | 24 | node_db_oracle::Query* query = new node_db_oracle::Query(); 25 | if (query == NULL) { 26 | THROW_EXCEPTION("Can't create query object") 27 | } 28 | 29 | if (args.Length() > 0) { 30 | v8::Handle set = query->set(args); 31 | if (!set.IsEmpty()) { 32 | return scope.Close(set); 33 | } 34 | } 35 | 36 | query->Wrap(args.This()); 37 | 38 | return scope.Close(args.This()); 39 | } 40 | 41 | v8::Handle node_db_oracle::Query::Limit(const v8::Arguments& args) { 42 | v8::HandleScope scope; 43 | 44 | if (args.Length() > 1) { 45 | ARG_CHECK_UINT32(0, offset); 46 | ARG_CHECK_UINT32(1, rows); 47 | } else { 48 | ARG_CHECK_UINT32(0, rows); 49 | } 50 | 51 | node_db_oracle::Query *query = node::ObjectWrap::Unwrap(args.This()); 52 | assert(query); 53 | 54 | std::string currentSql = query->sql.str(); 55 | 56 | query->sql.str(""); 57 | query->sql.clear(); 58 | 59 | uint32_t start = args[0]->ToInt32()->Value(), end = 0; 60 | if (args.Length() > 1) { 61 | end = args[1]->ToInt32()->Value(); 62 | } else if (start > 1) { 63 | end = start; 64 | start = 1; 65 | } 66 | 67 | query->sql << "SELECT * FROM (" << currentSql << ") WHERE ROWNUM"; 68 | if (start > 1 || end > 0) { 69 | query->sql << " BETWEEN " << start << " AND " << end; 70 | } else { 71 | query->sql << "=" << start; 72 | } 73 | 74 | return scope.Close(args.This()); 75 | } 76 | -------------------------------------------------------------------------------- /wscript: -------------------------------------------------------------------------------- 1 | #### 2 | # Copyright by Mariano Iglesias 3 | # See contributors list in README.md 4 | # 5 | # See license text in LICENSE file 6 | #### 7 | 8 | import Options, Utils 9 | from os import unlink, symlink, chdir, environ 10 | from os.path import exists 11 | 12 | srcdir = "." 13 | blddir = "build" 14 | VERSION = "0.2.3" 15 | 16 | def set_options(opt): 17 | opt.tool_options("compiler_cxx") 18 | opt.add_option('--debug', action='store_true', help='Run tests with nodeunit_g') 19 | opt.add_option('--warn', action='store_true', help='Enable extra -W* compiler flags') 20 | 21 | def configure(conf): 22 | conf.check_tool("compiler_cxx") 23 | conf.check_tool("node_addon") 24 | 25 | # Enables all the warnings that are easy to avoid 26 | conf.env.append_unique('CXXFLAGS', ["-Wall"]) 27 | if Options.options.warn: 28 | # Extra warnings 29 | conf.env.append_unique('CXXFLAGS', ["-Wextra"]) 30 | # Extra warnings, gcc 4.4 31 | conf.env.append_unique('CXXFLAGS', ["-Wconversion", "-Wshadow", "-Wsign-conversion", "-Wunreachable-code", "-Wredundant-decls", "-Wcast-qual"]) 32 | 33 | oci_include = environ.get("OCI_INCLUDE_DIR", "/opt/instantclient/sdk/include") 34 | if oci_include: 35 | conf.env.append_unique('CXXFLAGS', [ '-I' + oci_include ]) 36 | 37 | oci_lib = environ.get("OCI_LIB_DIR", "/opt/instantclient") 38 | if oci_lib: 39 | conf.env.append_unique('LINKFLAGS', [ '-L' + oci_lib ]) 40 | 41 | conf.env.append_unique('LINKFLAGS', ['-locci', '-lclntsh', '-lnnz11']) 42 | conf.check(header_name="occi.h", errmsg="Missing include files for OCI", mandatory=True) 43 | conf.check_cxx(lib="occi", errmsg="Missing libocci", mandatory=True) 44 | 45 | def build(bld): 46 | obj = bld.new_task_gen("cxx", "shlib", "node_addon") 47 | obj.target = "oracle_bindings" 48 | obj.source = "lib/node-db/binding.cc lib/node-db/connection.cc lib/node-db/events.cc lib/node-db/exception.cc lib/node-db/query.cc lib/node-db/result.cc src/connection.cc src/oracle.cc src/query.cc src/result.cc src/oracle_bindings.cc" 49 | obj.includes = "lib/" 50 | 51 | def test(tst): 52 | test_binary = 'nodeunit' 53 | if Options.options.debug: 54 | test_binary = 'nodeunit_g' 55 | 56 | Utils.exec_command(test_binary + ' tests.js') 57 | 58 | def lint(lnt): 59 | # Bindings C++ source code 60 | print("Run CPPLint:") 61 | Utils.exec_command('cpplint --filter=-whitespace/line_length ./lib/node-db/*.h ./lib/node-db/*.cc ./src/*.h ./src/*.cc') 62 | # Bindings javascript code, and tools 63 | print("Run Nodelint for sources:") 64 | Utils.exec_command('nodelint ./package.json ./db-drizzle.js') 65 | -------------------------------------------------------------------------------- /src/connection.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Mariano Iglesias 2 | #include "./connection.h" 3 | 4 | node_db_oracle::Connection::Connection() 5 | : environment(NULL), 6 | connection(NULL) { 7 | this->port = 1521; 8 | this->quoteName = '"'; 9 | } 10 | 11 | node_db_oracle::Connection::~Connection() { 12 | this->close(); 13 | if (this->environment) { 14 | oracle::occi::Environment::terminateEnvironment(this->environment); 15 | } 16 | } 17 | 18 | void node_db_oracle::Connection::setCharset(const std::string& charset) throw() { 19 | this->charset = charset; 20 | } 21 | 22 | void node_db_oracle::Connection::setNCharset(const std::string& ncharset) throw() { 23 | this->ncharset = ncharset; 24 | } 25 | 26 | bool node_db_oracle::Connection::isAlive(bool ping) throw() { 27 | if (ping && this->alive) { 28 | } 29 | return this->alive; 30 | } 31 | 32 | void node_db_oracle::Connection::open() throw(node_db::Exception&) { 33 | this->close(); 34 | 35 | if (!this->environment) { 36 | if (!this->charset.empty() && !this->ncharset.empty()) { 37 | this->environment = oracle::occi::Environment::createEnvironment(this->charset.c_str(), this->ncharset.c_str(), oracle::occi::Environment::THREADED_MUTEXED); 38 | } else { 39 | this->environment = oracle::occi::Environment::createEnvironment(oracle::occi::Environment::THREADED_MUTEXED); 40 | } 41 | if (this->environment == NULL) { 42 | throw node_db::Exception("Cannot create environment"); 43 | } 44 | } 45 | 46 | std::ostringstream connection; 47 | connection << "//" << this->hostname << ":" << this->port << "/" << this->database; 48 | try { 49 | this->connection = this->environment->createConnection(this->user, this->password, connection.str()); 50 | this->alive = true; 51 | } catch(oracle::occi::SQLException& exception) { 52 | throw node_db::Exception(exception.getMessage()); 53 | } 54 | } 55 | 56 | void node_db_oracle::Connection::close() { 57 | if (this->alive && this->environment) { 58 | this->environment->terminateConnection(this->connection); 59 | } 60 | this->alive = false; 61 | } 62 | 63 | std::string node_db_oracle::Connection::escape(const std::string& string) const throw(node_db::Exception&) { 64 | throw node_db::Exception("This binding does not implement escape()"); 65 | } 66 | 67 | std::string node_db_oracle::Connection::version() const { 68 | return this->connection->getServerVersion(); 69 | } 70 | 71 | node_db::Result* node_db_oracle::Connection::query(const std::string& query) const throw(node_db::Exception&) { 72 | return new node_db_oracle::Result(this->connection->createStatement(query)); 73 | } 74 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # db-oracle: Oracle database bindings for Node.js # 2 | 3 | For detailed information about this and other Node.js 4 | database bindings visit the [Node.js db-mysql homepage] [homepage]. 5 | 6 | ## INSTALL ## 7 | 8 | ### OCI libraries ### 9 | 10 | Before proceeding with installation, you need to have the 11 | [OCI instant client] [oci] [libraries] [oci-lib] and [include files] [oci-inc]. 12 | For example, you download the `instantclient-basic-linux.x64-11.2.0.3.0.zip` 13 | library file, and the `instantclient-sdk-linux.x64-11.2.0.3.0.zip` SDK file, 14 | and save them in your `$HOME/Downloads` directory. You would then uncompress 15 | both files, and move the generated directory to your `/opt` path: 16 | 17 | ```bash 18 | $ cd $HOME/Downloads 19 | $ unzip instantclient-basic-linux.x64-11.2.0.3.0.zip 20 | $ unzip instantclient-sdk-linux.x64-11.2.0.3.0.zip 21 | $ sudo mv instantclient_11_2/ /opt/instantclient 22 | ``` 23 | 24 | After uncompressing you will probably need to create symbolink links: 25 | 26 | ```bash 27 | $ cd /opt/instantclient 28 | $ sudo ln -s libocci.so.11.1 libocci.so 29 | $ sudo ln -s libclntsh.so.11.1 libclntsh.so 30 | ``` 31 | 32 | You will also need `libaio`. In **Arch Linux** this can easily be installed with: 33 | 34 | ```bash 35 | $ sudo pacman -S libaio 36 | ``` 37 | 38 | On **Debian** based distros: 39 | 40 | ```bash 41 | $ sudo apt-get install libaio 42 | ``` 43 | 44 | ### Configuring OCI ### 45 | 46 | Once you have the library and include files installed, and in order for the 47 | installation script to locate them properly, you'll need to set the 48 | `OCI_INCLUDE_DIR` and `OCI_LIB_DIR` environment variables. For example: 49 | 50 | ```bash 51 | $ export OCI_INCLUDE_DIR=/opt/instantclient/sdk/include/ 52 | $ export OCI_LIB_DIR=/opt/instantclient 53 | ``` 54 | 55 | ### Install ### 56 | 57 | Once the environment variables are set, install with npm: 58 | 59 | ```bash 60 | $ npm install db-oracle 61 | ``` 62 | 63 | You should also add the OCI library path to your `LD_LIBRARY_PATH` environment: 64 | 65 | ```bash 66 | export LD_LIBRARY_PATH=/opt/instantclient 67 | ``` 68 | 69 | ## QUICK START ## 70 | 71 | ```javascript 72 | var oracle = require('db-oracle'); 73 | new oracle.Database({ 74 | hostname: 'localhost', 75 | user: 'root', 76 | password: 'password', 77 | database: 'node' 78 | }).connect(function(error) { 79 | if (error) { 80 | return console.log("CONNECTION ERROR: " + error); 81 | } 82 | 83 | this.query().select('*').from('users').execute(function(error, rows) { 84 | if (error) { 85 | return console.log('ERROR: ' + error); 86 | } 87 | console.log(rows.length + ' ROWS'); 88 | }); 89 | }); 90 | ``` 91 | 92 | ## LICENSE ## 93 | 94 | This module is released under the [MIT License] [license]. 95 | 96 | [homepage]: http://nodejsdb.org/db-mysql 97 | [license]: http://www.opensource.org/licenses/mit-license.php 98 | [oci]: http://www.oracle.com/technetwork/database/features/oci/index.html 99 | [oci-lib]: http://www.oracle.com/technetwork/topics/linuxx86-64soft-092277.html 100 | [oci-inc]: http://www.oracle.com/technetwork/topics/linuxx86-64soft-092277.html 101 | -------------------------------------------------------------------------------- /src/oracle.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Mariano Iglesias 2 | #include "./oracle.h" 3 | 4 | v8::Persistent node_db_oracle::Oracle::constructorTemplate; 5 | 6 | node_db_oracle::Oracle::Oracle(): node_db::Binding() { 7 | this->connection = new node_db_oracle::Connection(); 8 | assert(this->connection); 9 | } 10 | 11 | node_db_oracle::Oracle::~Oracle() { 12 | if (this->connection != NULL) { 13 | delete this->connection; 14 | } 15 | } 16 | 17 | void node_db_oracle::Oracle::Init(v8::Handle target) { 18 | v8::HandleScope scope; 19 | 20 | v8::Local t = v8::FunctionTemplate::New(New); 21 | 22 | constructorTemplate = v8::Persistent::New(t); 23 | constructorTemplate->InstanceTemplate()->SetInternalFieldCount(1); 24 | 25 | node_db::Binding::Init(target, constructorTemplate); 26 | 27 | target->Set(v8::String::NewSymbol("Oracle"), constructorTemplate->GetFunction()); 28 | } 29 | 30 | v8::Handle node_db_oracle::Oracle::New(const v8::Arguments& args) { 31 | v8::HandleScope scope; 32 | 33 | node_db_oracle::Oracle* binding = new node_db_oracle::Oracle(); 34 | if (binding == NULL) { 35 | THROW_EXCEPTION("Can't create client object") 36 | } 37 | 38 | if (args.Length() > 0) { 39 | ARG_CHECK_OBJECT(0, options); 40 | 41 | v8::Handle set = binding->set(args[0]->ToObject()); 42 | if (!set.IsEmpty()) { 43 | return scope.Close(set); 44 | } 45 | } 46 | 47 | binding->Wrap(args.This()); 48 | 49 | return scope.Close(args.This()); 50 | } 51 | 52 | v8::Handle node_db_oracle::Oracle::set(const v8::Local options) { 53 | ARG_CHECK_OBJECT_ATTR_OPTIONAL_STRING(options, hostname); 54 | ARG_CHECK_OBJECT_ATTR_OPTIONAL_STRING(options, user); 55 | ARG_CHECK_OBJECT_ATTR_OPTIONAL_STRING(options, password); 56 | ARG_CHECK_OBJECT_ATTR_OPTIONAL_STRING(options, database); 57 | ARG_CHECK_OBJECT_ATTR_OPTIONAL_UINT32(options, port); 58 | ARG_CHECK_OBJECT_ATTR_OPTIONAL_STRING(options, charset); 59 | ARG_CHECK_OBJECT_ATTR_OPTIONAL_STRING(options, ncharset); 60 | 61 | node_db_oracle::Connection* connection = static_cast(this->connection); 62 | 63 | v8::String::Utf8Value hostname(options->Get(hostname_key)->ToString()); 64 | v8::String::Utf8Value user(options->Get(user_key)->ToString()); 65 | v8::String::Utf8Value password(options->Get(password_key)->ToString()); 66 | v8::String::Utf8Value database(options->Get(database_key)->ToString()); 67 | 68 | if (options->Has(hostname_key)) { 69 | connection->setHostname(*hostname); 70 | } 71 | 72 | if (options->Has(user_key)) { 73 | connection->setUser(*user); 74 | } 75 | 76 | if (options->Has(password_key)) { 77 | connection->setPassword(*password); 78 | } 79 | 80 | if (options->Has(database_key)) { 81 | connection->setDatabase(*database); 82 | } 83 | 84 | if (options->Has(port_key)) { 85 | connection->setPort(options->Get(port_key)->ToInt32()->Value()); 86 | } 87 | 88 | if (options->Has(charset_key)) { 89 | v8::String::Utf8Value charset(options->Get(charset_key)->ToString()); 90 | connection->setCharset(*charset); 91 | } 92 | 93 | if (options->Has(ncharset_key)) { 94 | v8::String::Utf8Value ncharset(options->Get(ncharset_key)->ToString()); 95 | connection->setNCharset(*ncharset); 96 | } 97 | 98 | return v8::Handle(); 99 | } 100 | 101 | v8::Persistent node_db_oracle::Oracle::createQuery() const { 102 | v8::Persistent query( 103 | node_db_oracle::Query::constructorTemplate->GetFunction()->NewInstance()); 104 | return query; 105 | } 106 | -------------------------------------------------------------------------------- /src/result.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Mariano Iglesias 2 | #include "./result.h" 3 | 4 | node_db_oracle::Result::Column::Column(oracle::occi::MetaData& column) { 5 | this->binary = false; 6 | this->name = column.getString(oracle::occi::MetaData::ATTR_NAME); 7 | 8 | switch (column.getInt(oracle::occi::MetaData::ATTR_DATA_TYPE)) { 9 | case oracle::occi::OCCI_TYPECODE_SMALLINT: 10 | this->type = (column.getInt(oracle::occi::MetaData::ATTR_DATA_SIZE) == 1 ? BOOL : INT); 11 | break; 12 | case oracle::occi::OCCI_TYPECODE_OCTET: 13 | case oracle::occi::OCCI_TYPECODE_INTEGER: 14 | this->type = INT; 15 | break; 16 | case oracle::occi::OCCI_TYPECODE_REAL: 17 | case oracle::occi::OCCI_TYPECODE_DOUBLE: 18 | case oracle::occi::OCCI_TYPECODE_BDOUBLE: 19 | case oracle::occi::OCCI_TYPECODE_FLOAT: 20 | case oracle::occi::OCCI_TYPECODE_BFLOAT: 21 | case oracle::occi::OCCI_TYPECODE_NUMBER: 22 | case oracle::occi::OCCI_TYPECODE_DECIMAL: 23 | this->type = NUMBER; 24 | break; 25 | case oracle::occi::OCCI_TYPECODE_DATE: 26 | this->type = DATETIME; 27 | break; 28 | case oracle::occi::OCCI_TYPECODE_CLOB: 29 | case oracle::occi::OCCI_TYPECODE_BLOB: 30 | this->type = TEXT; 31 | this->binary = true; 32 | break; 33 | default: 34 | this->type = STRING; 35 | break; 36 | } 37 | } 38 | 39 | node_db_oracle::Result::Column::~Column() { 40 | } 41 | 42 | bool node_db_oracle::Result::Column::isBinary() const { 43 | return this->binary; 44 | } 45 | 46 | std::string node_db_oracle::Result::Column::getName() const { 47 | return this->name; 48 | } 49 | 50 | node_db::Result::Column::type_t node_db_oracle::Result::Column::getType() const { 51 | return this->type; 52 | } 53 | 54 | node_db_oracle::Result::Result(oracle::occi::Statement* statement) throw(node_db::Exception&) 55 | : columns(NULL), 56 | totalColumns(0), 57 | rowNumber(0), 58 | empty(true), 59 | statement(statement), 60 | resultSet(NULL), 61 | previousColumnLengths(NULL), 62 | previousRow(NULL), 63 | nextColumnLengths(NULL), 64 | nextRow(NULL) { 65 | 66 | try { 67 | try { 68 | oracle::occi::Statement::Status status = this->statement->execute(); 69 | if (status == oracle::occi::Statement::RESULT_SET_AVAILABLE) { 70 | this->resultSet = this->statement->getResultSet(); 71 | } else if (status != oracle::occi::Statement::UPDATE_COUNT_AVAILABLE) { 72 | throw node_db::Exception("Cannot handle statement statuses other than RESULT_SET_AVAILABLE or UPDATE_COUNT_AVAILABLE"); 73 | } 74 | } catch(oracle::occi::SQLException& ex) { 75 | throw node_db::Exception(ex.getMessage()); 76 | } 77 | 78 | if (this->resultSet != NULL) { 79 | std::vector columns = this->resultSet->getColumnListMetaData(); 80 | 81 | this->empty = false; 82 | this->totalColumns = columns.size(); 83 | 84 | this->previousColumnLengths = new unsigned long[this->totalColumns]; 85 | if (this->previousColumnLengths == NULL) { 86 | throw node_db::Exception("Could not create buffer for column lengths"); 87 | } 88 | 89 | this->nextColumnLengths = new unsigned long[this->totalColumns]; 90 | if (this->nextColumnLengths == NULL) { 91 | throw node_db::Exception("Could not create buffer for column lengths"); 92 | } 93 | 94 | 95 | this->columns = new Column*[this->totalColumns]; 96 | if (this->columns == NULL) { 97 | throw node_db::Exception("Could not allocate storage for columns"); 98 | } 99 | 100 | for (uint16_t i = 0; i < this->totalColumns; i++) { 101 | this->columns[i] = new Column(columns[i]); 102 | if (this->columns[i] == NULL) { 103 | this->totalColumns = i; 104 | throw node_db::Exception("Could not allocate storage for column"); 105 | } 106 | } 107 | 108 | this->nextRow = this->row(this->nextColumnLengths); 109 | } 110 | } catch(...) { 111 | this->free(); 112 | throw; 113 | } 114 | } 115 | 116 | node_db_oracle::Result::~Result() { 117 | this->free(); 118 | } 119 | 120 | void node_db_oracle::Result::free() throw() { 121 | this->release(); 122 | 123 | this->freeRow(this->previousRow); 124 | this->freeRow(this->nextRow); 125 | 126 | if (this->previousColumnLengths != NULL) { 127 | delete [] this->previousColumnLengths; 128 | } 129 | 130 | if (this->nextColumnLengths != NULL) { 131 | delete [] this->nextColumnLengths; 132 | } 133 | 134 | if (this->columns != NULL) { 135 | for (uint16_t i = 0; i < this->totalColumns; i++) { 136 | delete this->columns[i]; 137 | } 138 | delete [] this->columns; 139 | } 140 | } 141 | 142 | void node_db_oracle::Result::release() throw() { 143 | if (this->resultSet != NULL) { 144 | this->statement->closeResultSet(this->resultSet); 145 | this->resultSet = NULL; 146 | } 147 | 148 | if (this->statement != NULL) { 149 | this->statement->getConnection()->terminateStatement(this->statement); 150 | this->statement = NULL; 151 | } 152 | } 153 | 154 | void node_db_oracle::Result::freeRow(char** row) throw() { 155 | if (row != NULL) { 156 | for (uint16_t i = 0; i < this->totalColumns; i++) { 157 | delete [] row[i]; 158 | } 159 | 160 | delete [] row; 161 | } 162 | } 163 | 164 | bool node_db_oracle::Result::hasNext() const throw() { 165 | return (this->nextRow != NULL); 166 | } 167 | 168 | char** node_db_oracle::Result::next() throw(node_db::Exception&) { 169 | this->freeRow(this->previousRow); 170 | 171 | if (this->nextRow == NULL) { 172 | return NULL; 173 | } 174 | 175 | this->rowNumber++; 176 | this->previousRow = this->nextRow; 177 | 178 | for(uint16_t i=0; i < this->totalColumns; i++) { 179 | this->previousColumnLengths[i] = this->nextColumnLengths[i]; 180 | } 181 | this->nextRow = this->row(this->nextColumnLengths); 182 | 183 | return this->previousRow; 184 | } 185 | 186 | unsigned long* node_db_oracle::Result::columnLengths() throw(node_db::Exception&) { 187 | return this->previousColumnLengths; 188 | } 189 | 190 | char** node_db_oracle::Result::row(unsigned long* rowColumnLengths) throw(node_db::Exception&) { 191 | if (this->resultSet == NULL) { 192 | throw node_db::Exception("No ResultSet"); 193 | } else if (!this->resultSet->next()) { 194 | return NULL; 195 | } 196 | 197 | uint16_t c=0; 198 | char** row; 199 | try { 200 | row = new char*[this->totalColumns]; 201 | if (row == NULL) { 202 | throw node_db::Exception("Could not allocate buffer for row"); 203 | } 204 | 205 | for (c=0; c < this->totalColumns; c++) { 206 | if (this->columns[c]->isBinary()) { 207 | if(!this->resultSet->isNull(c + 1)){ 208 | oracle::occi::Blob blob = this->resultSet->getBlob(c + 1); 209 | rowColumnLengths[c] = blob.length(); 210 | 211 | row[c] = new char[rowColumnLengths[c]]; 212 | if (row[c] == NULL) { 213 | throw node_db::Exception("Could not allocate buffer for row column"); 214 | } 215 | 216 | blob.read(rowColumnLengths[c], (unsigned char*) row[c], rowColumnLengths[c]); 217 | }else{ 218 | rowColumnLengths[c] = 0; 219 | row[c] = new char[0]; 220 | } 221 | } else { 222 | std::string string; 223 | if (this->columns[c]->getType() == Column::DATETIME) { 224 | oracle::occi::Date date = this->resultSet->getDate(c + 1); 225 | if (date.isNull()) { 226 | rowColumnLengths[c] = 0; 227 | row[c] = NULL; 228 | continue; 229 | } 230 | 231 | string = date.toText("YYYY-MM-DD HH24:MI:SS"); 232 | } else { 233 | string = this->resultSet->getString(c + 1); 234 | } 235 | 236 | rowColumnLengths[c] = string.length(); 237 | row[c] = new char[rowColumnLengths[c]]; 238 | if (row[c] == NULL) { 239 | throw node_db::Exception("Could not allocate buffer for row column"); 240 | } 241 | 242 | memcpy(row[c], string.c_str(), rowColumnLengths[c]); 243 | } 244 | } 245 | } catch(...) { 246 | if (row != NULL) { 247 | for (uint16_t i=0; i < c; i++) { 248 | if (row[i] != NULL) { 249 | delete [] row[i]; 250 | } 251 | } 252 | delete [] row; 253 | } 254 | throw; 255 | } 256 | 257 | return row; 258 | } 259 | 260 | uint64_t node_db_oracle::Result::index() const throw(std::out_of_range&) { 261 | if (this->rowNumber == 0) { 262 | throw std::out_of_range("Not standing on a row"); 263 | } 264 | return (this->rowNumber - 1); 265 | } 266 | 267 | node_db_oracle::Result::Column* node_db_oracle::Result::column(uint16_t i) const throw(std::out_of_range&) { 268 | if (i >= this->totalColumns) { 269 | throw std::out_of_range("Wrong column index"); 270 | } 271 | return this->columns[i]; 272 | } 273 | 274 | uint64_t node_db_oracle::Result::affectedCount() const throw() { 275 | return this->statement->getUpdateCount(); 276 | } 277 | 278 | uint64_t node_db_oracle::Result::insertId() const throw(node_db::Exception&) { 279 | //TODO: 280 | return 0; 281 | } 282 | 283 | uint16_t node_db_oracle::Result::warningCount() const throw(node_db::Exception&) { 284 | //TODO: 285 | return 0; 286 | } 287 | 288 | uint16_t node_db_oracle::Result::columnCount() const throw() { 289 | return this->totalColumns; 290 | } 291 | 292 | bool node_db_oracle::Result::isBuffered() const throw() { 293 | return false; 294 | } 295 | 296 | bool node_db_oracle::Result::isEmpty() const throw() { 297 | return this->empty; 298 | } 299 | --------------------------------------------------------------------------------