/** @file
Parser: sql fconnection decl.
Copyright (c) 2001-2026 Art. Lebedev Studio (https://www.artlebedev.com)
Authors: Konstantin Morshnev <moko@design.ru>, Alexandr Petrosian <paf@design.ru>
*/
#ifndef PA_SQL_CONNECTION_H
#define PA_SQL_CONNECTION_H
#define IDENT_PA_SQL_CONNECTION_H "$Id: pa_sql_connection.h,v 1.50 2026/04/25 13:38:46 moko Exp $"
#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) \
use(); \
actions
#else
#define SQL_CONNECTION_SERVICED_FUNC_GUARDED(actions) \
use(); \
if(!setjmp(fservices.mark)) { \
actions; \
} else \
fservices.propagate_exception();
#endif
/// SQL_Driver_services Pooled implementation
class SQL_Driver_services_impl: public SQL_Driver_services {
const String* furl;
Exception fexception;
const char* frequest_charset;
const char* fdocument_root;
public:
SQL_Driver_services_impl(const char* arequest_charset, const char* adocument_root): furl(0), frequest_charset(arequest_charset), fdocument_root(adocument_root) {}
void set_url(const String& aurl) { furl=&aurl;}
const String& url_without_login() const;
override void* malloc(size_t size) { return pa_malloc(size); }
override void* malloc_atomic(size_t size) { return pa_malloc_atomic(size); }
override void* realloc(void *ptr, size_t size) { return pa_realloc(ptr, size); }
override const char* request_charset() { return frequest_charset; }
override const char* request_document_root() { return fdocument_root; }
override void transcode(const char* src, size_t src_length,
const char*& dst, size_t& dst_length,
const char* charset_from_name,
const char* charset_to_name
);
/**
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() ? aexception.type() : "sql.connect", &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
}
};
/// SQL connection. handy wrapper around low level SQL_Driver
class SQL_Connection: public PA_Object {
const String& furl;
SQL_Driver& fdriver;
SQL_Driver_services_impl fservices;
void *fconnection;
time_t time_used;
public:
SQL_Connection(const String& aurl, SQL_Driver& adriver, const char* arequest_charset, const char* adocument_root):
furl(aurl),
fdriver(adriver),
fservices(arequest_charset, adocument_root),
fconnection(0),
time_used(0) {
}
SQL_Driver_services_impl& services() { return fservices; }
const String& get_url() { return furl; }
void set_url() {
fservices.set_url(furl);
}
void use() {
time_used=time(0); // they started to use at this time
}
bool expired(time_t older_dies) {
return 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(fconnection)
);
return false; // never reached, warning war
}
const char* quote(const char* str, unsigned int length) {
SQL_CONNECTION_SERVICED_FUNC_GUARDED(
return fdriver.quote(fconnection, str, length)
);
return NULL; // never reached, warning war
}
void query(
const char* statement,
size_t placeholders_count, SQL_Driver::Placeholder* placeholders,
unsigned long offset, unsigned long limit,
SQL_Driver_query_event_handlers& handlers,
const String& source) {
try {
SQL_CONNECTION_SERVICED_FUNC_GUARDED(
fdriver.query(fconnection, statement, placeholders_count, placeholders, offset, limit, handlers)
);
} catch(const Exception& e) { // query problem
if(strcmp(e.type(), "sql.connect")==0) { // if it is _throw exception,
// show query instead of connect string
throw Exception("sql.execute", &source, "%s", e.comment());
} else
rethrow;
}
}
void commit() {
SQL_CONNECTION_SERVICED_FUNC_GUARDED(
fdriver.commit(fconnection)
);
}
void rollback() {
SQL_CONNECTION_SERVICED_FUNC_GUARDED(
fdriver.rollback(fconnection)
);
}
/// return to cache
void close() {
SQL_driver_manager->close_connection(furl, this);
}
};
#endif
E-mail: