nodejs-db-informix  master
nodejs bindings for Informix
 All Classes Functions Pages
connection.cxx
1 #include "connection.h"
2 #include <sstream>
3 
4 nodejs_db_informix::Connection::Connection()
5  : compress(false),
6  readTimeout(0),
7  reconnect(true),
8  sslVerifyServer(false),
9  timeout(0),
10  writeTimeout(0)
11 {
12  this->port = 0;
13 
14  // construct connection from environment variables
15  this->connection = new ITConnection();
16 }
17 
18 nodejs_db_informix::Connection::Connection(
19  std::string h,
20  std::string u,
21  std::string pw,
22  std::string d,
23  uint32_t p
24 ) {
25  this->setHostname(h);
26  this->setUser(u);
27  this->setPassword(pw);
28  this->setDatabase(d);
29  this->setPort(p);
30 }
31 
32 nodejs_db_informix::Connection::~Connection() {
33  this->close();
34 }
35 
36 void
37 nodejs_db_informix::Connection::setCharset(
38  const std::string& charset
39 ) throw() {
40  this->charset = charset;
41 }
42 
43 void
44 nodejs_db_informix::Connection::setCompress(const bool compress) throw() {
45  this->compress = compress;
46 }
47 
48 void
49 nodejs_db_informix::Connection::setInitCommand(
50  const std::string& initCommand
51 ) throw() {
52  this->initCommand = initCommand;
53 }
54 
55 void
56 nodejs_db_informix::Connection::setReadTimeout(
57  const uint32_t readTimeout
58 ) throw() {
59  this->readTimeout = readTimeout;
60 }
61 
62 void
63 nodejs_db_informix::Connection::setReconnect(
64  const bool reconnect
65 ) throw() {
66  this->reconnect = reconnect;
67 }
68 
69 void
70 nodejs_db_informix::Connection::setSocket(const std::string& socket) throw() {
71  this->socket = socket;
72 }
73 
74 void
75 nodejs_db_informix::Connection::setSslVerifyServer(
76  const bool sslVerifyServer
77 ) throw() {
78  this->sslVerifyServer = sslVerifyServer;
79 }
80 
81 void nodejs_db_informix::Connection::setTimeout(
82  const uint32_t timeout
83 ) throw() {
84  this->timeout = timeout;
85 }
86 
87 void
88 nodejs_db_informix::Connection::setWriteTimeout(
89  const uint32_t writeTimeout
90 ) throw() {
91  this->writeTimeout = writeTimeout;
92 }
93 
94 bool
95 nodejs_db_informix::Connection::isAlive(bool ping) throw() {
96  if (this->alive) {
97  this->alive = this->connection->IsOpen();
98  }
99 
100 #ifdef DEV
101  std::cout << "IsAlive() == " << this->alive << std::endl;
102 #endif
103 
104  return this->alive;
105 }
106 
107 /**
108  * XXX: do we really need to pass dbInfo?
109  */
110 bool
112  // dbInfo = new ITDBInfo();
113 
114  // setup any custom parameters passed
115  std::string db = this->getDatabase();
116  if (db.c_str()
117  && !db.empty()
118  && !dbInfo.SetDatabase(ITString(db.c_str()))) {
119  std::cerr << "Failed to set database " << db << std::endl;
120  }
121 
122  std::string u = this->getUser();
123  if (u.c_str()
124  && !u.empty()
125  && !dbInfo.SetUser(ITString(u.c_str()))) {
126  std::cerr << "Failed to set username " << u << std::endl;
127  }
128 
129  std::string h = this->getHostname();
130  if (h.c_str()
131  && !h.empty()
132  && !dbInfo.SetSystem(ITString(h.c_str()))) {
133  std::cerr << "Failed to set hostname " << h << std::endl;
134  }
135 
136  std::string pw = this->getPassword();
137  if (pw.c_str()
138  && !pw.empty()
139  && !dbInfo.SetPassword(ITString(pw.c_str()))) {
140  std::cerr << "Failed to set password " << pw << std::endl;
141  }
142 
143  return true;
144 }
145 
146 void
147 nodejs_db_informix::Connection::open() throw(nodejs_db::Exception&) {
148  // close connection if any
149  // and don't worry about the return of this close
150  this->close();
151 
152  if (this->connection->IsOpen()) {
153  throw nodejs_db::Exception("Database connection is alreay open");
154  }
155 
156  ITDBInfo dbInfo = this->connection->GetDBInfo();
157 
158  if (dbInfo.Frozen()) {
159  throw nodejs_db::Exception("Database connection is alreay open");
160  }
161 
162  if (dbInfo.GetSystem().IsNull()) {
163  throw nodejs_db::Exception("Which system to connect to?");
164  }
165 
166  if (dbInfo.GetDatabase().IsNull()) {
167  throw nodejs_db::Exception("No database name specified");
168  }
169 
170  if (dbInfo.GetUser().IsNull()) {
171  throw nodejs_db::Exception("No database username specified");
172  }
173 
174  // prepare dbInfo
175  if (!this->_prepareITDBInfo(dbInfo)) {
176  throw nodejs_db::Exception("Could not prepare ITDBInfo");
177  }
178 
179 #ifdef DEV
180  std::cout << "Connecting with " << std::endl
181  << "User: " << dbInfo.GetUser().Data() << std::endl
182  << "System: " << dbInfo.GetSystem().Data() << std::endl
183  << "Database: " << dbInfo.GetDatabase().Data() << std::endl
184  ;
185 #endif
186 
187  // setup the dbInfo
188  if (!this->connection->SetDBInfo(dbInfo)) {
189  throw nodejs_db::Exception("Could not set the ITDBINfo");
190  }
191 
192  // open connection
193  if (!(this->alive = this->connection->Open())) {
194  throw nodejs_db::Exception("Connection failed!");
195  }
196 
197  // check if everything went ok.
198  if (!this->connection->IsOpen()) {
199  this->alive = false;
200  throw nodejs_db::Exception("Cannot create Informix connection");
201  }
202 }
203 
204 void
205 nodejs_db_informix::Connection::close() {
206  if (this->alive) {
207  if(this->connection->Close()) {
208  this->alive = false;
209  }
210  }
211  this->alive = false;
212 }
213 
214 /**
215  * Escape single quotes, line feed and carriage return
216  *
217  */
218 std::string
220 const throw(nodejs_db::Exception&) {
221  std::string result(s);
222  size_t pos = 0;
223  while (true) {
224  pos = result.find("'", pos);
225  if (pos == std::string::npos)
226  break;
227  result.insert(pos, "'");
228  // move forward
229  pos += 2;
230  }
231 
232  pos = 0;
233  while (true) {
234  pos = result.find("\n", pos);
235  if (pos == std::string::npos)
236  break;
237  result.erase(pos, 1);
238  result.insert(pos, "\\n");
239  }
240 
241  pos = 0;
242  while (true) {
243  pos = result.find("\r", pos);
244  if (pos == std::string::npos)
245  break;
246  result.erase(pos, 1);
247  result.insert(pos, "\\r");
248  }
249 
250  return result;
251 }
252 
253 
254 
255 /**
256  * Version string
257  */
258 std::string
260  return std::string("0.0.11");
261 }
262 
263 
264 
265 #ifdef DEV
266 void
267 nodejs_db_informix::Connection::_testExecForIteration() const {
268  ITQuery q_tmp(*(this->connection));
269  std::string qry("select * from sysmaster:sysdatabases");
270 
271  if (!q_tmp.ExecForIteration(qry.c_str())) {
272  std::cerr << "Could not execute query: " << qry << std::endl;
273  return;
274  }
275 
276  const ITTypeInfo *ti = q_tmp.RowType();
277  for (long cc = 0; cc < ti->ColumnCount(); ++cc) {
278  if (!ti->ColumnName(cc).IsNull()) {
279  std::cout << "Column " << cc << ": "
280  << ti->ColumnName(cc).Data() << std::endl;
281  } else {
282  std::cerr << "Column " << cc << ": Error!" << std::endl;
283  }
284  }
285 
286  ITRow *row;
287  int rc = 0;
288  while ((row = q_tmp.NextRow()) != NULL) {
289  ++rc;
290  std::cout << row->Printable() << std::endl;
291  row->Release();
292  }
293  std::cout << rc << " rows returned" << std::endl
294  << "Query: " << qry << std::endl;
295 
296  return;
297 }
298 #endif
299 
300 
301 
302 ITCallbackResult
303 // nodejs_db_informix::Connection::_QueryErrorHandler(
304 _QueryErrorHandler(
305  const ITErrorManager& err
306  , void* args
307  , long errCode
308 ) {
309  std::ostream *s = (std::ostream*) args;
310  (*s) << "Query: [" << errCode << "]"
311  << err.SqlState().Data() << ' '
312  << err.ErrorText().Data()
313  << std::endl;
314 
315  return IT_NOTHANDLED;
316 }
317 
318 
319 
320 /**
321  * execute select query
322  */
325  const std::string& query
326 ) const throw(nodejs_db::Exception&) {
327 
328 #ifdef DEV
329  this->_testExecForIteration();
330 #endif
331 
332 #ifdef DEBUG
333  std::cout << "nodejs_db_informix::Connection::query" << std::endl;
334 #endif
335 
336  ITQuery q(*(this->connection));
337 
338  q.AddCallback(_QueryErrorHandler, (void*) &std::cerr);
339 
340  ITSet *rs = q.ExecToSet(query.c_str());
341 
342  if (rs == NULL || q.RowCount() < 0) {
343  std::stringstream err;
344 
345  if (q.Warn()) {
346  err << "sqlstate: "
347  << q.SqlState().Data()
348  << ", warn: "
349  << q.WarningText().Data()
350  << ", "
351  ;
352  }
353 
354  if (q.Error()) {
355  err << "sqlstate: "
356  << q.SqlState().Data()
357  << ", error: "
358  << q.ErrorText().Data()
359  << ", "
360  ;
361  }
362 
363  err << "Could not execute query: " << query;
364  throw nodejs_db::Exception(err.str());
365  }
366 
367  // let the caller handle problems with q.RowType()
368  return new nodejs_db_informix::Result(rs, q.RowType(), q.RowCount());
369 }
370 
371 
372 
373 /**
374  * For insert, update, delete etc. we need a different ITQuery object
375  * Therefore, we need a new function
376  */
379  const std::string& query
380 ) const throw(nodejs_db::Exception&) {
381 #ifdef DEBUG
382  std::cout << "nodejs_db_informix::Connection::query_x" << std::endl;
383 #endif
384  ITQuery q(*(this->connection));
385 
386  q.AddCallback(_QueryErrorHandler, (void*) &std::cerr);
387 
388  ITBool s = q.ExecForStatus(query.c_str());
389 
390  if (!s) {
391  std::stringstream err;
392 
393  if (q.Warn()) {
394  err << "sqlstate: "
395  << q.SqlState().Data()
396  << ", warn: "
397  << q.WarningText().Data()
398  << ", "
399  ;
400  }
401 
402  if (q.Error()) {
403  err << "sqlstate: "
404  << q.SqlState().Data()
405  << ", error: "
406  << q.ErrorText().Data()
407  << ", "
408  ;
409  }
410 
411  err << "Could not execute query.";
412  throw nodejs_db::Exception(err.str());
413  }
414 
415 #ifdef DEBUG
416  // query type
417  ITString qt = q.Command();
418 
419  std::cout << "Type of query: " << qt.Data() << std::endl;
420  std::cout << "Result of DML: " << s << std::endl;
421 #endif
422 
423  return new nodejs_db_informix::Result(s, q.RowCount());
424 }