Browse files

first commit

  • Loading branch information...
0 parents commit 43fee35852cd4720d840b48344179f26cec2dda0 @joeferner committed Dec 20, 2011
Showing with 707 additions and 0 deletions.
  1. +1 −0 .gitignore
  2. +2 −0 index.js
  3. +9 −0 lib/oracle.js
  4. +279 −0 src/connection.cpp
  5. +35 −0 src/connection.h
  6. +125 −0 src/oracle_bindings.cpp
  7. +30 −0 src/oracle_bindings.h
  8. +29 −0 src/outParam.cpp
  9. +25 −0 src/outParam.h
  10. +54 −0 src/utils.h
  11. +5 −0 tests-settings.json
  12. +74 −0 tests/integration.js
  13. +39 −0 wscript
1 .gitignore
@@ -0,0 +1 @@
+build/
2 index.js
@@ -0,0 +1,2 @@
+
+module.exports = require('./lib/oracle');
9 lib/oracle.js
@@ -0,0 +1,9 @@
+
+var bindings = require("../build/Release/oracle_bindings");
+var oracle = new bindings.OracleClient();
+
+exports.connect = function(settings, callback) {
+ oracle.connect(settings, callback);
+}
+
+exports.OutParam = bindings.OutParam;
279 src/connection.cpp
@@ -0,0 +1,279 @@
+
+#include "connection.h"
+#include "outParam.h"
+#include <vector>
+
+Persistent<FunctionTemplate> Connection::constructorTemplate;
+
+#define VALUE_TYPE_OUTPUT 1
+#define VALUE_TYPE_STRING 2
+
+struct column_t {
+ int type;
+ std::string name;
+};
+
+struct row_t {
+ std::vector<void*> values;
+};
+
+struct value_t {
+ int type;
+ void* value;
+};
+
+struct execute_baton_t {
+ Connection *connection;
+ Persistent<Function> callback;
+ std::vector<value_t*> values;
+ std::string sql;
+ std::vector<column_t*> columns;
+ std::vector<row_t*>* rows;
+ std::string* error;
+ int updateCount;
+ int* returnParam;
+};
+
+void Connection::Init(Handle<Object> target) {
+ HandleScope scope;
+
+ Local<FunctionTemplate> t = FunctionTemplate::New(New);
+ constructorTemplate = Persistent<FunctionTemplate>::New(t);
+ constructorTemplate->InstanceTemplate()->SetInternalFieldCount(1);
+ constructorTemplate->SetClassName(String::NewSymbol("Connection"));
+
+ NODE_SET_PROTOTYPE_METHOD(constructorTemplate, "execute", Execute);
+ NODE_SET_PROTOTYPE_METHOD(constructorTemplate, "close", Close);
+
+ target->Set(String::NewSymbol("Connection"), constructorTemplate->GetFunction());
+}
+
+Handle<Value> Connection::New(const Arguments& args) {
+ HandleScope scope;
+
+ Connection *connection = new Connection();
+ connection->Wrap(args.This());
+ return args.This();
+}
+
+Connection::Connection() {
+}
+
+Connection::~Connection() {
+ closeConnection();
+}
+
+Handle<Value> Connection::Execute(const Arguments& args) {
+ Connection* connection = ObjectWrap::Unwrap<Connection>(args.This());
+
+ REQ_STRING_ARG(0, sql);
+ REQ_ARRAY_ARG(1, values);
+ REQ_FUN_ARG(2, callback);
+
+ String::AsciiValue sqlVal(sql);
+
+ execute_baton_t* baton = new execute_baton_t();
+ baton->connection = connection;
+ baton->sql = *sqlVal;
+ baton->callback = Persistent<Function>::New(callback);
+ baton->returnParam = NULL;
+
+ for(uint32_t i=0; i<values->Length(); i++) {
+ Local<Value> val = values->Get(i);
+
+ value_t *value = new value_t();
+ if(val->IsString()) {
+ String::AsciiValue asciiVal(val);
+ value->type = VALUE_TYPE_STRING;
+ value->value = new std::string(*asciiVal);
+ baton->values.push_back(value);
+ } else if(val->IsObject() && val->ToObject()->FindInstanceInPrototypeChain(OutParam::constructorTemplate) != Null()) {
+ value->type = VALUE_TYPE_OUTPUT;
+ value->value = NULL;
+ baton->values.push_back(value);
+ } else {
+ Handle<Value> argv[2];
+ argv[0] = Exception::Error(String::New("unhandled value type"));
+ argv[1] = Undefined();
+ baton->callback->Call(Context::GetCurrent()->Global(), 2, argv);
+ return Undefined();
+ }
+ }
+
+ eio_custom(EIO_Execute, EIO_PRI_DEFAULT, EIO_AfterExecute, baton);
+ ev_ref(EV_DEFAULT_UC);
+
+ connection->Ref();
+
+ return Undefined();
+}
+
+Handle<Value> Connection::Close(const Arguments& args) {
+ Connection* connection = ObjectWrap::Unwrap<Connection>(args.This());
+ connection->closeConnection();
+
+ return Undefined();
+}
+
+void Connection::closeConnection() {
+ if(m_environment && m_connection) {
+ m_environment->terminateConnection(m_connection);
+ m_connection = NULL;
+ }
+}
+
+void Connection::EIO_Execute(eio_req* req) {
+ execute_baton_t* baton = static_cast<execute_baton_t*>(req->data);
+
+ baton->rows = NULL;
+ baton->error = NULL;
+
+ oracle::occi::Statement* stmt = NULL;
+ oracle::occi::ResultSet* rs = NULL;
+ try {
+ //printf("%s\n", baton->sql.c_str());
+ stmt = baton->connection->m_connection->createStatement(baton->sql);
+ uint32_t index = 1;
+ int outputParam = -1;
+ for (std::vector<value_t*>::iterator iterator = baton->values.begin(), end = baton->values.end(); iterator != end; ++iterator, index++) {
+ value_t* val = *iterator;
+ switch(val->type) {
+ case VALUE_TYPE_STRING:
+ stmt->setString(index, *((std::string*)val->value));
+ break;
+ case VALUE_TYPE_OUTPUT:
+ stmt->registerOutParam(index, oracle::occi::OCCIINT);
+ outputParam = index;
+ break;
+ default:
+ baton->error = new std::string("unhandled value type");
+ goto error;
+ }
+ }
+
+ int status = stmt->execute();
+ if(status == oracle::occi::Statement::UPDATE_COUNT_AVAILABLE) {
+ baton->updateCount = stmt->getUpdateCount();
+ if(outputParam >= 0) {
+ baton->returnParam = new int;
+ *(baton->returnParam) = stmt->getInt(outputParam);
+ }
+ } else {
+ rs = stmt->executeQuery();
+ std::vector<oracle::occi::MetaData> columns = rs->getColumnListMetaData();
+ for (std::vector<oracle::occi::MetaData>::iterator iterator = columns.begin(), end = columns.end(); iterator != end; ++iterator) {
+ oracle::occi::MetaData metadata = *iterator;
+ column_t* col = new column_t();
+ col->name = metadata.getString(oracle::occi::MetaData::ATTR_NAME);
+ int type = metadata.getInt(oracle::occi::MetaData::ATTR_DATA_TYPE);
+ switch(type) {
+ default:
+ col->type = VALUE_TYPE_STRING;
+ break;
+ }
+ baton->columns.push_back(col);
+ }
+
+ baton->rows = new std::vector<row_t*>();
+
+ while(rs->next()) {
+ row_t* row = new row_t();
+ int colIndex = 1;
+ for (std::vector<column_t*>::iterator iterator = baton->columns.begin(), end = baton->columns.end(); iterator != end; ++iterator, colIndex++) {
+ column_t* col = *iterator;
+ switch(col->type) {
+ default:
+ case VALUE_TYPE_STRING:
+ row->values.push_back(new std::string(rs->getString(colIndex)));
+ break;
+ }
+ }
+ baton->rows->push_back(row);
+ }
+ }
+ } catch(oracle::occi::SQLException &ex) {
+ baton->error = new std::string(ex.getMessage());
+ }
+
+error:
+ if(stmt && rs) {
+ stmt->closeResultSet(rs);
+ }
+ if(stmt) {
+ baton->connection->m_connection->terminateStatement(stmt);
+ }
+}
+
+int Connection::EIO_AfterExecute(eio_req* req) {
+ execute_baton_t* baton = static_cast<execute_baton_t*>(req->data);
+ ev_unref(EV_DEFAULT_UC);
+ baton->connection->Unref();
+
+ Handle<Value> argv[2];
+ if(baton->error) {
+ argv[0] = Exception::Error(String::New(baton->error->c_str()));
+ argv[1] = Undefined();
+ } else {
+ argv[0] = Undefined();
+
+ if(baton->rows) {
+ size_t totalRows = baton->rows->size();
+ Local<Array> rows = Array::New(totalRows);
+ uint32_t index = 0;
+ for (std::vector<row_t*>::iterator iterator = baton->rows->begin(), end = baton->rows->end(); iterator != end; ++iterator, index++) {
+ row_t* currentRow = *iterator;
+ Local<Object> obj = Object::New();
+ uint32_t colIndex = 0;
+ for (std::vector<column_t*>::iterator iterator = baton->columns.begin(), end = baton->columns.end(); iterator != end; ++iterator, colIndex++) {
+ column_t* col = *iterator;
+ void* val = currentRow->values[colIndex];
+ switch(col->type) {
+ case VALUE_TYPE_STRING:
+ std::string* v = (std::string*)val;
+ obj->Set(String::New(col->name.c_str()), String::New(v->c_str()));
+ delete v;
+ break;
+ }
+ }
+ rows->Set(index, obj);
+ delete currentRow;
+ }
+ delete baton->rows;
+ argv[1] = rows;
+ } else {
+ Local<Object> obj = Object::New();
+ obj->Set(String::New("updateCount"), Integer::New(baton->updateCount));
+ if(baton->returnParam) {
+ obj->Set(String::New("returnParam"), Integer::New(*baton->returnParam));
+ delete baton->returnParam;
+ }
+ argv[1] = obj;
+ }
+ }
+ baton->callback->Call(Context::GetCurrent()->Global(), 2, argv);
+
+ baton->callback.Dispose();
+
+ for (std::vector<column_t*>::iterator iterator = baton->columns.begin(), end = baton->columns.end(); iterator != end; ++iterator) {
+ column_t* col = *iterator;
+ delete col;
+ }
+
+ for (std::vector<value_t*>::iterator iterator = baton->values.begin(), end = baton->values.end(); iterator != end; ++iterator) {
+ value_t* val = *iterator;
+ if(val->type == VALUE_TYPE_STRING) {
+ delete (std::string*)val->value;
+ }
+ delete val;
+ }
+
+ if(baton->error) delete baton->error;
+
+ delete baton;
+ return 0;
+}
+
+void Connection::setConnection(oracle::occi::Environment* environment, oracle::occi::Connection* connection) {
+ m_environment = environment;
+ m_connection = connection;
+}
35 src/connection.h
@@ -0,0 +1,35 @@
+
+#ifndef _connection_h_
+#define _connection_h_
+
+#include <v8.h>
+#include <node.h>
+#include <unistd.h>
+#include <occi.h>
+#include "utils.h"
+
+using namespace node;
+using namespace v8;
+
+class Connection : ObjectWrap {
+public:
+ static void Init(Handle<Object> target);
+ static Handle<Value> New(const Arguments& args);
+ static Handle<Value> Execute(const Arguments& args);
+ static Handle<Value> Close(const Arguments& args);
+ static Persistent<FunctionTemplate> constructorTemplate;
+ static void EIO_Execute(eio_req* req);
+ static int EIO_AfterExecute(eio_req* req);
+ void closeConnection();
+
+ Connection();
+ ~Connection();
+
+ void setConnection(oracle::occi::Environment* environment, oracle::occi::Connection* connection);
+
+private:
+ oracle::occi::Connection* m_connection;
+ oracle::occi::Environment* m_environment;
+};
+
+#endif
125 src/oracle_bindings.cpp
@@ -0,0 +1,125 @@
+
+#include "oracle_bindings.h"
+#include "connection.h"
+#include "outParam.h"
+
+Persistent<FunctionTemplate> OracleClient::s_ct;
+
+struct connect_baton_t {
+ OracleClient* client;
+ Persistent<Function> callback;
+ std::string hostname;
+ std::string user;
+ std::string password;
+ std::string database;
+ uint32_t port;
+ oracle::occi::Environment *environment;
+
+ std::string* error;
+ oracle::occi::Connection* connection;
+};
+
+void OracleClient::Init(Handle<Object> target) {
+ HandleScope scope;
+
+ Local<FunctionTemplate> t = FunctionTemplate::New(New);
+ s_ct = Persistent<FunctionTemplate>::New(t);
+ s_ct->InstanceTemplate()->SetInternalFieldCount(1);
+ s_ct->SetClassName(String::NewSymbol("OracleClient"));
+
+ NODE_SET_PROTOTYPE_METHOD(s_ct, "connect", Connect);
+
+ target->Set(String::NewSymbol("OracleClient"), s_ct->GetFunction());
+}
+
+Handle<Value> OracleClient::New(const Arguments& args) {
+ HandleScope scope;
+
+ OracleClient *client = new OracleClient();
+ client->Wrap(args.This());
+ return args.This();
+}
+
+OracleClient::OracleClient() {
+ m_environment = oracle::occi::Environment::createEnvironment(oracle::occi::Environment::THREADED_MUTEXED);
+}
+
+OracleClient::~OracleClient() {
+ oracle::occi::Environment::terminateEnvironment(m_environment);
+}
+
+Handle<Value> OracleClient::Connect(const Arguments& args) {
+ HandleScope scope;
+
+ REQ_OBJECT_ARG(0, settings);
+ REQ_FUN_ARG(1, callback);
+
+ OracleClient* client = ObjectWrap::Unwrap<OracleClient>(args.This());
+ connect_baton_t* baton = new connect_baton_t();
+ baton->client = client;
+ baton->callback = Persistent<Function>::New(callback);
+ baton->environment = client->m_environment;
+
+ OBJ_GET_STRING(settings, "hostname", baton->hostname);
+ OBJ_GET_STRING(settings, "user", baton->user);
+ OBJ_GET_STRING(settings, "password", baton->password);
+ OBJ_GET_STRING(settings, "database", baton->database);
+ OBJ_GET_NUMBER(settings, "port", baton->port, 1521);
+
+ client->Ref();
+
+ eio_custom(EIO_Connect, EIO_PRI_DEFAULT, EIO_AfterConnect, baton);
+ ev_ref(EV_DEFAULT_UC);
+
+ return Undefined();
+}
+
+void OracleClient::EIO_Connect(eio_req* req) {
+ connect_baton_t* baton = static_cast<connect_baton_t*>(req->data);
+
+ baton->error = NULL;
+
+ try {
+ std::ostringstream connectionStr;
+ connectionStr << "//" << baton->hostname << ":" << baton->port << "/" << baton->database;
+ baton->connection = baton->environment->createConnection(baton->user, baton->password, connectionStr.str());
+ } catch(oracle::occi::SQLException &ex) {
+ baton->error = new std::string(ex.getMessage());
+ }
+}
+
+int OracleClient::EIO_AfterConnect(eio_req* req) {
+ HandleScope scope;
+ connect_baton_t* baton = static_cast<connect_baton_t*>(req->data);
+ ev_unref(EV_DEFAULT_UC);
+ baton->client->Unref();
+
+ Handle<Value> argv[2];
+ if(baton->error) {
+ argv[0] = Exception::Error(String::New(baton->error->c_str()));
+ argv[1] = Undefined();
+ } else {
+ argv[0] = Undefined();
+ Handle<Object> connection = Connection::constructorTemplate->GetFunction()->NewInstance();
+ (node::ObjectWrap::Unwrap<Connection>(connection))->setConnection(baton->client->m_environment, baton->connection);
+ argv[1] = connection;
+ }
+
+ baton->callback->Call(Context::GetCurrent()->Global(), 2, argv);
+
+ baton->callback.Dispose();
+ if(baton->error) delete baton->error;
+
+ delete baton;
+ return 0;
+}
+
+extern "C" {
+ static void init(Handle<Object> target) {
+ OracleClient::Init(target);
+ Connection::Init(target);
+ OutParam::Init(target);
+ }
+
+ NODE_MODULE(oracle_bindings, init);
+}
30 src/oracle_bindings.h
@@ -0,0 +1,30 @@
+
+#ifndef _oracle_binding_h_
+#define _oracle_binding_h_
+
+#include <v8.h>
+#include <node.h>
+#include <unistd.h>
+#include <occi.h>
+#include "utils.h"
+
+using namespace node;
+using namespace v8;
+
+class OracleClient : ObjectWrap {
+public:
+ static void Init(Handle<Object> target);
+ static Handle<Value> New(const Arguments& args);
+ static Handle<Value> Connect(const Arguments& args);
+ static void EIO_Connect(eio_req* req);
+ static int EIO_AfterConnect(eio_req* req);
+
+ OracleClient();
+ ~OracleClient();
+
+private:
+ static Persistent<FunctionTemplate> s_ct;
+ oracle::occi::Environment* m_environment;
+};
+
+#endif
29 src/outParam.cpp
@@ -0,0 +1,29 @@
+
+#include "outParam.h"
+
+Persistent<FunctionTemplate> OutParam::constructorTemplate;
+
+void OutParam::Init(Handle<Object> target) {
+ HandleScope scope;
+
+ Local<FunctionTemplate> t = FunctionTemplate::New(New);
+ constructorTemplate = Persistent<FunctionTemplate>::New(t);
+ constructorTemplate->InstanceTemplate()->SetInternalFieldCount(1);
+ constructorTemplate->SetClassName(String::NewSymbol("OutParam"));
+
+ target->Set(String::NewSymbol("OutParam"), constructorTemplate->GetFunction());
+}
+
+Handle<Value> OutParam::New(const Arguments& args) {
+ HandleScope scope;
+
+ OutParam *client = new OutParam();
+ client->Wrap(args.This());
+ return args.This();
+}
+
+OutParam::OutParam() {
+}
+
+OutParam::~OutParam() {
+}
25 src/outParam.h
@@ -0,0 +1,25 @@
+
+#ifndef _outparam_h_
+#define _outparam_h_
+
+#include <v8.h>
+#include <node.h>
+#include <unistd.h>
+#include "utils.h"
+
+using namespace node;
+using namespace v8;
+
+class OutParam : ObjectWrap {
+public:
+ static void Init(Handle<Object> target);
+ static Handle<Value> New(const Arguments& args);
+ static Persistent<FunctionTemplate> constructorTemplate;
+
+ OutParam();
+ ~OutParam();
+
+private:
+};
+
+#endif
54 src/utils.h
@@ -0,0 +1,54 @@
+
+#ifndef _util_h_
+#define _util_h_
+
+#include <string>
+#include <sstream>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define REQ_STRING_ARG(I, VAR) \
+ if (args.Length() <= (I) || !args[I]->IsString()) \
+ return ThrowException(Exception::TypeError(String::New("Argument " #I " must be a string"))); \
+ Local<String> VAR = Local<String>::Cast(args[I]);
+
+#define REQ_ARRAY_ARG(I, VAR) \
+ if (args.Length() <= (I) || !args[I]->IsArray()) \
+ return ThrowException(Exception::TypeError(String::New("Argument " #I " must be an array"))); \
+ Local<Array> VAR = Local<Array>::Cast(args[I]);
+
+#define REQ_FUN_ARG(I, VAR) \
+ if (args.Length() <= (I) || !args[I]->IsFunction()) \
+ return ThrowException(Exception::TypeError(String::New("Argument " #I " must be a function"))); \
+ Local<Function> VAR = Local<Function>::Cast(args[I]);
+
+#define REQ_OBJECT_ARG(I, VAR) \
+ if (args.Length() <= (I) || !args[I]->IsObject()) \
+ return ThrowException(Exception::TypeError(String::New("Argument " #I " must be an object"))); \
+ Local<Object> VAR = Local<Object>::Cast(args[I]);
+
+#define OBJ_GET_STRING(OBJ, KEY, VAR) \
+ { \
+ Local<Value> __val = OBJ->Get(String::New(KEY)); \
+ if(__val->IsString()) { \
+ String::AsciiValue __asciiVal(__val); \
+ VAR = *__asciiVal; \
+ } \
+ }
+
+#define OBJ_GET_NUMBER(OBJ, KEY, VAR, DEFAULT) \
+ { \
+ Local<Value> __val = OBJ->Get(String::New(KEY)); \
+ if(__val->IsNumber()) { \
+ VAR = __val->ToNumber()->Value(); \
+ } \
+ else if(__val->IsString()) { \
+ String::AsciiValue __asciiVal(__val); \
+ VAR = atoi(*__asciiVal); \
+ } else { \
+ VAR = DEFAULT; \
+ } \
+ }
+
+
+#endif
5 tests-settings.json
@@ -0,0 +1,5 @@
+{
+ "hostname": "localhost",
+ "user": "test",
+ "password": "test"
+}
74 tests/integration.js
@@ -0,0 +1,74 @@
+
+/*
+ tests-settings.json:
+ {
+ "driver": "db-oracle",
+ "hostname": "localhost",
+ "user": "test",
+ "password": "test"
+ }
+
+ Database:
+ CREATE TABLE person (id INTEGER PRIMARY KEY, name VARCHAR(255));
+ CREATE SEQUENCE person_seq START WITH 1 INCREMENT BY 1 NOMAXVALUE;
+ CREATE TRIGGER person_pk_trigger BEFORE INSERT ON person FOR EACH row
+ BEGIN
+ SELECT person_seq.nextval INTO :new.id FROM dual;
+ END;
+ /
+*/
+
+var nodeunit = require("nodeunit");
+var oracle = require("../");
+
+var settings = JSON.parse(require('fs').readFileSync('./tests-settings.json','utf8'));
+
+exports['IntegrationTest'] = nodeunit.testCase({
+ setUp: function(callback) {
+ var self = this;
+ //console.log("connecting: ", settings);
+ oracle.connect(settings, function(err, connection) {
+ if(err) { callback(err); return; }
+ //console.log("connected");
+ self.connection = connection;
+ self.connection.execute("DELETE FROM person", [], function(err, results) {
+ if(err) { callback(err); return; }
+ //console.log("rows deleted: ", results);
+ callback();
+ });
+ });
+ },
+
+ tearDown: function(callback) {
+ if(this.connection) {
+ this.connection.close();
+ }
+ callback();
+ },
+
+ "select with single quote": function(test) {
+ var self = this;
+ self.connection.execute("INSERT INTO person (name) VALUES (:1)", ["Bill O'Neil"], function(err, results) {
+ if(err) { console.error(err); return; }
+ self.connection.execute("INSERT INTO person (name) VALUES (:1)", ["Bob Johnson"], function(err, results) {
+ if(err) { console.error(err); return; }
+ self.connection.execute("SELECT * FROM person WHERE name = :1", ["Bill O'Neil"], function(err, results) {
+ if(err) { console.error(err); return; }
+ //console.log(results);
+ test.equal(results.length, 1);
+ test.equal(results[0]['NAME'], "Bill O'Neil");
+ test.done();
+ });
+ });
+ });
+ },
+
+ "insert with returning value": function(test) {
+ var self = this;
+ self.connection.execute("INSERT INTO person (name) VALUES (:1) RETURNING id INTO :2", ["Bill O'Neil", new oracle.OutParam()], function(err, results) {
+ if(err) { console.error(err); return; }
+ test.ok(results.returnParam > 0);
+ test.done();
+ });
+ }
+});
39 wscript
@@ -0,0 +1,39 @@
+import Options, Utils
+from os import unlink, symlink, chdir, environ
+from os.path import exists
+
+#srcdir = "."
+#blddir = "build"
+#VERSION = "0.2.2"
+
+def set_options(opt):
+ opt.tool_options("compiler_cxx")
+
+def configure(conf):
+ conf.check_tool("compiler_cxx")
+ conf.check_tool("node_addon")
+
+ # Enables all the warnings that are easy to avoid
+ conf.env.append_unique('CXXFLAGS', ["-Wall"])
+ conf.env.append_unique('CXXFLAGS', ['-Isrc/'])
+ conf.env.append_unique('CXXFLAGS', ['-g'])
+ conf.env.append_unique('CXXFLAGS', ['-D_FILE_OFFSET_BITS=64'])
+ conf.env.append_unique('CXXFLAGS', ['-D_LARGEFILE_SOURCE'])
+
+ oci_include = environ.get("OCI_INCLUDE_DIR", "/usr/include/oracle/11.2/client")
+ if oci_include:
+ conf.env.append_unique('CXXFLAGS', [ '-I' + oci_include ])
+
+ oci_lib = environ.get("OCI_LIB_DIR", "/usr/lib/oracle/11.2/client/lib")
+ if oci_lib:
+ conf.env.append_unique('LINKFLAGS', [ '-L' + oci_lib ])
+
+ conf.env.append_unique('LINKFLAGS', ['-locci', '-lclntsh', '-lnnz11'])
+ conf.check(header_name="occi.h", errmsg="Missing include files for OCI", mandatory=True)
+ conf.check_cxx(lib="occi", errmsg="Missing libocci", mandatory=True)
+
+def build(bld):
+ obj = bld.new_task_gen("cxx", "shlib", "node_addon")
+ obj.target = "oracle_bindings"
+ obj.source = "src/connection.cpp src/outParam.cpp src/oracle_bindings.cpp"
+ obj.includes = "src/"

0 comments on commit 43fee35

Please sign in to comment.