X-Git-Url: https://git.stg.codes/stg.git/blobdiff_plain/8c6fa3fbaccc22127280bf77a48fab5a3ee0716e..46b0747592074017ff0ea4b33d4a7194235886e5:/libs/ibpp/_ibpp.cpp diff --git a/libs/ibpp/_ibpp.cpp b/libs/ibpp/_ibpp.cpp new file mode 100644 index 00000000..3374b966 --- /dev/null +++ b/libs/ibpp/_ibpp.cpp @@ -0,0 +1,367 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// File : $Id: _ibpp.cpp,v 1.3 2009/03/19 20:00:27 faust Exp $ +// Subject : IBPP, Initialization of the library +// +/////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright 2000-2006 T.I.P. Group S.A. and the IBPP Team (www.ibpp.org) +// +// The contents of this file are subject to the IBPP License (the "License"); +// you may not use this file except in compliance with the License. You may +// obtain a copy of the License at http://www.ibpp.org or in the 'license.txt' +// file which must have been distributed along with this file. +// +// This software, distributed under the License, is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +// License for the specific language governing rights and limitations +// under the License. +// +/////////////////////////////////////////////////////////////////////////////// +// +// COMMENTS +// * Tabulations should be set every four characters when editing this file. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifdef _MSC_VER +#pragma warning(disable: 4786 4996) +#ifndef _DEBUG +#pragma warning(disable: 4702) +#endif +#endif + +#include "_ibpp.h" + +#ifdef HAS_HDRSTOP +#pragma hdrstop +#endif + +#include + +#ifdef IBPP_WINDOWS +// New (optional) Registry Keys introduced by Firebird Server 1.5 +#define REG_KEY_ROOT_INSTANCES "SOFTWARE\\Firebird Project\\Firebird Server\\Instances" +#define FB_DEFAULT_INSTANCE "DefaultInstance" +#endif + +namespace ibpp_internals +{ + const double consts::dscales[19] = { + 1, 1E1, 1E2, 1E3, 1E4, 1E5, 1E6, 1E7, 1E8, + 1E9, 1E10, 1E11, 1E12, 1E13, 1E14, 1E15, + 1E16, 1E17, 1E18 }; + + const int consts::Dec31_1899 = 693595; + +// Many compilers confuses those following min/max with macros min and max ! +#undef min +#undef max + +#ifdef __DMC__ // Needs to break-down the declaration else compiler crash (!) + const std::numeric_limits i16_limits; + const std::numeric_limits i32_limits; + const int16_t consts::min16 = i16_limits.min(); + const int16_t consts::max16 = i16_limits.max(); + const int32_t consts::min32 = i32_limits.min(); + const int32_t consts::max32 = i32_limits.max(); +#else + const int16_t consts::min16 = std::numeric_limits::min(); + const int16_t consts::max16 = std::numeric_limits::max(); + const int32_t consts::min32 = std::numeric_limits::min(); + const int32_t consts::max32 = std::numeric_limits::max(); +#endif + + GDS gds; // Global unique GDS instance + +#ifdef IBPP_WINDOWS + std::string AppPath; // Used by GDS::Call() below +#endif + +#ifdef _DEBUG + std::ostream& operator<< (std::ostream& a, flush_debug_stream_type) + { + if (std::stringstream* p = dynamic_cast(&a)) + { +#ifdef IBPP_WINDOWS + ::OutputDebugString(("IBPP: " + p->str() + "\n").c_str()); +#endif + p->str(""); + } + return a; + } +#endif // _DEBUG + +} + +using namespace ibpp_internals; + +GDS* GDS::Call() +{ + // Let's load the CLIENT library, if it is not already loaded. + // The load is guaranteed to be done only once per application. + + if (! mReady) + { +#ifdef IBPP_WINDOWS + + // Let's load the FBCLIENT.DLL or GDS32.DLL, we will never release it. + // Windows will do that for us when the executable will terminate. + + char fbdll[MAX_PATH]; + HKEY hkey_instances; + + // Try to load FBCLIENT.DLL from each of the additional optional paths + // that may have been specified through ClientLibSearchPaths(). + // We also want to actually update the environment PATH so that it references + // the specific path from where we attempt the load. This is useful because + // it directs the system to attempt finding dependencies (like the C/C++ + // runtime libraries) from the same location where FBCLIENT is found. + + mHandle = 0; + + std::string SysPath(getenv("PATH")); + std::string::size_type pos = 0; + while (pos < mSearchPaths.size()) + { + std::string::size_type newpos = mSearchPaths.find(';', pos); + + std::string path; + if (newpos == std::string::npos) path = mSearchPaths.substr(pos); + else path = mSearchPaths.substr(pos, newpos-pos); + + if (path.size() >= 1) + { + if (path[path.size()-1] != '\\') path += '\\'; + + AppPath.assign("PATH="); + AppPath.append(path).append(";").append(SysPath); + putenv(AppPath.c_str()); + + path.append("fbclient.dll"); + mHandle = LoadLibrary(path.c_str()); + if (mHandle != 0 || newpos == std::string::npos) break; + } + pos = newpos + 1; + } + + if (mHandle == 0) + { + // Try to load FBCLIENT.DLL from the current application location. This + // is a usefull step for applications using the embedded version of FB + // or a local copy (for whatever reasons) of the dll. + + if (! AppPath.empty()) + { + // Restores the original system path + AppPath.assign("PATH="); + AppPath.append(SysPath); + putenv(AppPath.c_str()); + } + + int len = GetModuleFileName(NULL, fbdll, sizeof(fbdll)); + if (len != 0) + { + // Get to the last '\' (this one precedes the filename part). + // There is always one after a success call to GetModuleFileName(). + char* p = fbdll + len; + do {--p;} while (*p != '\\'); + *p = '\0'; + lstrcat(fbdll, "\\fbembed.dll");// Local copy could be named fbembed.dll + mHandle = LoadLibrary(fbdll); + if (mHandle == 0) + { + *p = '\0'; + lstrcat(fbdll, "\\fbclient.dll"); // Or possibly renamed fbclient.dll + mHandle = LoadLibrary(fbdll); + } + } + } + + if (mHandle == 0) + { + // Try to locate FBCLIENT.DLL through the optional FB registry key. + + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_KEY_ROOT_INSTANCES, 0, + KEY_READ, &hkey_instances) == ERROR_SUCCESS) + { + DWORD keytype; + DWORD buflen = sizeof(fbdll); + if (RegQueryValueEx(hkey_instances, FB_DEFAULT_INSTANCE, 0, + &keytype, reinterpret_cast(fbdll), + &buflen) == ERROR_SUCCESS && keytype == REG_SZ) + { + lstrcat(fbdll, "bin\\fbclient.dll"); + mHandle = LoadLibrary(fbdll); + } + RegCloseKey(hkey_instances); + } + } + + if (mHandle == 0) + { + // Let's try from the PATH and System directories + mHandle = LoadLibrary("fbclient.dll"); + if (mHandle == 0) + { + // Not found. Last try : attemps loading gds32.dll from PATH and + // System directories + mHandle = LoadLibrary("gds32.dll"); + if (mHandle == 0) + throw LogicExceptionImpl("GDS::Call()", + _("Can't find or load FBCLIENT.DLL or GDS32.DLL")); + } + } +#endif + + mGDSVersion = 60; + + // Get the entry points that we need + +#ifdef IBPP_WINDOWS +#define IB_ENTRYPOINT(X) \ + if ((m_##X = (proto_##X*)GetProcAddress(mHandle, "isc_"#X)) == 0) \ + throw LogicExceptionImpl("GDS:gds()", _("Entry-point isc_"#X" not found")) +#endif +#ifdef IBPP_UNIX +/* TODO : perform a late-bind on unix --- not so important, well I think (OM) */ +#define IB_ENTRYPOINT(X) m_##X = (proto_##X*)isc_##X +#endif + + IB_ENTRYPOINT(create_database); + IB_ENTRYPOINT(attach_database); + IB_ENTRYPOINT(detach_database); + IB_ENTRYPOINT(drop_database); + IB_ENTRYPOINT(database_info); + IB_ENTRYPOINT(open_blob2); + IB_ENTRYPOINT(create_blob2); + IB_ENTRYPOINT(close_blob); + IB_ENTRYPOINT(cancel_blob); + IB_ENTRYPOINT(get_segment); + IB_ENTRYPOINT(put_segment); + IB_ENTRYPOINT(blob_info); + IB_ENTRYPOINT(array_lookup_bounds); + IB_ENTRYPOINT(array_get_slice); + IB_ENTRYPOINT(array_put_slice); + IB_ENTRYPOINT(vax_integer); + IB_ENTRYPOINT(sqlcode); + IB_ENTRYPOINT(sql_interprete); + IB_ENTRYPOINT(interprete); + IB_ENTRYPOINT(que_events); + IB_ENTRYPOINT(cancel_events); + IB_ENTRYPOINT(start_multiple); + IB_ENTRYPOINT(commit_transaction); + IB_ENTRYPOINT(commit_retaining); + IB_ENTRYPOINT(rollback_transaction); + IB_ENTRYPOINT(rollback_retaining); + IB_ENTRYPOINT(dsql_execute_immediate); + IB_ENTRYPOINT(dsql_allocate_statement); + IB_ENTRYPOINT(dsql_describe); + IB_ENTRYPOINT(dsql_describe_bind); + IB_ENTRYPOINT(dsql_prepare); + IB_ENTRYPOINT(dsql_execute); + IB_ENTRYPOINT(dsql_execute2); + IB_ENTRYPOINT(dsql_fetch); + IB_ENTRYPOINT(dsql_free_statement); + IB_ENTRYPOINT(dsql_set_cursor_name); + IB_ENTRYPOINT(dsql_sql_info); + + IB_ENTRYPOINT(service_attach); + IB_ENTRYPOINT(service_detach); + IB_ENTRYPOINT(service_start); + IB_ENTRYPOINT(service_query); + + mReady = true; + } + + return this; +} + +namespace IBPP +{ + + bool CheckVersion(uint32_t AppVersion) + { + //(void)gds.Call(); // Just call it to trigger the initialization + return (AppVersion & 0xFFFFFF00) == + (IBPP::Version & 0xFFFFFF00) ? true : false; + } + + int GDSVersion() + { + return gds.Call()->mGDSVersion; + } + +#ifdef IBPP_WINDOWS + void ClientLibSearchPaths(const std::string& paths) + { + gds.mSearchPaths.assign(paths); + } +#else + void ClientLibSearchPaths(const std::string&) + { + } +#endif + + // Factories for our Interface objects + + Service ServiceFactory(const std::string& ServerName, + const std::string& UserName, const std::string& UserPassword) + { + (void)gds.Call(); // Triggers the initialization, if needed + return new ServiceImpl(ServerName, UserName, UserPassword); + } + + Database DatabaseFactory(const std::string& ServerName, + const std::string& DatabaseName, const std::string& UserName, + const std::string& UserPassword, const std::string& RoleName, + const std::string& CharSet, const std::string& CreateParams) + { + (void)gds.Call(); // Triggers the initialization, if needed + return new DatabaseImpl(ServerName, DatabaseName, UserName, + UserPassword, RoleName, CharSet, CreateParams); + } + + Transaction TransactionFactory(Database db, TAM am, + TIL il, TLR lr, TFF flags) + { + (void)gds.Call(); // Triggers the initialization, if needed + return new TransactionImpl( dynamic_cast(db.intf()), + am, il, lr, flags); + } + + Statement StatementFactory(Database db, Transaction tr, + const std::string& sql) + { + (void)gds.Call(); // Triggers the initialization, if needed + return new StatementImpl( dynamic_cast(db.intf()), + dynamic_cast(tr.intf()), + sql); + } + + Blob BlobFactory(Database db, Transaction tr) + { + (void)gds.Call(); // Triggers the initialization, if needed + return new BlobImpl(dynamic_cast(db.intf()), + dynamic_cast(tr.intf())); + } + + Array ArrayFactory(Database db, Transaction tr) + { + (void)gds.Call(); // Triggers the initialization, if needed + return new ArrayImpl(dynamic_cast(db.intf()), + dynamic_cast(tr.intf())); + } + + Events EventsFactory(Database db) + { + (void)gds.Call(); // Triggers the initialization, if needed + return new EventsImpl(dynamic_cast(db.intf())); + } + +} + +// +// EOF +// +