Commit e96ae2d4 authored by msobczak's avatar msobczak

Added dynamically loaded backends.

parent 9aad1941
......@@ -19,7 +19,7 @@ OBJECTSSO = blob-s.o factory-s.o row-id-s.o session-s.o \
vector-into-type-s.o vector-use-type-s.o
libsoci-empty.a : ${OBJECTS}
libsoci_empty.a : ${OBJECTS}
ar rv $@ $?
rm *.o
......@@ -53,7 +53,7 @@ vector-use-type.o : vector-use-type.cpp
shared : ${OBJECTSSO}
${COMPILER} -shared -o libsoci-empty.so ${OBJECTSSO}
${COMPILER} -shared -o libsoci_empty.so ${OBJECTSSO}
rm *.o
blob-s.o : blob.cpp
......@@ -85,4 +85,4 @@ vector-use-type-s.o : vector-use-type.cpp
clean :
rm -f libsoci-empty.a libsoci-empty.so
rm -f libsoci_empty.a libsoci_empty.so
......@@ -24,3 +24,14 @@ empty_session_backend * empty_backend_factory::make_session(
}
empty_backend_factory const soci::empty;
extern "C"
{
// for dynamic backend loading
SOCI_EMPTY_DECL backend_factory const * factory_empty()
{
return &soci::empty;
}
} // extern "C"
......@@ -178,7 +178,15 @@ struct SOCI_EMPTY_DECL empty_backend_factory : backend_factory
std::string const &connectString) const;
};
SOCI_EMPTY_DECL extern empty_backend_factory const empty;
extern SOCI_EMPTY_DECL empty_backend_factory const empty;
extern "C"
{
// for dynamic backend loading
SOCI_EMPTY_DECL backend_factory const * factory_empty();
} // extern "C"
} // namespace soci
......
......@@ -2,7 +2,7 @@ COMPILER = g++
CXXFLAGS = -Wall -pedantic -Wno-long-long
INCLUDEDIRS = -I.. -I../../../core
LIBDIRS = -L.. -L../../../core
LIBS = -lsoci-core -lsoci-empty
LIBS = -lsoci_core -lsoci_empty
test-empty : test-empty.cpp
......
......@@ -18,7 +18,7 @@ OBJECTSSO = blob-s.o factory-s.o row-id-s.o session-s.o \
standard-into-type-s.o standard-use-type-s.o statement-s.o \
vector-into-type-s.o vector-use-type-s.o error-s.o common-s.o
libsoci-firebird.a : ${OBJECTS}
libsoci_firebird.a : ${OBJECTS}
ar rv $@ $?
rm *.o
......@@ -59,7 +59,7 @@ vector-use-type.o : vector-use-type.cpp
${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS}
shared : ${OBJECTSSO}
${COMPILER} -shared -o libsoci-firebird.so ${OBJECTSSO}
${COMPILER} -shared -o libsoci_firebird.so ${OBJECTSSO}
rm *.o
blob-s.o : blob.cpp
......@@ -96,4 +96,4 @@ vector-use-type-s.o : vector-use-type.cpp
${COMPILER} -c -o $@ $? ${CXXFLAGSSO} ${INCLUDEDIRS}
clean :
rm -f *.o libsoci-firebird.a libsoci-firebird.so
rm -f *.o libsoci_firebird.a libsoci_firebird.so
......@@ -17,3 +17,14 @@ firebird_session_backend * firebird_backend_factory::make_session(
}
firebird_backend_factory const soci::firebird;
extern "C"
{
// for dynamic backend loading
SOCI_EMPTY_DECL backend_factory const * factory_firebird()
{
return &soci::firebird;
}
} // extern "C"
......@@ -316,7 +316,15 @@ struct firebird_backend_factory : backend_factory
std::string const &connectString) const;
};
SOCI_FIREBIRD_DECL extern firebird_backend_factory const firebird;
extern SOCI_FIREBIRD_DECL firebird_backend_factory const firebird;
extern "C"
{
// for dynamic backend loading
SOCI_FIREBIRD_DECL backend_factory const * factory_firebird();
} // extern "C"
} // namespace soci
......
......@@ -11,7 +11,7 @@ COMPILER = g++
CXXFLAGS = -Wall -pedantic -Wno-long-long
INCLUDEDIRS = -I.. -I../../../core ${FIREBIRDINCLUDEDIR}
LIBDIRS = -L.. -L../../../core ${FIREBIRDLIBDIR}
LIBS = -lsoci-core -lsoci-firebird ${FIREBIRDLIBS}
LIBS = -lsoci_core -lsoci_firebird ${FIREBIRDLIBS}
test-firebird : test-firebird.cpp
......
......@@ -23,7 +23,7 @@ OBJECTSSO = blob-s.o factory-s.o row-id-s.o session-s.o \
vector-into-type-s.o vector-use-type-s.o common-s.o
libsoci-mysql.a : ${OBJECTS}
libsoci_mysql.a : ${OBJECTS}
ar rv $@ $?
rm *.o
......@@ -59,7 +59,7 @@ vector-use-type.o : vector-use-type.cpp
${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS}
shared : ${OBJECTSSO}
${COMPILER} -shared -o libsoci-mysql.so ${OBJECTSSO}
${COMPILER} -shared -o libsoci_mysql.so ${OBJECTSSO}
rm *.o
blob-s.o : blob.cpp
......@@ -94,4 +94,4 @@ vector-use-type-s.o : vector-use-type.cpp
clean :
rm -f libsoci-mysql.a libsoci-mysql.so
rm -f libsoci_mysql.a libsoci_mysql.so
......@@ -26,3 +26,14 @@ mysql_session_backend * mysql_backend_factory::make_session(
}
mysql_backend_factory const soci::mysql;
extern "C"
{
// for dynamic backend loading
SOCI_MYSQL_DECL backend_factory const * factory_mysql()
{
return &soci::mysql;
}
} // extern "C"
......@@ -247,7 +247,15 @@ struct mysql_backend_factory : backend_factory
std::string const &connectString) const;
};
SOCI_MYSQL_DECL extern mysql_backend_factory const mysql;
extern SOCI_MYSQL_DECL mysql_backend_factory const mysql;
extern "C"
{
// for dynamic backend loading
SOCI_MYSQL_DECL backend_factory const * factory_mysql();
} // extern "C"
} // namespace SOCI
......
......@@ -11,7 +11,7 @@ COMPILER = g++
CXXFLAGS = -Wall -pedantic -Wno-long-long
INCLUDEDIRS = -I.. -I../../../core ${MYSQLINCLUDEDIR}
LIBDIRS = -L.. -L../../../core ${MYSQLLIBDIR}
LIBS = -lsoci-core -lsoci-mysql ${MYSQLLIBS}
LIBS = -lsoci_core -lsoci_mysql ${MYSQLLIBS}
test-mysql : test-mysql.cpp
......
......@@ -19,7 +19,7 @@ OBJECTSSO = blob-s.o factory-s.o row-id-s.o session-s.o \
vector-into-type-s.o vector-use-type-s.o
libsoci-odbc.a : ${OBJECTS}
libsoci_odbc.a : ${OBJECTS}
ar rv $@ $?
ranlib $@
rm *.o
......@@ -54,7 +54,7 @@ vector-use-type.o : vector-use-type.cpp
shared : ${OBJECTSSO}
${COMPILER} -shared -o libsoci-odbc.so ${OBJECTSSO}
${COMPILER} -shared -o libsoci_odbc.so ${OBJECTSSO}
rm *.o
blob-s.o : blob.cpp
......@@ -86,4 +86,4 @@ vector-use-type-s.o : vector-use-type.cpp
clean :
rm -f libsoci-odbc.a libsoci-odbc.so
rm -f libsoci_odbc.a libsoci_odbc.so
......@@ -20,3 +20,14 @@ odbc_session_backend * odbc_backend_factory::make_session(
}
odbc_backend_factory const soci::odbc;
extern "C"
{
// for dynamic backend loading
SOCI_ODBC_DECL backend_factory const * factory_odbc()
{
return &soci::odbc;
}
} // extern "C"
......@@ -242,14 +242,6 @@ struct odbc_session_backend : details::session_backend
SQLHDBC hdbc_;
};
struct odbc_backend_factory : backend_factory
{
virtual odbc_session_backend * make_session(
std::string const &connectString) const;
};
SOCI_ODBC_DECL extern odbc_backend_factory const odbc;
class SOCI_ODBC_DECL odbc_soci_error : public soci_error
{
SQLCHAR message_[SQL_MAX_MESSAGE_LENGTH + 1];
......@@ -300,7 +292,22 @@ inline bool is_odbc_error(SQLRETURN rc)
}
}
} // namespace SOCI
struct odbc_backend_factory : backend_factory
{
virtual odbc_session_backend * make_session(
std::string const &connectString) const;
};
extern SOCI_ODBC_DECL odbc_backend_factory const odbc;
extern "C"
{
// for dynamic backend loading
SOCI_ODBC_DECL backend_factory const * factory_odbc();
} // extern "C"
} // namespace SOCI
#endif // SOCI_EMPTY_H_INCLUDED
......@@ -11,7 +11,7 @@ COMPILER = g++
CXXFLAGS = -Wall -pedantic -Wno-long-long
INCLUDEDIRS = -I.. -I../../../core ${ODBCINCLUDEDIR}
LIBDIRS = -L.. -L../../../core ${ODBCLIBDIR}
LIBS = -lsoci-core -lsoci-odbc ${ODBCLIBS}
LIBS = -lsoci_core -lsoci_odbc ${ODBCLIBS}
test-odbc-mssql: test-odbc-mssql.cpp
......
......@@ -18,7 +18,7 @@ OBJECTSSO = blob-s.o factory-s.o row-id-s.o session-s.o \
standard-into-type-s.o standard-use-type-s.o statement-s.o \
vector-into-type-s.o vector-use-type-s.o error-s.o
libsoci-oracle.a : ${OBJECTS}
libsoci_oracle.a : ${OBJECTS}
ar rv $@ $?
rm *.o
......@@ -57,7 +57,7 @@ vector-use-type.o : vector-use-type.cpp
shared : ${OBJECTSSO}
${COMPILER} -shared -o libsoci-oracle.so ${OBJECTSSO}
${COMPILER} -shared -o libsoci_oracle.so ${OBJECTSSO}
rm *.o
blob-s.o : blob.cpp
......@@ -92,4 +92,4 @@ vector-use-type-s.o : vector-use-type.cpp
clean :
rm -f *.o libsoci-oracle.a libsoci-oracle.so
rm -f *.o libsoci_oracle.a libsoci_oracle.so
......@@ -71,3 +71,14 @@ oracle_session_backend * oracle_backend_factory::make_session(
}
oracle_backend_factory const soci::oracle;
extern "C"
{
// for dynamic backend loading
SOCI_ORACLE_DECL backend_factory const * factory_oracle()
{
return &soci::oracle;
}
} // extern "C"
......@@ -269,8 +269,15 @@ struct oracle_backend_factory : backend_factory
std::string const &connectString) const;
};
SOCI_ORACLE_DECL extern oracle_backend_factory const oracle;
extern SOCI_ORACLE_DECL oracle_backend_factory const oracle;
extern "C"
{
// for dynamic backend loading
SOCI_ORACLE_DECL backend_factory const * factory_oracle();
} // extern "C"
} // namespace soci
......
......@@ -15,7 +15,7 @@ COMPILER = g++
CXXFLAGS = -Wall -pedantic -Wno-long-long
INCLUDEDIRS = -I.. -I../../../core -I../../../core/test ${ORACLEINCLUDEDIR} ${BOOSTINCLUDEDIR}
LIBDIRS = -L.. -L../../../core ${ORACLELIBDIR}
LIBS = -lsoci-core -lsoci-oracle ${ORACLELIBS}
LIBS = -lsoci_core -lsoci_oracle ${ORACLELIBS}
test-oracle : test-oracle.cpp
......
......@@ -20,7 +20,7 @@ OBJECTSSO = blob-s.o factory-s.o row-id-s.o session-s.o \
vector-into-type-s.o vector-use-type-s.o common-s.o
libsoci-postgresql.a : ${OBJECTS}
libsoci_postgresql.a : ${OBJECTS}
ar rv $@ $?
rm *.o
......@@ -57,7 +57,7 @@ vector-use-type.o : vector-use-type.cpp
shared : ${OBJECTSSO}
${COMPILER} -shared -o libsoci-postgresql.so ${OBJECTSSO}
${COMPILER} -shared -o libsoci_postgresql.so ${OBJECTSSO}
rm *.o
blob-s.o : blob.cpp
......@@ -92,4 +92,4 @@ vector-use-type-s.o : vector-use-type.cpp
clean :
rm -f libsoci-postgresql.a libsoci-postgresql.so
rm -f libsoci_postgresql.a libsoci_postgresql.so
......@@ -34,3 +34,14 @@ postgresql_session_backend * postgresql_backend_factory::make_session(
}
postgresql_backend_factory const soci::postgresql;
extern "C"
{
// for dynamic backend loading
SOCI_POSTGRESQL_DECL backend_factory const * factory_postgresql()
{
return &soci::postgresql;
}
} // extern "C"
......@@ -243,7 +243,15 @@ struct postgresql_backend_factory : backend_factory
std::string const &connectString) const;
};
SOCI_POSTGRESQL_DECL extern postgresql_backend_factory const postgresql;
extern SOCI_POSTGRESQL_DECL postgresql_backend_factory const postgresql;
extern "C"
{
// for dynamic backend loading
SOCI_POSTGRESQL_DECL backend_factory const * factory_postgresql();
} // extern "C"
} // namespace soci
......
......@@ -15,7 +15,7 @@ COMPILER = g++
CXXFLAGS = -Wall -pedantic -Wno-long-long
INCLUDEDIRS = -I.. -I../../../core/test -I../../../core ${PGSQLINCLUDEDIR} ${BOOSTINCLUDEDIR}
LIBDIRS = -L.. -L../../../core ${PGSQLLIBDIR}
LIBS = -lsoci-core -lsoci-postgresql ${PGSQLLIBS}
LIBS = -lsoci_core -lsoci_postgresql ${PGSQLLIBS}
test-postgresql : test-postgresql.cpp
......
......@@ -297,6 +297,41 @@ void test5()
std::cout << "test 5 passed" << std::endl;
}
// dynamic backend test
void test6()
{
try
{
session sql("nosuchbackend://" + connectString);
assert(false);
}
catch (soci_error const & e)
{
assert(e.what() == std::string("Failed to open: libsoci_nosuchbackend.so"));
}
{
dynamic_backends::register_backend("pgsql", backEnd);
std::vector<std::string> backends = dynamic_backends::list_all();
assert(backends.size() == 1);
assert(backends[0] == "pgsql");
{
session sql("pgsql://" + connectString);
}
dynamic_backends::unload("pgsql");
backends = dynamic_backends::list_all();
assert(backends.empty());
}
{
session sql("postgresql://" + connectString);
}
}
// DDL Creation objects for common tests
struct table_creator_one : public table_creator_base
{
......@@ -402,6 +437,7 @@ int main(int argc, char** argv)
test3();
test4();
test5();
// test6();
std::cout << "\nOK, all tests passed.\n\n";
return EXIT_SUCCESS;
......
......@@ -20,7 +20,7 @@ OBJECTSSO = blob-s.o factory-s.o row-id-s.o session-s.o \
vector-into-type-s.o vector-use-type-s.o common-s.o
libsoci-sqlite3.a : ${OBJECTS}
libsoci_sqlite3.a : ${OBJECTS}
ar rv $@ $?
rm *.o
......@@ -57,7 +57,7 @@ vector-use-type.o : vector-use-type.cpp
shared : ${OBJECTSSO}
${COMPILER} -shared -o libsoci-sqlite3.so ${OBJECTSSO}
${COMPILER} -shared -o libsoci_sqlite3.so ${OBJECTSSO}
rm *.o
blob-s.o : blob.cpp
......@@ -92,4 +92,4 @@ vector-use-type-s.o : vector-use-type.cpp
clean :
rm -f libsoci-sqlite3.a libsoci-sqlite3.so
rm -f libsoci_sqlite3.a libsoci_sqlite3.so
......@@ -23,4 +23,15 @@ sqlite3_session_backend * sqlite3_backend_factory::make_session(
return new sqlite3_session_backend(connectString);
}
SOCI_SQLITE3_DECL sqlite3_backend_factory const soci::sqlite3;
sqlite3_backend_factory const soci::sqlite3;
extern "C"
{
// for dynamic backend loading
SOCI_SQLITE3_DECL backend_factory const * factory_sqlite3()
{
return &soci::sqlite3;
}
} // extern "C"
......@@ -247,7 +247,15 @@ struct sqlite3_backend_factory : backend_factory
std::string const &connectString) const;
};
SOCI_SQLITE3_DECL extern sqlite3_backend_factory const sqlite3;
extern SOCI_SQLITE3_DECL sqlite3_backend_factory const sqlite3;
extern "C"
{
// for dynamic backend loading
SOCI_SQLITE3_DECL backend_factory const * factory_sqlite3();
} // extern "C"
} // namespace SOCI
......
......@@ -12,7 +12,7 @@ COMPILER = g++
CXXFLAGS = -Wall -pedantic -Wno-long-long
INCLUDEDIRS = -I.. -I../../../core -I../../../core/test ${SQLITE3INCLUDEDIR} ${BOOSTINCLUDEDIR}
LIBDIRS = -L.. -L../../../core ${SQLITE3LIBDIR}
LIBS = -lsoci-core -lsoci-sqlite3 ${SQLITE3LIBS}
LIBS = -lsoci_core -lsoci_sqlite3 ${SQLITE3LIBS}
test-sqlite3 : test-sqlite3.cpp
......
# $Id: Makefile.am,v 1.9 2007/10/06 19:31:51 msobczak Exp $
# $Id: Makefile.am,v 1.10 2008/03/27 14:16:36 msobczak Exp $
#
# Copyright (C) 2006, Mateusz Loskot
#
......@@ -14,6 +14,7 @@ lib@SOCI_CORE_LIBRARY_NAME@_la_LDFLAGS = \
-release @LIBTOOL_RELEASE@
lib@SOCI_CORE_LIBRARY_NAME@_la_SOURCES = \
backend-loader.cpp \
blob.cpp \
error.cpp \
into-type.cpp \
......@@ -33,9 +34,11 @@ lib@SOCI_CORE_LIBRARY_NAME@_la_SOURCES = \
socidir = $(includedir)/soci
soci_HEADERS = \
backend-loader.h \
blob.h \
blob-exchange.h \
boost-optional.h \
boost-tuple.h \
error.h \
exchange-traits.h \
into.h \
......
......@@ -4,16 +4,16 @@ INCLUDEDIRS = -I/usr/include/boost_1_34_1
OBJS = session.o statement.o row.o values.o \
into-type.o use-type.o \
blob.o rowid.o procedure.o ref-counted-prepare-info.o ref-counted-statement.o \
once-temp-type.o prepare-temp-type.o error.o transaction.o
once-temp-type.o prepare-temp-type.o error.o transaction.o backend-loader.o
libsoci-core.a : ${OBJS}
libsoci_core.a : ${OBJS}
ar rv $@ $?
rm *.o
shared : ${OBJS}
${COMPILER} -fPIC -c $? ${CXXFLAGS} ${INCLUDEDIRS}
${COMPILER} -shared -o libsoci-core.so ${OBJS}
${COMPILER} -shared -o libsoci_core.so ${OBJS}
rm *.o
session.o : session.cpp
......@@ -61,5 +61,9 @@ prepare-temp-type.o : prepare-temp-type.cpp
transaction.o : transaction.cpp
${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS}
backend-loader.o : backend-loader.cpp
${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS}
clean :
rm -f libsoci-core.a libsoci-core.so
rm -f libsoci_core.a libsoci_core.so
#define SOCI_SOURCE
#include "backend-loader.h"
#include "error.h"
#include <map>
using namespace std;
using namespace soci;
using namespace soci::dynamic_backends;
#ifndef SOCI_LIBRARY_SUFFIX
#define SOCI_LIBRARY_SUFFIX ""
#endif
#ifdef _WIN32
#include <windows.h>
typedef CRITICAL_SECTION soci_mutex_t;
typedef HMODULE soci_handler_t;
#define LOCK(x) EnterCriticalSection(x)
#define UNLOCK(x) LeaveCriticalSection(x)
#define MUTEX_INIT(x) InitializeCriticalSection(x)
#define MUTEX_DEST(x) DeleteCriticalSection(x)
#define DLOPEN(x) LoadLibrary(x)
#define DLCLOSE(x) FreeLibrary(x)
#define DLSYM(x,y) GetProcAddress(x, y)
#define LIBNAME(x) ("libsoci_" + x + SOCI_LIBRARY_SUFFIX + ".dll")
#else
#include <pthread.h>
#include <dlfcn.h>
typedef pthread_mutex_t soci_mutex_t;
typedef void * soci_handler_t;
#define LOCK(x) pthread_mutex_lock(x)
#define UNLOCK(x) pthread_mutex_unlock(x)
#define MUTEX_INIT(x) pthread_mutex_init(x, NULL)
#define MUTEX_DEST(x) pthread_mutex_destroy(x)
#define DLOPEN(x) dlopen(x, RTLD_LAZY)
#define DLCLOSE(x) dlclose(x)
#define DLSYM(x,y) dlsym(x,y)
#define LIBNAME(x) ("libsoci_" + x + SOCI_LIBRARY_SUFFIX + ".so")
#endif // _WIN32
namespace // unnamed
{
soci_mutex_t mutex_;
// used to automatically initialize the mutex above
struct mutex_mgr
{
mutex_mgr()
{
MUTEX_INIT(&mutex_);
}
~mutex_mgr()
{
MUTEX_DEST(&mutex_);
}
} mutex_mgr_;
class scoped_lock
{
public:
scoped_lock(soci_mutex_t * m) : mptr(m) { LOCK(m); };
~scoped_lock() { UNLOCK(mptr); };
private:
soci_mutex_t * mptr;
};
struct info
{
soci_handler_t handler_;
backend_factory const * factory_;
info() : handler_(NULL), factory_(NULL) {}
~info()
{
if (handler_ != NULL)
{
DLCLOSE(handler_);
}
}
};
typedef map<string, info> factory_map;
factory_map factories_;
// non-synchronized helper for the other functions
void do_unload(string const & name)
{
factory_map::iterator i = factories_.find(name);
if (i != factories_.end())
{
soci_handler_t h = i->second.handler_;
if (h != NULL)
{
DLCLOSE(h);
}
factories_.erase(i);
}
}
// non-synchronized helper
void do_register_backend(
string const & name, string const & shared_object)
{
std::string so = (shared_object.empty() ? LIBNAME(name) : shared_object);
soci_handler_t h = DLOPEN(so.c_str());
if(h == NULL)
{
throw soci_error("Failed to open: " + so);
}
std::string symbol = "factory_" + name;
typedef backend_factory const * bfc_ptr;
typedef bfc_ptr (*get_t)(void);
get_t entry;
entry = reinterpret_cast<get_t>(reinterpret_cast<long>(DLSYM(h, symbol.c_str())));
if (entry == NULL)
{
DLCLOSE(h);
throw soci_error("Failed to resolve dynamic symbol: " + symbol);
}
// unload the existing handler if it's already loaded
do_unload(name);
backend_factory const * f = entry();
info new_entry;
new_entry.factory_ = f;
new_entry.handler_ = h;
factories_[name] = new_entry;
}