1 ///////////////////////////////////////////////////////////////////////////////
\r
3 // File : $Id: _ibpp.cpp,v 1.3 2009/03/19 20:00:27 faust Exp $
\r
4 // Subject : IBPP, Initialization of the library
\r
6 ///////////////////////////////////////////////////////////////////////////////
\r
8 // (C) Copyright 2000-2006 T.I.P. Group S.A. and the IBPP Team (www.ibpp.org)
\r
10 // The contents of this file are subject to the IBPP License (the "License");
\r
11 // you may not use this file except in compliance with the License. You may
\r
12 // obtain a copy of the License at http://www.ibpp.org or in the 'license.txt'
\r
13 // file which must have been distributed along with this file.
\r
15 // This software, distributed under the License, is distributed on an "AS IS"
\r
16 // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
\r
17 // License for the specific language governing rights and limitations
\r
18 // under the License.
\r
20 ///////////////////////////////////////////////////////////////////////////////
\r
23 // * Tabulations should be set every four characters when editing this file.
\r
25 ///////////////////////////////////////////////////////////////////////////////
\r
28 #pragma warning(disable: 4786 4996)
\r
30 #pragma warning(disable: 4702)
\r
43 // New (optional) Registry Keys introduced by Firebird Server 1.5
\r
44 #define REG_KEY_ROOT_INSTANCES "SOFTWARE\\Firebird Project\\Firebird Server\\Instances"
\r
45 #define FB_DEFAULT_INSTANCE "DefaultInstance"
\r
48 namespace ibpp_internals
\r
50 const double consts::dscales[19] = {
\r
51 1, 1E1, 1E2, 1E3, 1E4, 1E5, 1E6, 1E7, 1E8,
\r
52 1E9, 1E10, 1E11, 1E12, 1E13, 1E14, 1E15,
\r
55 const int consts::Dec31_1899 = 693595;
\r
57 // Many compilers confuses those following min/max with macros min and max !
\r
61 #ifdef __DMC__ // Needs to break-down the declaration else compiler crash (!)
\r
62 const std::numeric_limits<int16_t> i16_limits;
\r
63 const std::numeric_limits<int32_t> i32_limits;
\r
64 const int16_t consts::min16 = i16_limits.min();
\r
65 const int16_t consts::max16 = i16_limits.max();
\r
66 const int32_t consts::min32 = i32_limits.min();
\r
67 const int32_t consts::max32 = i32_limits.max();
\r
69 const int16_t consts::min16 = std::numeric_limits<int16_t>::min();
\r
70 const int16_t consts::max16 = std::numeric_limits<int16_t>::max();
\r
71 const int32_t consts::min32 = std::numeric_limits<int32_t>::min();
\r
72 const int32_t consts::max32 = std::numeric_limits<int32_t>::max();
\r
75 GDS gds; // Global unique GDS instance
\r
78 std::string AppPath; // Used by GDS::Call() below
\r
82 std::ostream& operator<< (std::ostream& a, flush_debug_stream_type)
\r
84 if (std::stringstream* p = dynamic_cast<std::stringstream*>(&a))
\r
87 ::OutputDebugString(("IBPP: " + p->str() + "\n").c_str());
\r
97 using namespace ibpp_internals;
\r
101 // Let's load the CLIENT library, if it is not already loaded.
\r
102 // The load is guaranteed to be done only once per application.
\r
106 #ifdef IBPP_WINDOWS
\r
108 // Let's load the FBCLIENT.DLL or GDS32.DLL, we will never release it.
\r
109 // Windows will do that for us when the executable will terminate.
\r
111 char fbdll[MAX_PATH];
\r
112 HKEY hkey_instances;
\r
114 // Try to load FBCLIENT.DLL from each of the additional optional paths
\r
115 // that may have been specified through ClientLibSearchPaths().
\r
116 // We also want to actually update the environment PATH so that it references
\r
117 // the specific path from where we attempt the load. This is useful because
\r
118 // it directs the system to attempt finding dependencies (like the C/C++
\r
119 // runtime libraries) from the same location where FBCLIENT is found.
\r
123 std::string SysPath(getenv("PATH"));
\r
124 std::string::size_type pos = 0;
\r
125 while (pos < mSearchPaths.size())
\r
127 std::string::size_type newpos = mSearchPaths.find(';', pos);
\r
130 if (newpos == std::string::npos) path = mSearchPaths.substr(pos);
\r
131 else path = mSearchPaths.substr(pos, newpos-pos);
\r
133 if (path.size() >= 1)
\r
135 if (path[path.size()-1] != '\\') path += '\\';
\r
137 AppPath.assign("PATH=");
\r
138 AppPath.append(path).append(";").append(SysPath);
\r
139 putenv(AppPath.c_str());
\r
141 path.append("fbclient.dll");
\r
142 mHandle = LoadLibrary(path.c_str());
\r
143 if (mHandle != 0 || newpos == std::string::npos) break;
\r
150 // Try to load FBCLIENT.DLL from the current application location. This
\r
151 // is a usefull step for applications using the embedded version of FB
\r
152 // or a local copy (for whatever reasons) of the dll.
\r
154 if (! AppPath.empty())
\r
156 // Restores the original system path
\r
157 AppPath.assign("PATH=");
\r
158 AppPath.append(SysPath);
\r
159 putenv(AppPath.c_str());
\r
162 int len = GetModuleFileName(NULL, fbdll, sizeof(fbdll));
\r
165 // Get to the last '\' (this one precedes the filename part).
\r
166 // There is always one after a success call to GetModuleFileName().
\r
167 char* p = fbdll + len;
\r
168 do {--p;} while (*p != '\\');
\r
170 lstrcat(fbdll, "\\fbembed.dll");// Local copy could be named fbembed.dll
\r
171 mHandle = LoadLibrary(fbdll);
\r
175 lstrcat(fbdll, "\\fbclient.dll"); // Or possibly renamed fbclient.dll
\r
176 mHandle = LoadLibrary(fbdll);
\r
183 // Try to locate FBCLIENT.DLL through the optional FB registry key.
\r
185 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_KEY_ROOT_INSTANCES, 0,
\r
186 KEY_READ, &hkey_instances) == ERROR_SUCCESS)
\r
189 DWORD buflen = sizeof(fbdll);
\r
190 if (RegQueryValueEx(hkey_instances, FB_DEFAULT_INSTANCE, 0,
\r
191 &keytype, reinterpret_cast<UCHAR*>(fbdll),
\r
192 &buflen) == ERROR_SUCCESS && keytype == REG_SZ)
\r
194 lstrcat(fbdll, "bin\\fbclient.dll");
\r
195 mHandle = LoadLibrary(fbdll);
\r
197 RegCloseKey(hkey_instances);
\r
203 // Let's try from the PATH and System directories
\r
204 mHandle = LoadLibrary("fbclient.dll");
\r
207 // Not found. Last try : attemps loading gds32.dll from PATH and
\r
208 // System directories
\r
209 mHandle = LoadLibrary("gds32.dll");
\r
211 throw LogicExceptionImpl("GDS::Call()",
\r
212 _("Can't find or load FBCLIENT.DLL or GDS32.DLL"));
\r
219 // Get the entry points that we need
\r
221 #ifdef IBPP_WINDOWS
\r
222 #define IB_ENTRYPOINT(X) \
\r
223 if ((m_##X = (proto_##X*)GetProcAddress(mHandle, "isc_"#X)) == 0) \
\r
224 throw LogicExceptionImpl("GDS:gds()", _("Entry-point isc_"#X" not found"))
\r
227 /* TODO : perform a late-bind on unix --- not so important, well I think (OM) */
\r
228 #define IB_ENTRYPOINT(X) m_##X = (proto_##X*)isc_##X
\r
231 IB_ENTRYPOINT(create_database);
\r
232 IB_ENTRYPOINT(attach_database);
\r
233 IB_ENTRYPOINT(detach_database);
\r
234 IB_ENTRYPOINT(drop_database);
\r
235 IB_ENTRYPOINT(database_info);
\r
236 IB_ENTRYPOINT(open_blob2);
\r
237 IB_ENTRYPOINT(create_blob2);
\r
238 IB_ENTRYPOINT(close_blob);
\r
239 IB_ENTRYPOINT(cancel_blob);
\r
240 IB_ENTRYPOINT(get_segment);
\r
241 IB_ENTRYPOINT(put_segment);
\r
242 IB_ENTRYPOINT(blob_info);
\r
243 IB_ENTRYPOINT(array_lookup_bounds);
\r
244 IB_ENTRYPOINT(array_get_slice);
\r
245 IB_ENTRYPOINT(array_put_slice);
\r
246 IB_ENTRYPOINT(vax_integer);
\r
247 IB_ENTRYPOINT(sqlcode);
\r
248 IB_ENTRYPOINT(sql_interprete);
\r
249 IB_ENTRYPOINT(interprete);
\r
250 IB_ENTRYPOINT(que_events);
\r
251 IB_ENTRYPOINT(cancel_events);
\r
252 IB_ENTRYPOINT(start_multiple);
\r
253 IB_ENTRYPOINT(commit_transaction);
\r
254 IB_ENTRYPOINT(commit_retaining);
\r
255 IB_ENTRYPOINT(rollback_transaction);
\r
256 IB_ENTRYPOINT(rollback_retaining);
\r
257 IB_ENTRYPOINT(dsql_execute_immediate);
\r
258 IB_ENTRYPOINT(dsql_allocate_statement);
\r
259 IB_ENTRYPOINT(dsql_describe);
\r
260 IB_ENTRYPOINT(dsql_describe_bind);
\r
261 IB_ENTRYPOINT(dsql_prepare);
\r
262 IB_ENTRYPOINT(dsql_execute);
\r
263 IB_ENTRYPOINT(dsql_execute2);
\r
264 IB_ENTRYPOINT(dsql_fetch);
\r
265 IB_ENTRYPOINT(dsql_free_statement);
\r
266 IB_ENTRYPOINT(dsql_set_cursor_name);
\r
267 IB_ENTRYPOINT(dsql_sql_info);
\r
269 IB_ENTRYPOINT(service_attach);
\r
270 IB_ENTRYPOINT(service_detach);
\r
271 IB_ENTRYPOINT(service_start);
\r
272 IB_ENTRYPOINT(service_query);
\r
283 bool CheckVersion(uint32_t AppVersion)
\r
285 //(void)gds.Call(); // Just call it to trigger the initialization
\r
286 return (AppVersion & 0xFFFFFF00) ==
\r
287 (IBPP::Version & 0xFFFFFF00) ? true : false;
\r
292 return gds.Call()->mGDSVersion;
\r
295 #ifdef IBPP_WINDOWS
\r
296 void ClientLibSearchPaths(const std::string& paths)
\r
298 gds.mSearchPaths.assign(paths);
\r
301 void ClientLibSearchPaths(const std::string&)
\r
306 // Factories for our Interface objects
\r
308 Service ServiceFactory(const std::string& ServerName,
\r
309 const std::string& UserName, const std::string& UserPassword)
\r
311 (void)gds.Call(); // Triggers the initialization, if needed
\r
312 return new ServiceImpl(ServerName, UserName, UserPassword);
\r
315 Database DatabaseFactory(const std::string& ServerName,
\r
316 const std::string& DatabaseName, const std::string& UserName,
\r
317 const std::string& UserPassword, const std::string& RoleName,
\r
318 const std::string& CharSet, const std::string& CreateParams)
\r
320 (void)gds.Call(); // Triggers the initialization, if needed
\r
321 return new DatabaseImpl(ServerName, DatabaseName, UserName,
\r
322 UserPassword, RoleName, CharSet, CreateParams);
\r
325 Transaction TransactionFactory(Database db, TAM am,
\r
326 TIL il, TLR lr, TFF flags)
\r
328 (void)gds.Call(); // Triggers the initialization, if needed
\r
329 return new TransactionImpl( dynamic_cast<DatabaseImpl*>(db.intf()),
\r
330 am, il, lr, flags);
\r
333 Statement StatementFactory(Database db, Transaction tr,
\r
334 const std::string& sql)
\r
336 (void)gds.Call(); // Triggers the initialization, if needed
\r
337 return new StatementImpl( dynamic_cast<DatabaseImpl*>(db.intf()),
\r
338 dynamic_cast<TransactionImpl*>(tr.intf()),
\r
342 Blob BlobFactory(Database db, Transaction tr)
\r
344 (void)gds.Call(); // Triggers the initialization, if needed
\r
345 return new BlobImpl(dynamic_cast<DatabaseImpl*>(db.intf()),
\r
346 dynamic_cast<TransactionImpl*>(tr.intf()));
\r
349 Array ArrayFactory(Database db, Transaction tr)
\r
351 (void)gds.Call(); // Triggers the initialization, if needed
\r
352 return new ArrayImpl(dynamic_cast<DatabaseImpl*>(db.intf()),
\r
353 dynamic_cast<TransactionImpl*>(tr.intf()));
\r
356 Events EventsFactory(Database db)
\r
358 (void)gds.Call(); // Triggers the initialization, if needed
\r
359 return new EventsImpl(dynamic_cast<DatabaseImpl*>(db.intf()));
\r