]> git.stg.codes - stg.git/blob - libs/ibpp/_ibpp.cpp
More subscriptions, less notifiers.
[stg.git] / libs / ibpp / _ibpp.cpp
1 ///////////////////////////////////////////////////////////////////////////////\r
2 //\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
5 //\r
6 ///////////////////////////////////////////////////////////////////////////////\r
7 //\r
8 //      (C) Copyright 2000-2006 T.I.P. Group S.A. and the IBPP Team (www.ibpp.org)\r
9 //\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
14 //\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
19 //\r
20 ///////////////////////////////////////////////////////////////////////////////\r
21 //\r
22 //      COMMENTS\r
23 //      * Tabulations should be set every four characters when editing this file.\r
24 //\r
25 ///////////////////////////////////////////////////////////////////////////////\r
26 \r
27 #ifdef _MSC_VER\r
28 #pragma warning(disable: 4786 4996)\r
29 #ifndef _DEBUG\r
30 #pragma warning(disable: 4702)\r
31 #endif\r
32 #endif\r
33 \r
34 #include "_ibpp.h"\r
35 \r
36 #ifdef HAS_HDRSTOP\r
37 #pragma hdrstop\r
38 #endif\r
39 \r
40 #include <limits>\r
41 \r
42 #ifdef IBPP_WINDOWS\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
46 #endif\r
47 \r
48 namespace ibpp_internals\r
49 {\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
53                   1E16, 1E17, 1E18 };\r
54 \r
55         const int consts::Dec31_1899 = 693595;\r
56 \r
57 // Many compilers confuses those following min/max with macros min and max !\r
58 #undef min\r
59 #undef max\r
60 \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
68 #else\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
73 #endif\r
74 \r
75         GDS gds;        // Global unique GDS instance\r
76 \r
77 #ifdef IBPP_WINDOWS\r
78         std::string AppPath;    // Used by GDS::Call() below\r
79 #endif\r
80 \r
81 #ifdef _DEBUG\r
82         std::ostream& operator<< (std::ostream& a, flush_debug_stream_type)\r
83         {\r
84                 if (std::stringstream* p = dynamic_cast<std::stringstream*>(&a))\r
85                 {\r
86 #ifdef IBPP_WINDOWS\r
87                         ::OutputDebugString(("IBPP: " + p->str() + "\n").c_str());\r
88 #endif\r
89                         p->str("");\r
90                 }\r
91                 return a;\r
92         }\r
93 #endif  // _DEBUG\r
94 \r
95 }\r
96 \r
97 using namespace ibpp_internals;\r
98 \r
99 GDS* GDS::Call()\r
100 {\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
103 \r
104         if (! mReady)\r
105         {\r
106 #ifdef IBPP_WINDOWS\r
107 \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
110 \r
111                 char fbdll[MAX_PATH];\r
112                 HKEY hkey_instances;\r
113 \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
120 \r
121                 mHandle = 0;\r
122 \r
123                 std::string SysPath(getenv("PATH"));\r
124                 std::string::size_type pos = 0;\r
125                 while (pos < mSearchPaths.size())\r
126                 {\r
127                         std::string::size_type newpos = mSearchPaths.find(';', pos);\r
128 \r
129                         std::string path;\r
130                         if (newpos == std::string::npos) path = mSearchPaths.substr(pos);\r
131                         else path = mSearchPaths.substr(pos, newpos-pos);\r
132 \r
133                         if (path.size() >= 1)\r
134                         {\r
135                                 if (path[path.size()-1] != '\\') path += '\\';\r
136 \r
137                                 AppPath.assign("PATH=");\r
138                                 AppPath.append(path).append(";").append(SysPath);\r
139                                 putenv(AppPath.c_str());\r
140 \r
141                                 path.append("fbclient.dll");\r
142                                 mHandle = LoadLibrary(path.c_str());\r
143                                 if (mHandle != 0 || newpos == std::string::npos) break;\r
144                         }\r
145                         pos = newpos + 1;\r
146                 }\r
147 \r
148                 if (mHandle == 0)\r
149                 {\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
153 \r
154                         if (! AppPath.empty())\r
155                         {\r
156                                 // Restores the original system path\r
157                                 AppPath.assign("PATH=");\r
158                                 AppPath.append(SysPath);\r
159                                 putenv(AppPath.c_str());\r
160                         }\r
161 \r
162                         int len = GetModuleFileName(NULL, fbdll, sizeof(fbdll));\r
163                         if (len != 0)\r
164                         {\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
169                                 *p = '\0';\r
170                                 lstrcat(fbdll, "\\fbembed.dll");// Local copy could be named fbembed.dll\r
171                                 mHandle = LoadLibrary(fbdll);\r
172                                 if (mHandle == 0)\r
173                                 {\r
174                                         *p = '\0';\r
175                                         lstrcat(fbdll, "\\fbclient.dll");       // Or possibly renamed fbclient.dll\r
176                                         mHandle = LoadLibrary(fbdll);\r
177                                 }\r
178                         }\r
179                 }\r
180 \r
181                 if (mHandle == 0)\r
182                 {\r
183                         // Try to locate FBCLIENT.DLL through the optional FB registry key.\r
184 \r
185                         if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_KEY_ROOT_INSTANCES, 0,\r
186                                 KEY_READ, &hkey_instances) == ERROR_SUCCESS)\r
187                         {\r
188                                 DWORD keytype;\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
193                                 {\r
194                                         lstrcat(fbdll, "bin\\fbclient.dll");\r
195                                         mHandle = LoadLibrary(fbdll);\r
196                                 }\r
197                                 RegCloseKey(hkey_instances);\r
198                         }\r
199                 }\r
200 \r
201                 if (mHandle == 0)\r
202                 {\r
203                         // Let's try from the PATH and System directories\r
204                         mHandle = LoadLibrary("fbclient.dll");\r
205                         if (mHandle == 0)\r
206                         {\r
207                                 // Not found. Last try : attemps loading gds32.dll from PATH and\r
208                                 // System directories\r
209                                 mHandle = LoadLibrary("gds32.dll");\r
210                                 if (mHandle == 0)\r
211                                         throw LogicExceptionImpl("GDS::Call()",\r
212                                                 _("Can't find or load FBCLIENT.DLL or GDS32.DLL"));\r
213                         }\r
214                 }\r
215 #endif\r
216 \r
217                 mGDSVersion = 60;\r
218 \r
219                 // Get the entry points that we need\r
220 \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
225 #endif\r
226 #ifdef IBPP_UNIX\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
229 #endif\r
230 \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
268 \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
273 \r
274                 mReady = true;\r
275         }\r
276 \r
277         return this;\r
278 }\r
279 \r
280 namespace IBPP\r
281 {\r
282 \r
283         bool CheckVersion(uint32_t AppVersion)\r
284         {\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
288         }\r
289 \r
290         int GDSVersion()\r
291         {\r
292                 return gds.Call()->mGDSVersion;\r
293         }\r
294 \r
295 #ifdef IBPP_WINDOWS\r
296         void ClientLibSearchPaths(const std::string& paths)\r
297         {\r
298                 gds.mSearchPaths.assign(paths);\r
299         }\r
300 #else\r
301         void ClientLibSearchPaths(const std::string&)\r
302         {\r
303         }\r
304 #endif\r
305 \r
306         //      Factories for our Interface objects\r
307 \r
308         Service ServiceFactory(const std::string& ServerName,\r
309                                 const std::string& UserName, const std::string& UserPassword)\r
310         {\r
311                 (void)gds.Call();                       // Triggers the initialization, if needed\r
312                 return new ServiceImpl(ServerName, UserName, UserPassword);\r
313         }\r
314 \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
319         {\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
323         }\r
324 \r
325         Transaction TransactionFactory(Database db, TAM am,\r
326                                         TIL il, TLR lr, TFF flags)\r
327         {\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
331         }\r
332 \r
333         Statement StatementFactory(Database db, Transaction tr,\r
334                 const std::string& sql)\r
335         {\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
339                                                                         sql);\r
340         }\r
341 \r
342         Blob BlobFactory(Database db, Transaction tr)\r
343         {\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
347         }\r
348 \r
349         Array ArrayFactory(Database db, Transaction tr)\r
350         {\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
354         }\r
355 \r
356         Events EventsFactory(Database db)\r
357         {\r
358                 (void)gds.Call();                       // Triggers the initialization, if needed\r
359                 return new EventsImpl(dynamic_cast<DatabaseImpl*>(db.intf()));\r
360         }\r
361 \r
362 }\r
363 \r
364 //\r
365 //      EOF\r
366 //\r
367 \r