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