1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 //  Copyright (C) 2010-2011  Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com>
4 //
5 //  Distributed under:
6 //
7 //                   the Boost Software License, Version 1.0.
8 //              (See accompanying file LICENSE_1_0.txt or copy at
9 //                     http://www.boost.org/LICENSE_1_0.txt)
10 //
11 //  or (at your opinion) under:
12 //
13 //                               The MIT License
14 //                 (See accompanying file MIT.txt or a copy at
15 //              http://www.opensource.org/licenses/mit-license.php)
16 //
17 ///////////////////////////////////////////////////////////////////////////////
18 #define CPPDB_SOURCE
19 #include <cppdb/frontend.h>
20 #include <cppdb/backend.h>
21 #include <cppdb/conn_manager.h>
22 #include <cppdb/pool.h>
23 
24 namespace cppdb {
25 	struct result::data {};
26 
27 	class throw_guard {
28 	public:
throw_guard(ref_ptr<backend::connection> const & conn)29 		throw_guard(ref_ptr<backend::connection> const &conn) : conn_(conn.get())
30 		{
31 		}
done()32 		void done()
33 		{
34 			conn_ = 0;
35 		}
~throw_guard()36 		~throw_guard()
37 		{
38 			if(conn_ && std::uncaught_exception()) {
39 				conn_->recyclable(false);
40 			}
41 		}
42 	private:
43 		backend::connection *conn_;
44 	};
45 
result()46 	result::result() :
47 		eof_(false),
48 		fetched_(false),
49 		current_col_(0)
50 	{
51 	}
result(ref_ptr<backend::result> res,ref_ptr<backend::statement> stat,ref_ptr<backend::connection> conn)52 	result::result(	ref_ptr<backend::result> res,
53 			ref_ptr<backend::statement> stat,
54 			ref_ptr<backend::connection> conn)
55 	: eof_(false),
56 	  fetched_(false),
57 	  current_col_(0),
58 	  res_(res),
59 	  stat_(stat),
60 	  conn_(conn)
61 	{
62 	}
result(result const & other)63 	result::result(result const &other) :
64 		eof_(other.eof_),
65 		fetched_(other.fetched_),
66 		current_col_(other.current_col_),
67 		res_(other.res_),
68 		stat_(other.stat_),
69 		conn_(other.conn_)
70 	{
71 	}
72 
operator =(result const & other)73 	result const &result::operator=(result const &other)
74 	{
75 		eof_ = other.eof_;
76 		fetched_ = other.fetched_;
77 		current_col_ = other.current_col_;
78 		res_ = other.res_;
79 		stat_ = other.stat_;
80 		conn_ = other.conn_;
81 		return *this;
82 	}
83 
~result()84 	result::~result()
85 	{
86 		clear();
87 	}
88 
cols()89 	int result::cols()
90 	{
91 		return res_->cols();
92 	}
93 
next()94 	bool result::next()
95 	{
96 		throw_guard g(conn_);
97 
98 		if(eof_)
99 			return false;
100 		fetched_=true;
101 		eof_ = res_->next()==false;
102 		current_col_ = 0;
103 		return !eof_;
104 	}
105 
index(std::string const & n)106 	int result::index(std::string const &n)
107 	{
108 		int c = res_->name_to_column(n);
109 		if(c<0)
110 			throw invalid_column();
111 		return c;
112 	}
113 
name(int col)114 	std::string result::name(int col)
115 	{
116 		if(col < 0 || col>= cols())
117 			throw invalid_column();
118 		return res_->column_to_name(col);
119 	}
120 
find_column(std::string const & name)121 	int result::find_column(std::string const &name)
122 	{
123 		int c = res_->name_to_column(name);
124 		if(c < 0)
125 			return -1;
126 		return c;
127 	}
128 
rewind_column()129 	void result::rewind_column()
130 	{
131 		current_col_ = 0;
132 	}
133 
empty()134 	bool result::empty()
135 	{
136 		if(!res_)
137 			return true;
138 		return eof_ || !fetched_;
139 	}
140 
clear()141 	void result::clear()
142 	{
143 		eof_ = true;
144 		fetched_ = true;
145 		res_.reset();
146 		stat_.reset();
147 		conn_.reset();
148 	}
149 
check()150 	void result::check()
151 	{
152 		if(empty())
153 			throw empty_row_access();
154 	}
155 
is_null(int col)156 	bool result::is_null(int col)
157 	{
158 		return res_->is_null(col);
159 	}
is_null(std::string const & n)160 	bool result::is_null(std::string const &n)
161 	{
162 		return is_null(index(n));
163 	}
164 
165 
fetch(int col,short & v)166 	bool result::fetch(int col,short &v) { return res_->fetch(col,v); }
fetch(int col,unsigned short & v)167 	bool result::fetch(int col,unsigned short &v) { return res_->fetch(col,v); }
fetch(int col,int & v)168 	bool result::fetch(int col,int &v) { return res_->fetch(col,v); }
fetch(int col,unsigned & v)169 	bool result::fetch(int col,unsigned &v) { return res_->fetch(col,v); }
fetch(int col,long & v)170 	bool result::fetch(int col,long &v) { return res_->fetch(col,v); }
fetch(int col,unsigned long & v)171 	bool result::fetch(int col,unsigned long &v) { return res_->fetch(col,v); }
fetch(int col,long long & v)172 	bool result::fetch(int col,long long &v) { return res_->fetch(col,v); }
fetch(int col,unsigned long long & v)173 	bool result::fetch(int col,unsigned long long &v) { return res_->fetch(col,v); }
fetch(int col,float & v)174 	bool result::fetch(int col,float &v) { return res_->fetch(col,v); }
fetch(int col,double & v)175 	bool result::fetch(int col,double &v) { return res_->fetch(col,v); }
fetch(int col,long double & v)176 	bool result::fetch(int col,long double &v) { return res_->fetch(col,v); }
fetch(int col,std::string & v)177 	bool result::fetch(int col,std::string &v) { return res_->fetch(col,v); }
fetch(int col,std::tm & v)178 	bool result::fetch(int col,std::tm &v) { return res_->fetch(col,v); }
fetch(int col,std::ostream & v)179 	bool result::fetch(int col,std::ostream &v) { return res_->fetch(col,v); }
180 
fetch(std::string const & n,short & v)181 	bool result::fetch(std::string const &n,short &v) { return res_->fetch(index(n),v); }
fetch(std::string const & n,unsigned short & v)182 	bool result::fetch(std::string const &n,unsigned short &v) { return res_->fetch(index(n),v); }
fetch(std::string const & n,int & v)183 	bool result::fetch(std::string const &n,int &v) { return res_->fetch(index(n),v); }
fetch(std::string const & n,unsigned & v)184 	bool result::fetch(std::string const &n,unsigned &v) { return res_->fetch(index(n),v); }
fetch(std::string const & n,long & v)185 	bool result::fetch(std::string const &n,long &v) { return res_->fetch(index(n),v); }
fetch(std::string const & n,unsigned long & v)186 	bool result::fetch(std::string const &n,unsigned long &v) { return res_->fetch(index(n),v); }
fetch(std::string const & n,long long & v)187 	bool result::fetch(std::string const &n,long long &v) { return res_->fetch(index(n),v); }
fetch(std::string const & n,unsigned long long & v)188 	bool result::fetch(std::string const &n,unsigned long long &v) { return res_->fetch(index(n),v); }
fetch(std::string const & n,float & v)189 	bool result::fetch(std::string const &n,float &v) { return res_->fetch(index(n),v); }
fetch(std::string const & n,double & v)190 	bool result::fetch(std::string const &n,double &v) { return res_->fetch(index(n),v); }
fetch(std::string const & n,long double & v)191 	bool result::fetch(std::string const &n,long double &v) { return res_->fetch(index(n),v); }
fetch(std::string const & n,std::string & v)192 	bool result::fetch(std::string const &n,std::string &v) { return res_->fetch(index(n),v); }
fetch(std::string const & n,std::tm & v)193 	bool result::fetch(std::string const &n,std::tm &v) { return res_->fetch(index(n),v); }
fetch(std::string const & n,std::ostream & v)194 	bool result::fetch(std::string const &n,std::ostream &v) { return res_->fetch(index(n),v); }
195 
fetch(short & v)196 	bool result::fetch(short &v) { return res_->fetch(current_col_++,v); }
fetch(unsigned short & v)197 	bool result::fetch(unsigned short &v) { return res_->fetch(current_col_++,v); }
fetch(int & v)198 	bool result::fetch(int &v) { return res_->fetch(current_col_++,v); }
fetch(unsigned & v)199 	bool result::fetch(unsigned &v) { return res_->fetch(current_col_++,v); }
fetch(long & v)200 	bool result::fetch(long &v) { return res_->fetch(current_col_++,v); }
fetch(unsigned long & v)201 	bool result::fetch(unsigned long &v) { return res_->fetch(current_col_++,v); }
fetch(long long & v)202 	bool result::fetch(long long &v) { return res_->fetch(current_col_++,v); }
fetch(unsigned long long & v)203 	bool result::fetch(unsigned long long &v) { return res_->fetch(current_col_++,v); }
fetch(float & v)204 	bool result::fetch(float &v) { return res_->fetch(current_col_++,v); }
fetch(double & v)205 	bool result::fetch(double &v) { return res_->fetch(current_col_++,v); }
fetch(long double & v)206 	bool result::fetch(long double &v) { return res_->fetch(current_col_++,v); }
fetch(std::string & v)207 	bool result::fetch(std::string &v) { return res_->fetch(current_col_++,v); }
fetch(std::tm & v)208 	bool result::fetch(std::tm &v) { return res_->fetch(current_col_++,v); }
fetch(std::ostream & v)209 	bool result::fetch(std::ostream &v) { return res_->fetch(current_col_++,v); }
210 
211 
212 
213 	struct statement::data {};
214 
statement()215 	statement::statement() : placeholder_(1) {}
~statement()216 	statement::~statement()
217 	{
218 		stat_.reset();
219 		conn_.reset();
220 	}
221 
statement(statement const & other)222 	statement::statement(statement const &other) :
223 		placeholder_(other.placeholder_),
224 		stat_(other.stat_),
225 		conn_(other.conn_)
226 	{
227 	}
operator =(statement const & other)228 	statement const &statement::operator=(statement const &other)
229 	{
230 		placeholder_ = other.placeholder_;
231 		stat_=other.stat_;
232 		conn_=other.conn_;
233 		return *this;
234 	}
235 
statement(ref_ptr<backend::statement> stat,ref_ptr<backend::connection> conn)236 	statement::statement(ref_ptr<backend::statement> stat,ref_ptr<backend::connection> conn) :
237 		placeholder_(1),
238 		stat_(stat),
239 		conn_(conn)
240 	{
241 	}
242 
empty() const243 	bool statement::empty() const
244 	{
245 		return !stat_;
246 	}
247 
clear()248 	void statement::clear()
249 	{
250 		stat_.reset();
251 		conn_.reset();
252 	}
253 
reset()254 	void statement::reset()
255 	{
256 		throw_guard g(conn_);
257 		placeholder_ = 1;
258 		stat_->reset();
259 	}
260 
operator <<(std::string const & v)261 	statement &statement::operator<<(std::string const &v)
262 	{
263 		return bind(v);
264 	}
operator <<(char const * s)265 	statement &statement::operator<<(char const *s)
266 	{
267 		return bind(s);
268 	}
269 
operator <<(std::tm const & v)270 	statement &statement::operator<<(std::tm const &v)
271 	{
272 		return bind(v);
273 	}
274 
operator <<(std::istream & v)275 	statement &statement::operator<<(std::istream &v)
276 	{
277 		return bind(v);
278 	}
279 
operator <<(void (* manipulator)(statement & st))280 	statement &statement::operator<<(void (*manipulator)(statement &st))
281 	{
282 		manipulator(*this);
283 		return *this;
284 	}
operator <<(result (* manipulator)(statement & st))285 	result statement::operator<<(result (*manipulator)(statement &st))
286 	{
287 		return manipulator(*this);
288 	}
289 
bind(int v)290 	statement &statement::bind(int v)
291 	{
292 		stat_->bind(placeholder_++,v);
293 		return *this;
294 	}
bind(unsigned v)295 	statement &statement::bind(unsigned v)
296 	{
297 		stat_->bind(placeholder_++,v);
298 		return *this;
299 	}
bind(long v)300 	statement &statement::bind(long v)
301 	{
302 		stat_->bind(placeholder_++,v);
303 		return *this;
304 	}
bind(unsigned long v)305 	statement &statement::bind(unsigned long v)
306 	{
307 		stat_->bind(placeholder_++,v);
308 		return *this;
309 	}
bind(long long v)310 	statement &statement::bind(long long v)
311 	{
312 		stat_->bind(placeholder_++,v);
313 		return *this;
314 	}
bind(unsigned long long v)315 	statement &statement::bind(unsigned long long v)
316 	{
317 		stat_->bind(placeholder_++,v);
318 		return *this;
319 	}
bind(double v)320 	statement &statement::bind(double v)
321 	{
322 		stat_->bind(placeholder_++,v);
323 		return *this;
324 	}
bind(long double v)325 	statement &statement::bind(long double v)
326 	{
327 		stat_->bind(placeholder_++,v);
328 		return *this;
329 	}
330 
bind(std::string const & v)331 	statement &statement::bind(std::string const &v)
332 	{
333 		stat_->bind(placeholder_++,v);
334 		return *this;
335 	}
bind(char const * s)336 	statement &statement::bind(char const *s)
337 	{
338 		stat_->bind(placeholder_++,s);
339 		return *this;
340 	}
bind(char const * b,char const * e)341 	statement &statement::bind(char const *b,char const *e)
342 	{
343 		stat_->bind(placeholder_++,b,e);
344 		return *this;
345 	}
bind(std::tm const & v)346 	statement &statement::bind(std::tm const &v)
347 	{
348 		stat_->bind(placeholder_++,v);
349 		return *this;
350 	}
bind(std::istream & v)351 	statement &statement::bind(std::istream &v)
352 	{
353 		stat_->bind(placeholder_++,v);
354 		return *this;
355 	}
bind_null()356 	statement &statement::bind_null()
357 	{
358 		stat_->bind_null(placeholder_++);
359 		return *this;
360 	}
361 
362 
bind(int col,std::string const & v)363 	void statement::bind(int col,std::string const &v)
364 	{
365 		stat_->bind(col,v);
366 	}
bind(int col,char const * s)367 	void statement::bind(int col,char const *s)
368 	{
369 		stat_->bind(col,s);
370 	}
bind(int col,char const * b,char const * e)371 	void statement::bind(int col,char const *b,char const *e)
372 	{
373 		stat_->bind(col,b,e);
374 	}
bind(int col,std::tm const & v)375 	void statement::bind(int col,std::tm const &v)
376 	{
377 		stat_->bind(col,v);
378 	}
bind(int col,std::istream & v)379 	void statement::bind(int col,std::istream &v)
380 	{
381 		stat_->bind(col,v);
382 	}
bind(int col,int v)383 	void statement::bind(int col,int v)
384 	{
385 		stat_->bind(col,v);
386 	}
bind(int col,unsigned v)387 	void statement::bind(int col,unsigned v)
388 	{
389 		stat_->bind(col,v);
390 	}
bind(int col,long v)391 	void statement::bind(int col,long v)
392 	{
393 		stat_->bind(col,v);
394 	}
bind(int col,unsigned long v)395 	void statement::bind(int col,unsigned long v)
396 	{
397 		stat_->bind(col,v);
398 	}
bind(int col,long long v)399 	void statement::bind(int col,long long v)
400 	{
401 		stat_->bind(col,v);
402 	}
bind(int col,unsigned long long v)403 	void statement::bind(int col,unsigned long long v)
404 	{
405 		stat_->bind(col,v);
406 	}
bind(int col,double v)407 	void statement::bind(int col,double v)
408 	{
409 		stat_->bind(col,v);
410 	}
bind(int col,long double v)411 	void statement::bind(int col,long double v)
412 	{
413 		stat_->bind(col,v);
414 	}
bind_null(int col)415 	void statement::bind_null(int col)
416 	{
417 		stat_->bind_null(col);
418 	}
419 
last_insert_id()420 	long long statement::last_insert_id()
421 	{
422 		throw_guard g(conn_);
423 		return stat_->sequence_last(std::string());
424 	}
425 
sequence_last(std::string const & seq)426 	long long statement::sequence_last(std::string const &seq)
427 	{
428 		throw_guard g(conn_);
429 		return stat_->sequence_last(seq);
430 	}
affected()431 	unsigned long long statement::affected()
432 	{
433 		throw_guard g(conn_);
434 		return stat_->affected();
435 	}
436 
row()437 	result statement::row()
438 	{
439 		throw_guard g(conn_);
440 		ref_ptr<backend::result> backend_res = stat_->query();
441 		result res(backend_res,stat_,conn_);
442 		if(res.next()) {
443 			if(res.res_->has_next() == backend::result::next_row_exists) {
444 				g.done();
445 				throw multiple_rows_query();
446 			}
447 		}
448 		return res;
449 	}
450 
query()451 	result statement::query()
452 	{
453 		throw_guard g(conn_);
454 		ref_ptr<backend::result> res(stat_->query());
455 		return result(res,stat_,conn_);
456 	}
operator result()457 	statement::operator result()
458 	{
459 		return query();
460 	}
exec()461 	void statement::exec()
462 	{
463 		throw_guard g(conn_);
464 		stat_->exec();
465 	}
466 
467 	struct session::data {};
468 
session()469 	session::session()
470 	{
471 	}
session(session const & other)472 	session::session(session const &other) :
473 		conn_(other.conn_)
474 	{
475 	}
operator =(session const & other)476 	session const &session::operator=(session const &other)
477 	{
478 		conn_ = other.conn_;
479 		return *this;
480 	}
session(ref_ptr<backend::connection> conn)481 	session::session(ref_ptr<backend::connection> conn) : conn_(conn)
482 	{
483 	}
session(ref_ptr<backend::connection> conn,once_functor const & f)484 	session::session(ref_ptr<backend::connection> conn,once_functor const &f) : conn_(conn)
485 	{
486 		once(f);
487 	}
~session()488 	session::~session()
489 	{
490 	}
session(connection_info const & ci)491 	session::session(connection_info const &ci)
492 	{
493 		open(ci);
494 	}
session(std::string const & cs)495 	session::session(std::string const &cs)
496 	{
497 		open(cs);
498 	}
session(connection_info const & ci,once_functor const & f)499 	session::session(connection_info const &ci,once_functor const &f)
500 	{
501 		open(ci);
502 		once(f);
503 	}
session(std::string const & cs,once_functor const & f)504 	session::session(std::string const &cs,once_functor const &f)
505 	{
506 		open(cs);
507 		once(f);
508 	}
509 
open(connection_info const & ci)510 	void session::open(connection_info const &ci)
511 	{
512 		conn_ = connections_manager::instance().open(ci);
513 	}
open(std::string const & cs)514 	void session::open(std::string const &cs)
515 	{
516 		conn_ = connections_manager::instance().open(cs);
517 	}
close()518 	void session::close()
519 	{
520 		conn_.reset();
521 	}
522 
is_open()523 	bool session::is_open()
524 	{
525 		return conn_;
526 	}
527 
prepare(std::string const & query)528 	statement session::prepare(std::string const &query)
529 	{
530 		throw_guard g(conn_);
531 		ref_ptr<backend::statement> stat_ptr(conn_->prepare(query));
532 		statement stat(stat_ptr,conn_);
533 		return stat;
534 	}
535 
create_statement(std::string const & query)536 	statement session::create_statement(std::string const &query)
537 	{
538 		throw_guard g(conn_);
539 		ref_ptr<backend::statement> stat_ptr(conn_->get_statement(query));
540 		statement stat(stat_ptr,conn_);
541 		return stat;
542 	}
543 
create_prepared_statement(std::string const & query)544 	statement session::create_prepared_statement(std::string const &query)
545 	{
546 		throw_guard g(conn_);
547 		ref_ptr<backend::statement> stat_ptr(conn_->get_prepared_statement(query));
548 		statement stat(stat_ptr,conn_);
549 		return stat;
550 	}
551 
create_prepared_uncached_statement(std::string const & query)552 	statement session::create_prepared_uncached_statement(std::string const &query)
553 	{
554 		throw_guard g(conn_);
555 		ref_ptr<backend::statement> stat_ptr(conn_->get_prepared_uncached_statement(query));
556 		statement stat(stat_ptr,conn_);
557 		return stat;
558 	}
559 
560 
operator <<(std::string const & q)561 	statement session::operator<<(std::string const &q)
562 	{
563 		return prepare(q);
564 	}
operator <<(char const * s)565 	statement session::operator<<(char const *s)
566 	{
567 		return prepare(s);
568 	}
begin()569 	void session::begin()
570 	{
571 		throw_guard g(conn_);
572 		conn_->begin();
573 	}
commit()574 	void session::commit()
575 	{
576 		throw_guard g(conn_);
577 		conn_->commit();
578 	}
rollback()579 	void session::rollback()
580 	{
581 		throw_guard g(conn_);
582 		conn_->rollback();
583 	}
escape(char const * b,char const * e)584 	std::string session::escape(char const *b,char const *e)
585 	{
586 		return conn_->escape(b,e);
587 	}
escape(char const * s)588 	std::string session::escape(char const *s)
589 	{
590 		return conn_->escape(s);
591 	}
escape(std::string const & s)592 	std::string session::escape(std::string const &s)
593 	{
594 		return conn_->escape(s);
595 	}
driver()596 	std::string session::driver()
597 	{
598 		return conn_->driver();
599 	}
engine()600 	std::string session::engine()
601 	{
602 		return conn_->engine();
603 	}
604 
once_called(bool v)605 	void session::once_called(bool v)
606 	{
607 		conn_->once_called(v);
608 	}
once_called()609 	bool session::once_called()
610 	{
611 		return conn_->once_called();
612 	}
613 
once(once_functor const & f)614 	void session::once(once_functor const &f)
615 	{
616 		if(!once_called()) {
617 			f(*this);
618 			once_called(true);
619 		}
620 	}
621 
622 	struct transaction::data {};
623 
transaction(session & s)624 	transaction::transaction(session &s) :
625 		s_(&s),
626 		commited_(false)
627 	{
628 		s_->begin();
629 	}
630 
commit()631 	void transaction::commit()
632 	{
633 		s_->commit();
634 		commited_ =true;
635 	}
rollback()636 	void transaction::rollback()
637 	{
638 		if(!commited_)
639 			s_->rollback();
640 		commited_=true;
641 	}
~transaction()642 	transaction::~transaction()
643 	{
644 		try {
645 			rollback();
646 		}
647 		catch(...)
648 		{
649 		}
650 	}
651 
clear_cache()652 	void session::clear_cache()
653 	{
654 		conn_->clear_cache();
655 	}
656 
clear_pool()657 	void session::clear_pool()
658 	{
659 		conn_->clear_cache();
660 		conn_->recyclable(false);
661 		conn_->get_pool()->clear();
662 	}
663 
recyclable()664 	bool session::recyclable()
665 	{
666 		return conn_->recyclable();
667 	}
recyclable(bool v)668 	void session::recyclable(bool v)
669 	{
670 		conn_->recyclable(v);
671 	}
672 
get_specific(std::type_info const & t)673 	connection_specific_data *session::get_specific(std::type_info const &t)
674 	{
675 		return conn_->connection_specific_get(t);
676 	}
release_specific(std::type_info const & t)677 	connection_specific_data *session::release_specific(std::type_info const &t)
678 	{
679 		return conn_->connection_specific_release(t);
680 	}
reset_specific(std::type_info const & t,connection_specific_data * p)681 	void session::reset_specific(std::type_info const &t,connection_specific_data *p)
682 	{
683 		conn_->connection_specific_reset(t,p);
684 	}
685 
version_string()686 	char const *version_string()
687 	{
688 		return CPPDB_VERSION;
689 	}
version_number()690 	int version_number()
691 	{
692 		return CPPDB_MAJOR * 10000 + CPPDB_MINOR * 100 + CPPDB_PATCH;
693 	}
694 
695 }  // cppdb
696