File:  [parser3project] / parser3 / src / include / pa_sql_connection.h
Revision 1.30.2.5: download - view: text, annotated - select for diffs - revision graph
Fri Jan 31 12:10:45 2003 UTC (23 years, 5 months ago) by paf
Diff to: branchpoint 1.30: preferred, unified
ConstStringPtr died, long live StringPtr

/** @file
	Parser: sql fconnection decl.

	Copyright (c) 2001, 2003 ArtLebedev Group (http://www.artlebedev.com)
	Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru)
*/

#ifndef PA_SQL_CONNECTION_H
#define PA_SQL_CONNECTION_H

static const char* IDENT_SQL_CONNECTION_H="$Date: 2003/01/31 12:10:45 $";

#include "pa_pool.h"
#include "pa_sql_driver.h"
#include "pa_sql_driver_manager.h"

// defines

/// @see SQL_Driver_services_impl::_throw
#ifdef PA_WITH_SJLJ_EXCEPTIONS
	#define SQL_CONNECTION_SERVICED_FUNC_GUARDED(actions) actions
#else
	#define SQL_CONNECTION_SERVICED_FUNC_GUARDED(actions) \
		if(!setjmp(fservices.mark)) { \
			actions; \
		} else \
			fservices.propagate_exception();
#endif

/// SQL_Driver_services Pooled implementation
class SQL_Driver_services_impl: public SQL_Driver_services {
	Pool *fpool;
	StringPtr furl;
	Exception fexception;
public:
	SQL_Driver_services_impl(): fpool(0), furl(0) {}
	void set_pool_and_url(Pool *apool, StringPtr aurl) { fpool=apool; furl=aurl;}

	override void *malloc(size_t size) { return fpool->malloc(size); }
	override void *calloc(size_t size) { return fpool->calloc(size); }
	override void *realloc(void *ptr, size_t size) { return fpool->realloc(ptr, size); }

	/**
		normally we can't 'throw' from dynamic library, so
		the idea is to #1 jump to C++ some function to main body, where
		every function stack frame has exception unwind information
		and from there... #2 propagate_exception()

        but when parser configured --with-sjlj-exceptions
		one can simply 'throw' from dynamic library.
		[sad story: one can not longjump/throw due to some bug in gcc as of 3.2.1 version]
	*/
	override void _throw(const SQL_Error& aexception) { 
		// converting SQL_exception to parser Exception
		// hiding passwords and addresses from accidental show [imagine user forgot @exception]
#ifdef PA_WITH_SJLJ_EXCEPTIONS
		throw
#else
		fexception=
#endif
			Exception(aexception.type(), 
					url_without_login(),
				aexception.comment()); 

#ifndef PA_WITH_SJLJ_EXCEPTIONS
		longjmp(mark, 1);
#endif
	}
	virtual void propagate_exception() {
#ifndef PA_WITH_SJLJ_EXCEPTIONS
		throw fexception;
#endif
	}

private:
	StringPtr url_without_login() const;
};

/// SQL connection. handy wrapper around low level SQL_Driver
class SQL_Connection: public PA_Object {
	StringPtr  furl;
	SQL_Driver& fdriver;
	SQL_Driver_services_impl fservices;
	void *fconnection;
	time_t time_used;
	bool marked_to_rollback;

public:

	SQL_Connection(StringPtr aurl, SQL_Driver& adriver):
		furl(aurl),
		fdriver(adriver),
		fconnection(0),
		time_used(0), 
		marked_to_rollback(false) {
	}
	
	StringPtr get_url() { return furl; }

	void set_pool(Pool *pool) {
		fservices.set_pool_and_url(pool, pool?furl:StringPtr(0));
	}
	bool expired(time_t older_dies) {
		return /*!freferences && */time_used<older_dies;
	}
	time_t get_time_used() { return time_used; }

	bool connected() { return fconnection!=0; }
	void connect(char *used_only_in_connect_url_cstr) { 
		SQL_CONNECTION_SERVICED_FUNC_GUARDED(
			fdriver.connect(used_only_in_connect_url_cstr, fservices, &fconnection)
		);
	}
	void disconnect() { 
		fdriver.disconnect(fconnection); fconnection=0; 
	}
	bool ping() { 
		SQL_CONNECTION_SERVICED_FUNC_GUARDED(
			return fdriver.ping(fservices, fconnection)
		);
		return 0; // never reached
	}
	uint quote(char *to, const char *from, unsigned int length) {
		SQL_CONNECTION_SERVICED_FUNC_GUARDED(
			return fdriver.quote(fservices, fconnection, to, from, length)
		);
		return 0; // never reached
	}

	void query(
		const char *statement, unsigned long offset, unsigned long limit,
		SQL_Driver_query_event_handlers& handlers, 
		StringPtr source) {
		try {
			SQL_CONNECTION_SERVICED_FUNC_GUARDED(
				fdriver.query(fservices, fconnection, 
					statement, offset, limit, 
					handlers)
			);	
		} catch(const Exception& e) { // query problem
			if(strcmp(e.type(), "sql.connect")==0) { // if it is _throw exception, 
				// give more specific source [were url]
				throw Exception("sql.execute",
					source, 
					"%s", e.comment());
			} else
				/*re*/throw;
		}
	}

	void mark_to_rollback() {
		marked_to_rollback=true;
	}

private: // closing process

	void commit() { 
		SQL_CONNECTION_SERVICED_FUNC_GUARDED(
			fdriver.commit(fservices, fconnection) 
		);
	}
	void rollback() { 
		SQL_CONNECTION_SERVICED_FUNC_GUARDED(
			fdriver.rollback(fservices, fconnection)
		);
	}

	/// return to cache
	void close() {
		if(marked_to_rollback) {
			rollback();
			marked_to_rollback=false;
		} else
			commit();

		SQL_driver_manager.close_connection(furl, SQL_ConnectionPtr(this));
	}

};

#endif

E-mail: