1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 // File : $Id: _ibpp.cpp 75 2006-05-12 08:40:41Z epocman $
4 // Subject : IBPP, Initialization of the library
5 //
6 ///////////////////////////////////////////////////////////////////////////////
7 //
8 // (C) Copyright 2000-2006 T.I.P. Group S.A. and the IBPP Team (www.ibpp.org)
9 //
10 // The contents of this file are subject to the IBPP License (the "License");
11 // you may not use this file except in compliance with the License. You may
12 // obtain a copy of the License at http://www.ibpp.org or in the 'license.txt'
13 // file which must have been distributed along with this file.
14 //
15 // This software, distributed under the License, is distributed on an "AS IS"
16 // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
17 // License for the specific language governing rights and limitations
18 // under the License.
19 //
20 ///////////////////////////////////////////////////////////////////////////////
21 //
22 // COMMENTS
23 // * Tabulations should be set every four characters when editing this file.
24 //
25 ///////////////////////////////////////////////////////////////////////////////
26
27 #ifdef _MSC_VER
28 #pragma warning(disable: 4786 4996)
29 #ifndef _DEBUG
30 #pragma warning(disable: 4702)
31 #endif
32 #endif
33
34 #include "_ibpp.h"
35
36 #ifdef HAS_HDRSTOP
37 #pragma hdrstop
38 #endif
39
40 #include <limits>
41
42 #ifdef IBPP_WINDOWS
43 // New (optional) Registry Keys introduced by Firebird Server 1.5
44 #define REG_KEY_ROOT_INSTANCES "SOFTWARE\\Firebird Project\\Firebird Server\\Instances"
45 #define FB_DEFAULT_INSTANCE "DefaultInstance"
46 #endif
47
48 namespace ibpp_internals
49 {
50 const double consts::dscales[19] = {
51 1, 1E1, 1E2, 1E3, 1E4, 1E5, 1E6, 1E7, 1E8,
52 1E9, 1E10, 1E11, 1E12, 1E13, 1E14, 1E15,
53 1E16, 1E17, 1E18 };
54
55 const int consts::Dec31_1899 = 693595;
56
57 // Many compilers confuses those following min/max with macros min and max !
58 #undef min
59 #undef max
60
61 #ifdef __DMC__ // Needs to break-down the declaration else compiler crash (!)
62 const std::numeric_limits<int16_t> i16_limits;
63 const std::numeric_limits<int32_t> i32_limits;
64 const int16_t consts::min16 = i16_limits.min();
65 const int16_t consts::max16 = i16_limits.max();
66 const int32_t consts::min32 = i32_limits.min();
67 const int32_t consts::max32 = i32_limits.max();
68 #else
69 const int16_t consts::min16 = std::numeric_limits<int16_t>::min();
70 const int16_t consts::max16 = std::numeric_limits<int16_t>::max();
71 const int32_t consts::min32 = std::numeric_limits<int32_t>::min();
72 const int32_t consts::max32 = std::numeric_limits<int32_t>::max();
73 #endif
74
75 GDS gds; // Global unique GDS instance
76
77 #ifdef IBPP_WINDOWS
78 std::string AppPath; // Used by GDS::Call() below
79 #endif
80
81 #ifdef _DEBUG
operator <<(std::ostream & a,flush_debug_stream_type)82 std::ostream& operator<< (std::ostream& a, flush_debug_stream_type)
83 {
84 if (std::stringstream* p = dynamic_cast<std::stringstream*>(&a))
85 {
86 #ifdef IBPP_WINDOWS
87 ::OutputDebugString(("IBPP: " + p->str() + "\n").c_str());
88 #endif
89 p->str("");
90 }
91 return a;
92 }
93 #endif // _DEBUG
94
95 }
96
97 using namespace ibpp_internals;
98
Call()99 GDS* GDS::Call()
100 {
101 // Let's load the CLIENT library, if it is not already loaded.
102 // The load is guaranteed to be done only once per application.
103
104 if (! mReady)
105 {
106 #ifdef IBPP_WINDOWS
107
108 // Let's load the FBCLIENT.DLL or GDS32.DLL, we will never release it.
109 // Windows will do that for us when the executable will terminate.
110
111 char fbdll[MAX_PATH];
112 HKEY hkey_instances;
113
114 // Try to load FBCLIENT.DLL from each of the additional optional paths
115 // that may have been specified through ClientLibSearchPaths().
116 // We also want to actually update the environment PATH so that it references
117 // the specific path from where we attempt the load. This is useful because
118 // it directs the system to attempt finding dependencies (like the C/C++
119 // runtime libraries) from the same location where FBCLIENT is found.
120
121 mHandle = 0;
122
123 std::string SysPath(getenv("PATH"));
124 std::string::size_type pos = 0;
125 while (pos < mSearchPaths.size())
126 {
127 std::string::size_type newpos = mSearchPaths.find(';', pos);
128
129 std::string path;
130 if (newpos == std::string::npos) path = mSearchPaths.substr(pos);
131 else path = mSearchPaths.substr(pos, newpos-pos);
132
133 if (path.size() >= 1)
134 {
135 if (path[path.size()-1] != '\\') path += '\\';
136
137 AppPath.assign("PATH=");
138 AppPath.append(path).append(";").append(SysPath);
139 putenv(AppPath.c_str());
140
141 path.append("fbclient.dll");
142 mHandle = LoadLibrary(path.c_str());
143 if (mHandle != 0 || newpos == std::string::npos) break;
144 }
145 pos = newpos + 1;
146 }
147
148 if (mHandle == 0)
149 {
150 // Try to load FBCLIENT.DLL from the current application location. This
151 // is a usefull step for applications using the embedded version of FB
152 // or a local copy (for whatever reasons) of the dll.
153
154 if (! AppPath.empty())
155 {
156 // Restores the original system path
157 AppPath.assign("PATH=");
158 AppPath.append(SysPath);
159 putenv(AppPath.c_str());
160 }
161
162 int len = GetModuleFileName(NULL, fbdll, sizeof(fbdll));
163 if (len != 0)
164 {
165 // Get to the last '\' (this one precedes the filename part).
166 // There is always one after a success call to GetModuleFileName().
167 char* p = fbdll + len;
168 do {--p;} while (*p != '\\');
169 *p = '\0';
170 lstrcat(fbdll, "\\fbembed.dll");// Local copy could be named fbembed.dll
171 mHandle = LoadLibrary(fbdll);
172 if (mHandle == 0)
173 {
174 *p = '\0';
175 lstrcat(fbdll, "\\fbclient.dll"); // Or possibly renamed fbclient.dll
176 mHandle = LoadLibrary(fbdll);
177 }
178 }
179 }
180
181 if (mHandle == 0)
182 {
183 // Try to locate FBCLIENT.DLL through the optional FB registry key.
184
185 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_KEY_ROOT_INSTANCES, 0,
186 KEY_READ, &hkey_instances) == ERROR_SUCCESS)
187 {
188 DWORD keytype;
189 DWORD buflen = sizeof(fbdll);
190 if (RegQueryValueEx(hkey_instances, FB_DEFAULT_INSTANCE, 0,
191 &keytype, reinterpret_cast<UCHAR*>(fbdll),
192 &buflen) == ERROR_SUCCESS && keytype == REG_SZ)
193 {
194 lstrcat(fbdll, "bin\\fbclient.dll");
195 mHandle = LoadLibrary(fbdll);
196 }
197 RegCloseKey(hkey_instances);
198 }
199 }
200
201 if (mHandle == 0)
202 {
203 // Let's try from the PATH and System directories
204 mHandle = LoadLibrary("fbclient.dll");
205 if (mHandle == 0)
206 {
207 // Not found. Last try : attemps loading gds32.dll from PATH and
208 // System directories
209 mHandle = LoadLibrary("gds32.dll");
210 if (mHandle == 0)
211 throw LogicExceptionImpl("GDS::Call()",
212 _("Can't find or load FBCLIENT.DLL or GDS32.DLL"));
213 }
214 }
215 #endif
216
217 mGDSVersion = 60;
218
219 // Get the entry points that we need
220
221 #ifdef IBPP_WINDOWS
222 #define IB_ENTRYPOINT(X) \
223 if ((m_##X = (proto_##X*)GetProcAddress(mHandle, "isc_"#X)) == 0) \
224 throw LogicExceptionImpl("GDS:gds()", _("Entry-point isc_"#X" not found"))
225 #endif
226 #ifdef IBPP_UNIX
227 /* TODO : perform a late-bind on unix --- not so important, well I think (OM) */
228 #define IB_ENTRYPOINT(X) m_##X = (proto_##X*)isc_##X
229 #endif
230
231 IB_ENTRYPOINT(create_database);
232 IB_ENTRYPOINT(attach_database);
233 IB_ENTRYPOINT(detach_database);
234 IB_ENTRYPOINT(drop_database);
235 IB_ENTRYPOINT(database_info);
236 IB_ENTRYPOINT(open_blob2);
237 IB_ENTRYPOINT(create_blob2);
238 IB_ENTRYPOINT(close_blob);
239 IB_ENTRYPOINT(cancel_blob);
240 IB_ENTRYPOINT(get_segment);
241 IB_ENTRYPOINT(put_segment);
242 IB_ENTRYPOINT(blob_info);
243 IB_ENTRYPOINT(array_lookup_bounds);
244 IB_ENTRYPOINT(array_get_slice);
245 IB_ENTRYPOINT(array_put_slice);
246 IB_ENTRYPOINT(vax_integer);
247 IB_ENTRYPOINT(sqlcode);
248 IB_ENTRYPOINT(sql_interprete);
249 IB_ENTRYPOINT(interprete);
250 IB_ENTRYPOINT(que_events);
251 IB_ENTRYPOINT(cancel_events);
252 IB_ENTRYPOINT(start_multiple);
253 IB_ENTRYPOINT(commit_transaction);
254 IB_ENTRYPOINT(commit_retaining);
255 IB_ENTRYPOINT(rollback_transaction);
256 IB_ENTRYPOINT(rollback_retaining);
257 IB_ENTRYPOINT(dsql_execute_immediate);
258 IB_ENTRYPOINT(dsql_allocate_statement);
259 IB_ENTRYPOINT(dsql_describe);
260 IB_ENTRYPOINT(dsql_describe_bind);
261 IB_ENTRYPOINT(dsql_prepare);
262 IB_ENTRYPOINT(dsql_execute);
263 IB_ENTRYPOINT(dsql_execute2);
264 IB_ENTRYPOINT(dsql_fetch);
265 IB_ENTRYPOINT(dsql_free_statement);
266 IB_ENTRYPOINT(dsql_set_cursor_name);
267 IB_ENTRYPOINT(dsql_sql_info);
268
269 IB_ENTRYPOINT(service_attach);
270 IB_ENTRYPOINT(service_detach);
271 IB_ENTRYPOINT(service_start);
272 IB_ENTRYPOINT(service_query);
273
274 mReady = true;
275 }
276
277 return this;
278 }
279
280 namespace IBPP
281 {
282
CheckVersion(uint32_t AppVersion)283 bool CheckVersion(uint32_t AppVersion)
284 {
285 //(void)gds.Call(); // Just call it to trigger the initialization
286 return (AppVersion & 0xFFFFFF00) ==
287 (IBPP::Version & 0xFFFFFF00) ? true : false;
288 }
289
GDSVersion()290 int GDSVersion()
291 {
292 return gds.Call()->mGDSVersion;
293 }
294
295 #ifdef IBPP_WINDOWS
ClientLibSearchPaths(const std::string & paths)296 void ClientLibSearchPaths(const std::string& paths)
297 {
298 gds.mSearchPaths.assign(paths);
299 }
300 #else
ClientLibSearchPaths(const std::string &)301 void ClientLibSearchPaths(const std::string&)
302 {
303 }
304 #endif
305
306 // Factories for our Interface objects
307
ServiceFactory(const std::string & ServerName,const std::string & UserName,const std::string & UserPassword)308 Service ServiceFactory(const std::string& ServerName,
309 const std::string& UserName, const std::string& UserPassword)
310 {
311 (void)gds.Call(); // Triggers the initialization, if needed
312 return new ServiceImpl(ServerName, UserName, UserPassword);
313 }
314
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)315 Database DatabaseFactory(const std::string& ServerName,
316 const std::string& DatabaseName, const std::string& UserName,
317 const std::string& UserPassword, const std::string& RoleName,
318 const std::string& CharSet, const std::string& CreateParams)
319 {
320 (void)gds.Call(); // Triggers the initialization, if needed
321 return new DatabaseImpl(ServerName, DatabaseName, UserName,
322 UserPassword, RoleName, CharSet, CreateParams);
323 }
324
TransactionFactory(Database db,TAM am,TIL il,TLR lr,TFF flags)325 Transaction TransactionFactory(Database db, TAM am,
326 TIL il, TLR lr, TFF flags)
327 {
328 (void)gds.Call(); // Triggers the initialization, if needed
329 return new TransactionImpl( dynamic_cast<DatabaseImpl*>(db.intf()),
330 am, il, lr, flags);
331 }
332
StatementFactory(Database db,Transaction tr,const std::string & sql)333 Statement StatementFactory(Database db, Transaction tr,
334 const std::string& sql)
335 {
336 (void)gds.Call(); // Triggers the initialization, if needed
337 return new StatementImpl( dynamic_cast<DatabaseImpl*>(db.intf()),
338 dynamic_cast<TransactionImpl*>(tr.intf()),
339 sql);
340 }
341
BlobFactory(Database db,Transaction tr)342 Blob BlobFactory(Database db, Transaction tr)
343 {
344 (void)gds.Call(); // Triggers the initialization, if needed
345 return new BlobImpl(dynamic_cast<DatabaseImpl*>(db.intf()),
346 dynamic_cast<TransactionImpl*>(tr.intf()));
347 }
348
ArrayFactory(Database db,Transaction tr)349 Array ArrayFactory(Database db, Transaction tr)
350 {
351 (void)gds.Call(); // Triggers the initialization, if needed
352 return new ArrayImpl(dynamic_cast<DatabaseImpl*>(db.intf()),
353 dynamic_cast<TransactionImpl*>(tr.intf()));
354 }
355
EventsFactory(Database db)356 Events EventsFactory(Database db)
357 {
358 (void)gds.Call(); // Triggers the initialization, if needed
359 return new EventsImpl(dynamic_cast<DatabaseImpl*>(db.intf()));
360 }
361
362 }
363
364 //
365 // EOF
366 //
367
368