]> git.stg.codes - stg.git/blob - stglibs/ibpp.lib/service.cpp
Allow to user USER_IMPL with USERS_IMPL methods (like SearchNext, Find*
[stg.git] / stglibs / ibpp.lib / service.cpp
1 ///////////////////////////////////////////////////////////////////////////////\r
2 //\r
3 //      File    : $Id: service.cpp,v 1.1 2007/05/05 17:00:43 faust Exp $\r
4 //      Subject : IBPP, Service class implementation\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 using namespace ibpp_internals;\r
41 \r
42 #ifdef IBPP_UNIX\r
43 #include <unistd.h>\r
44 #define Sleep(x) usleep(x)\r
45 #endif\r
46 \r
47 //      (((((((( OBJECT INTERFACE IMPLEMENTATION ))))))))\r
48 \r
49 void ServiceImpl::Connect()\r
50 {\r
51         if (mHandle     != 0) return;   // Already connected\r
52         \r
53         if (gds.Call()->mGDSVersion < 60)\r
54                 throw LogicExceptionImpl("Service", _("Requires the version 6 of GDS32.DLL"));\r
55         if (mUserName.empty())\r
56                 throw LogicExceptionImpl("Service::Connect", _("Unspecified user name."));\r
57         if (mUserPassword.empty())\r
58                 throw LogicExceptionImpl("Service::Connect", _("Unspecified user password."));\r
59 \r
60         // Attach to the Service Manager\r
61         IBS status;\r
62         SPB spb;\r
63         std::string connect;\r
64 \r
65         // Build a SPB based on the     properties\r
66         spb.Insert(isc_spb_version);\r
67         spb.Insert(isc_spb_current_version);\r
68         spb.InsertString(isc_spb_user_name, 1, mUserName.c_str());\r
69         spb.InsertString(isc_spb_password, 1, mUserPassword.c_str());\r
70 \r
71         if (! mServerName.empty())\r
72         {\r
73                 connect = mServerName;\r
74                 connect += ":";\r
75         }\r
76 \r
77         connect += "service_mgr";\r
78 \r
79         (*gds.Call()->m_service_attach)(status.Self(), (short)connect.size(), (char*)connect.c_str(),\r
80                 &mHandle, spb.Size(), spb.Self());\r
81         if (status.Errors())\r
82         {\r
83                 mHandle = 0;            // Should be, but better be     sure...\r
84                 throw SQLExceptionImpl(status, "Service::Connect", _("isc_service_attach failed"));\r
85         }\r
86 }\r
87 \r
88 void ServiceImpl::Disconnect()\r
89 {\r
90         if (mHandle     == 0) return; // Already disconnected\r
91         \r
92         if (gds.Call()->mGDSVersion < 60)\r
93                 throw LogicExceptionImpl("Service", _("Requires the version 6 of GDS32.DLL"));\r
94 \r
95         IBS status;\r
96 \r
97         // Detach from the service manager\r
98         (*gds.Call()->m_service_detach)(status.Self(), &mHandle);\r
99 \r
100         // Set mHandle to 0 now, just in case we need to throw, because Disconnect()\r
101         // is called from Service destructor and we want to maintain a coherent state.\r
102         mHandle = 0;\r
103         if (status.Errors())\r
104                 throw SQLExceptionImpl(status, "Service::Disconnect", _("isc_service_detach failed"));\r
105 }\r
106 \r
107 void ServiceImpl::GetVersion(std::string& version)\r
108 {\r
109         // Based on a patch provided by Torsten Martinsen (SourceForge 'bullestock')\r
110 \r
111         if (gds.Call()->mGDSVersion < 60)\r
112                 throw LogicExceptionImpl("Service", _("Requires the version 6 of GDS32.DLL"));\r
113         if (mHandle == 0)\r
114                 throw LogicExceptionImpl("Service::GetVersion", _("Service is not connected."));\r
115 \r
116         IBS status;\r
117         SPB spb;\r
118         RB result(250);\r
119 \r
120         spb.Insert(isc_info_svc_server_version);\r
121 \r
122         (*gds.Call()->m_service_query)(status.Self(), &mHandle, 0, 0, 0, spb.Size(), spb.Self(),\r
123                 result.Size(), result.Self());\r
124         if (status.Errors())\r
125                 throw SQLExceptionImpl(status, "Service::GetVersion", _("isc_service_query failed"));\r
126 \r
127         result.GetString(isc_info_svc_server_version, version);\r
128 }\r
129 \r
130 void ServiceImpl::AddUser(const IBPP::User& user)\r
131 {\r
132         if (gds.Call()->mGDSVersion >= 60 && mHandle == 0)\r
133                 throw LogicExceptionImpl("Service::AddUser", _("Service is not connected."));\r
134         if (user.username.empty())\r
135                 throw LogicExceptionImpl("Service::AddUser", _("Username required."));\r
136         if (user.password.empty())\r
137                 throw LogicExceptionImpl("Service::AddUser", _("Password required."));\r
138 \r
139         IBS status;\r
140         SPB spb;\r
141         spb.Insert(isc_action_svc_add_user);\r
142         spb.InsertString(isc_spb_sec_username, 2, user.username.c_str());\r
143         spb.InsertString(isc_spb_sec_password, 2, user.password.c_str());\r
144         if (! user.firstname.empty())\r
145                         spb.InsertString(isc_spb_sec_firstname, 2, user.firstname.c_str());\r
146         if (! user.middlename.empty())\r
147                         spb.InsertString(isc_spb_sec_middlename, 2, user.middlename.c_str());\r
148         if (! user.lastname.empty())\r
149                         spb.InsertString(isc_spb_sec_lastname, 2, user.lastname.c_str());\r
150         if (user.userid != 0)\r
151                         spb.InsertQuad(isc_spb_sec_userid, (int32_t)user.userid);\r
152         if (user.groupid != 0)\r
153                         spb.InsertQuad(isc_spb_sec_groupid, (int32_t)user.groupid);\r
154 \r
155         (*gds.Call()->m_service_start)(status.Self(), &mHandle, 0, spb.Size(), spb.Self());\r
156         if (status.Errors())\r
157                 throw SQLExceptionImpl(status, "Service::AddUser", _("isc_service_start failed"));\r
158 \r
159         Wait();\r
160 }\r
161 \r
162 void ServiceImpl::ModifyUser(const IBPP::User& user)\r
163 {\r
164         if (gds.Call()->mGDSVersion >= 60 && mHandle == 0)\r
165                 throw LogicExceptionImpl("Service::ModifyUser", _("Service is not connected."));\r
166         if (user.username.empty())\r
167                 throw LogicExceptionImpl("Service::ModifyUser", _("Username required."));\r
168 \r
169         IBS status;\r
170         SPB spb;\r
171 \r
172         spb.Insert(isc_action_svc_modify_user);\r
173         spb.InsertString(isc_spb_sec_username, 2, user.username.c_str());\r
174         if (! user.password.empty())\r
175                         spb.InsertString(isc_spb_sec_password, 2, user.password.c_str());\r
176         if (! user.firstname.empty())\r
177                         spb.InsertString(isc_spb_sec_firstname, 2, user.firstname.c_str());\r
178         if (! user.middlename.empty())\r
179                         spb.InsertString(isc_spb_sec_middlename, 2, user.middlename.c_str());\r
180         if (! user.lastname.empty())\r
181                         spb.InsertString(isc_spb_sec_lastname, 2, user.lastname.c_str());\r
182         if (user.userid != 0)\r
183                         spb.InsertQuad(isc_spb_sec_userid, (int32_t)user.userid);\r
184         if (user.groupid != 0)\r
185                         spb.InsertQuad(isc_spb_sec_groupid, (int32_t)user.groupid);\r
186 \r
187         (*gds.Call()->m_service_start)(status.Self(), &mHandle, 0, spb.Size(), spb.Self());\r
188         if (status.Errors())\r
189                 throw SQLExceptionImpl(status, "Service::ModifyUser", _("isc_service_start failed"));\r
190 \r
191         Wait();\r
192 }\r
193 \r
194 void ServiceImpl::RemoveUser(const std::string& username)\r
195 {\r
196 \r
197         if (gds.Call()->mGDSVersion >= 60 && mHandle == 0)\r
198                 throw LogicExceptionImpl("Service::RemoveUser", _("Service is not connected."));\r
199         if (username.empty())\r
200                 throw LogicExceptionImpl("Service::RemoveUser", _("Username required."));\r
201 \r
202         IBS status;\r
203         SPB spb;\r
204 \r
205         spb.Insert(isc_action_svc_delete_user);\r
206         spb.InsertString(isc_spb_sec_username, 2, username.c_str());\r
207 \r
208         (*gds.Call()->m_service_start)(status.Self(), &mHandle, 0, spb.Size(), spb.Self());\r
209         if (status.Errors())\r
210                 throw SQLExceptionImpl(status, "Service::RemoveUser", _("isc_service_start failed"));\r
211 \r
212         Wait();\r
213 }\r
214 \r
215 void ServiceImpl::GetUser(IBPP::User& user)\r
216 {\r
217         if (gds.Call()->mGDSVersion < 60)\r
218                 throw LogicExceptionImpl("Service", _("Requires the version 6 of GDS32.DLL"));\r
219         if (mHandle == 0)\r
220                 throw LogicExceptionImpl("Service::GetUser", _("Service is not connected."));\r
221         if (user.username.empty())\r
222                 throw LogicExceptionImpl("Service::GetUser", _("Username required."));\r
223 \r
224         SPB spb;\r
225         spb.Insert(isc_action_svc_display_user);\r
226         spb.InsertString(isc_spb_sec_username, 2, user.username.c_str());\r
227 \r
228         IBS status;\r
229         (*gds.Call()->m_service_start)(status.Self(), &mHandle, 0, spb.Size(), spb.Self());\r
230         if (status.Errors())\r
231                 throw SQLExceptionImpl(status, "Service::GetUser", _("isc_service_start failed"));\r
232 \r
233         RB result(8000);\r
234         char request[] = {isc_info_svc_get_users};\r
235         status.Reset();\r
236         (*gds.Call()->m_service_query)(status.Self(), &mHandle, 0, 0, 0,\r
237                 sizeof(request), request, result.Size(), result.Self());\r
238         if (status.Errors())\r
239                 throw SQLExceptionImpl(status, "Service::GetUser", _("isc_service_query failed"));\r
240 \r
241         char* p = result.Self();\r
242         if (*p != isc_info_svc_get_users)\r
243                 throw SQLExceptionImpl(status, "Service::GetUser", _("isc_service_query returned unexpected answer"));\r
244 \r
245         p += 3; // Skips the 'isc_info_svc_get_users' and its total length\r
246         user.clear();\r
247         while (*p != isc_info_end)\r
248         {\r
249                 if (*p == isc_spb_sec_userid)\r
250                 {\r
251                         user.userid = (uint32_t)(*gds.Call()->m_vax_integer)(p+1, 4);\r
252                         p += 5;\r
253                 }\r
254                 else if (*p == isc_spb_sec_groupid)\r
255                 {\r
256                         user.groupid = (uint32_t)(*gds.Call()->m_vax_integer)(p+1, 4);\r
257                         p += 5;\r
258                 }\r
259                 else\r
260                 {\r
261                         unsigned short len = (unsigned short)(*gds.Call()->m_vax_integer)(p+1, 2);\r
262                         switch (*p)\r
263                         {\r
264                         case isc_spb_sec_username :\r
265                                 // For each user, this is the first element returned\r
266                                 if (len != 0) user.username.assign(p+3, len);\r
267                                 break;\r
268                         case isc_spb_sec_password :\r
269                                 if (len != 0) user.password.assign(p+3, len);\r
270                                 break;\r
271                         case isc_spb_sec_firstname :\r
272                                 if (len != 0) user.firstname.assign(p+3, len);\r
273                                 break;\r
274                         case isc_spb_sec_middlename :\r
275                                 if (len != 0) user.middlename.assign(p+3, len);\r
276                                 break;\r
277                         case isc_spb_sec_lastname :\r
278                                 if (len != 0) user.lastname.assign(p+3, len);\r
279                                 break;\r
280                         }\r
281                         p += (3 + len);\r
282                 }\r
283     }\r
284 }\r
285 \r
286 void ServiceImpl::GetUsers(std::vector<IBPP::User>& users)\r
287 {\r
288         if (gds.Call()->mGDSVersion < 60)\r
289                 throw LogicExceptionImpl("Service", _("Requires the version 6 of GDS32.DLL"));\r
290         if (mHandle == 0)\r
291                 throw LogicExceptionImpl("Service::GetUsers", _("Service is not connected."));\r
292 \r
293         SPB spb;\r
294         spb.Insert(isc_action_svc_display_user);\r
295 \r
296         IBS status;\r
297         (*gds.Call()->m_service_start)(status.Self(), &mHandle, 0, spb.Size(), spb.Self());\r
298         if (status.Errors())\r
299                 throw SQLExceptionImpl(status, "Service::GetUsers", _("isc_service_start failed"));\r
300 \r
301         RB result(8000);\r
302         char request[] = {isc_info_svc_get_users};\r
303         status.Reset();\r
304         (*gds.Call()->m_service_query)(status.Self(), &mHandle, 0, 0, 0,\r
305                 sizeof(request), request, result.Size(), result.Self());\r
306         if (status.Errors())\r
307                 throw SQLExceptionImpl(status, "Service::GetUsers", _("isc_service_query failed"));\r
308 \r
309         users.clear();\r
310         char* p = result.Self();\r
311         if (*p != isc_info_svc_get_users)\r
312                 throw SQLExceptionImpl(status, "Service::GetUsers", _("isc_service_query returned unexpected answer"));\r
313 \r
314         p += 3; // Skips the 'isc_info_svc_get_users' and its total length\r
315         IBPP::User user;\r
316         while (*p != isc_info_end)\r
317         {\r
318                 if (*p == isc_spb_sec_userid)\r
319                 {\r
320                         user.userid = (uint32_t)(*gds.Call()->m_vax_integer)(p+1, 4);\r
321                         p += 5;\r
322                 }\r
323                 else if (*p == isc_spb_sec_groupid)\r
324                 {\r
325                         user.groupid = (uint32_t)(*gds.Call()->m_vax_integer)(p+1, 4);\r
326                         p += 5;\r
327                 }\r
328                 else\r
329                 {\r
330                         unsigned short len = (unsigned short)(*gds.Call()->m_vax_integer)(p+1, 2);\r
331                         switch (*p)\r
332                         {\r
333                         case isc_spb_sec_username :\r
334                                 // For each user, this is the first element returned\r
335                                 if (! user.username.empty()) users.push_back(user);     // Flush previous user\r
336                                 user.clear();\r
337                                 if (len != 0) user.username.assign(p+3, len);\r
338                                 break;\r
339                         case isc_spb_sec_password :\r
340                                 if (len != 0) user.password.assign(p+3, len);\r
341                                 break;\r
342                         case isc_spb_sec_firstname :\r
343                                 if (len != 0) user.firstname.assign(p+3, len);\r
344                                 break;\r
345                         case isc_spb_sec_middlename :\r
346                                 if (len != 0) user.middlename.assign(p+3, len);\r
347                                 break;\r
348                         case isc_spb_sec_lastname :\r
349                                 if (len != 0) user.lastname.assign(p+3, len);\r
350                                 break;\r
351                         }\r
352                         p += (3 + len);\r
353                 }\r
354     }\r
355         if (! user.username.empty()) users.push_back(user);     // Flush last user\r
356 }\r
357 \r
358 void ServiceImpl::SetPageBuffers(const std::string& dbfile, int buffers)\r
359 {\r
360         if (gds.Call()->mGDSVersion < 60)\r
361                 throw LogicExceptionImpl("Service", _("Requires the version 6 of GDS32.DLL"));\r
362         if (mHandle     == 0)\r
363                 throw LogicExceptionImpl("Service::SetPageBuffers", _("Service is not connected."));\r
364         if (dbfile.empty())\r
365                 throw LogicExceptionImpl("Service::SetPageBuffers", _("Main database file must be specified."));\r
366 \r
367         IBS status;\r
368         SPB spb;\r
369 \r
370         spb.Insert(isc_action_svc_properties);\r
371         spb.InsertString(isc_spb_dbname, 2, dbfile.c_str());\r
372         spb.InsertQuad(isc_spb_prp_page_buffers, buffers);\r
373 \r
374         (*gds.Call()->m_service_start)(status.Self(), &mHandle, 0, spb.Size(), spb.Self());\r
375         if (status.Errors())\r
376                 throw SQLExceptionImpl(status, "Service::SetPageBuffers", _("isc_service_start failed"));\r
377 \r
378         Wait();\r
379 }\r
380 \r
381 void ServiceImpl::SetSweepInterval(const std::string& dbfile, int sweep)\r
382 {\r
383         if (gds.Call()->mGDSVersion < 60)\r
384                 throw LogicExceptionImpl("Service", _("Requires the version 6 of GDS32.DLL"));\r
385         if (mHandle     == 0)\r
386                 throw LogicExceptionImpl("Service::SetSweepInterval", _("Service is not connected."));\r
387         if (dbfile.empty())\r
388                 throw LogicExceptionImpl("Service::SetSweepInterval", _("Main database file must be specified."));\r
389 \r
390         IBS status;\r
391         SPB spb;\r
392 \r
393         spb.Insert(isc_action_svc_properties);\r
394         spb.InsertString(isc_spb_dbname, 2, dbfile.c_str());\r
395         spb.InsertQuad(isc_spb_prp_sweep_interval, sweep);\r
396 \r
397         (*gds.Call()->m_service_start)(status.Self(), &mHandle, 0, spb.Size(), spb.Self());\r
398         if (status.Errors())\r
399                 throw SQLExceptionImpl(status, "Service::SetSweepInterval", _("isc_service_start failed"));\r
400 \r
401         Wait();\r
402 }\r
403 \r
404 void ServiceImpl::SetSyncWrite(const std::string& dbfile, bool sync)\r
405 {\r
406         if (gds.Call()->mGDSVersion < 60)\r
407                 throw LogicExceptionImpl("Service", _("Requires the version 6 of GDS32.DLL"));\r
408         if (mHandle     == 0)\r
409                 throw LogicExceptionImpl("Service::SetSyncWrite", _("Service is not connected."));\r
410         if (dbfile.empty())\r
411                 throw LogicExceptionImpl("Service::SetSyncWrite", _("Main database file must be specified."));\r
412 \r
413         IBS status;\r
414         SPB spb;\r
415 \r
416         spb.Insert(isc_action_svc_properties);\r
417         spb.InsertString(isc_spb_dbname, 2, dbfile.c_str());\r
418         if (sync) spb.InsertByte(isc_spb_prp_write_mode, (char)isc_spb_prp_wm_sync);\r
419         else spb.InsertByte(isc_spb_prp_write_mode, (char)isc_spb_prp_wm_async);\r
420 \r
421         (*gds.Call()->m_service_start)(status.Self(), &mHandle, 0, spb.Size(), spb.Self());\r
422         if (status.Errors())\r
423                 throw SQLExceptionImpl(status, "Service::SetSyncWrite", _("isc_service_start failed"));\r
424 \r
425         Wait();\r
426 }\r
427 \r
428 void ServiceImpl::SetReadOnly(const std::string& dbfile, bool readonly)\r
429 {\r
430         if (gds.Call()->mGDSVersion < 60)\r
431                 throw LogicExceptionImpl("Service", _("Requires the version 6 of GDS32.DLL"));\r
432         if (mHandle     == 0)\r
433                 throw LogicExceptionImpl("Service::SetReadOnly", _("Service is not connected."));\r
434         if (dbfile.empty())\r
435                 throw LogicExceptionImpl("Service::SetReadOnly", _("Main database file must be specified."));\r
436 \r
437         IBS status;\r
438         SPB spb;\r
439 \r
440         spb.Insert(isc_action_svc_properties);\r
441         spb.InsertString(isc_spb_dbname, 2, dbfile.c_str());\r
442         if (readonly) spb.InsertByte(isc_spb_prp_access_mode, (char)isc_spb_prp_am_readonly);\r
443         else spb.InsertByte(isc_spb_prp_access_mode, (char)isc_spb_prp_am_readwrite);\r
444 \r
445         (*gds.Call()->m_service_start)(status.Self(), &mHandle, 0, spb.Size(), spb.Self());\r
446         if (status.Errors())\r
447                 throw SQLExceptionImpl(status, "Service::SetReadOnly", _("isc_service_start failed"));\r
448 \r
449         Wait();\r
450 }\r
451 \r
452 void ServiceImpl::SetReserveSpace(const std::string& dbfile, bool reserve)\r
453 {\r
454         if (gds.Call()->mGDSVersion < 60)\r
455                 throw LogicExceptionImpl("Service", _("Requires the version 6 of GDS32.DLL"));\r
456         if (mHandle     == 0)\r
457                 throw LogicExceptionImpl("Service::SetReserveSpace", _("Service is not connected."));\r
458         if (dbfile.empty())\r
459                 throw LogicExceptionImpl("Service::SetReserveSpace", _("Main database file must be specified."));\r
460 \r
461         IBS status;\r
462         SPB spb;\r
463 \r
464         spb.Insert(isc_action_svc_properties);\r
465         spb.InsertString(isc_spb_dbname, 2, dbfile.c_str());\r
466         if (reserve) spb.InsertByte(isc_spb_prp_reserve_space, (char)isc_spb_prp_res);\r
467         else spb.InsertByte(isc_spb_prp_reserve_space, (char)isc_spb_prp_res_use_full);\r
468 \r
469         (*gds.Call()->m_service_start)(status.Self(), &mHandle, 0, spb.Size(), spb.Self());\r
470         if (status.Errors())\r
471                 throw SQLExceptionImpl(status, "Service::SetReserveSpace", _("isc_service_start failed"));\r
472 \r
473         Wait();\r
474 }\r
475 \r
476 void ServiceImpl::Shutdown(const std::string& dbfile, IBPP::DSM mode, int sectimeout)\r
477 {\r
478         if (gds.Call()->mGDSVersion < 60)\r
479                 throw LogicExceptionImpl("Service", _("Requires the version 6 of GDS32.DLL"));\r
480         if (mHandle     == 0)\r
481                 throw LogicExceptionImpl("Service::Shutdown", _("Service is not connected."));\r
482         if (dbfile.empty())\r
483                 throw LogicExceptionImpl("Service::Shutdown", _("Main database file must be specified."));\r
484 \r
485         IBS status;\r
486         SPB spb;\r
487 \r
488         spb.Insert(isc_action_svc_properties);\r
489         spb.InsertString(isc_spb_dbname, 2, dbfile.c_str());\r
490         switch (mode)\r
491         {\r
492                 case IBPP::dsDenyAttach :\r
493                         spb.InsertQuad(isc_spb_prp_deny_new_attachments, sectimeout);\r
494                         break;\r
495                 case IBPP::dsDenyTrans :\r
496                         spb.InsertQuad(isc_spb_prp_deny_new_transactions, sectimeout);\r
497                         break;\r
498                 case IBPP::dsForce :\r
499                         spb.InsertQuad(isc_spb_prp_shutdown_db, sectimeout);\r
500                         break;\r
501         }\r
502 \r
503         (*gds.Call()->m_service_start)(status.Self(), &mHandle, 0, spb.Size(), spb.Self());\r
504         if (status.Errors())\r
505                 throw SQLExceptionImpl(status, "Service::Shutdown", _("isc_service_start failed"));\r
506 \r
507         Wait();\r
508 }\r
509 \r
510 void ServiceImpl::Restart(const std::string& dbfile)\r
511 {\r
512         if (gds.Call()->mGDSVersion < 60)\r
513                 throw LogicExceptionImpl("Service", _("Requires the version 6 of GDS32.DLL"));\r
514         if (mHandle     == 0)\r
515                 throw LogicExceptionImpl("Service::Restart", _("Service is not connected."));\r
516         if (dbfile.empty())\r
517                 throw LogicExceptionImpl("Service::Restart", _("Main database file must be specified."));\r
518 \r
519         IBS status;\r
520         SPB spb;\r
521 \r
522         spb.Insert(isc_action_svc_properties);\r
523         spb.InsertString(isc_spb_dbname, 2, dbfile.c_str());\r
524         spb.InsertQuad(isc_spb_options, isc_spb_prp_db_online);\r
525 \r
526         (*gds.Call()->m_service_start)(status.Self(), &mHandle, 0, spb.Size(), spb.Self());\r
527         if (status.Errors())\r
528                 throw SQLExceptionImpl(status, "Service::Restart", _("isc_service_start failed"));\r
529 \r
530         Wait();\r
531 }\r
532 \r
533 void ServiceImpl::Sweep(const std::string& dbfile)\r
534 {\r
535         if (gds.Call()->mGDSVersion < 60)\r
536                 throw LogicExceptionImpl("Service", _("Requires the version 6 of GDS32.DLL"));\r
537         if (mHandle     == 0)\r
538                 throw LogicExceptionImpl("Service::Sweep", _("Service is not connected."));\r
539         if (dbfile.empty())\r
540                 throw LogicExceptionImpl("Service::Sweep", _("Main database file must be specified."));\r
541 \r
542         IBS status;\r
543         SPB spb;\r
544 \r
545         spb.Insert(isc_action_svc_repair);\r
546         spb.InsertString(isc_spb_dbname, 2, dbfile.c_str());\r
547         spb.InsertQuad(isc_spb_options, isc_spb_rpr_sweep_db);\r
548 \r
549         (*gds.Call()->m_service_start)(status.Self(), &mHandle, 0, spb.Size(), spb.Self());\r
550         if (status.Errors())\r
551                 throw SQLExceptionImpl(status, "Service::Sweep", _("isc_service_start failed"));\r
552 \r
553         Wait();\r
554 }\r
555 \r
556 void ServiceImpl::Repair(const std::string& dbfile, IBPP::RPF flags)\r
557 {\r
558         if (gds.Call()->mGDSVersion < 60)\r
559                 throw LogicExceptionImpl("Service", _("Requires the version 6 of GDS32.DLL"));\r
560         if (mHandle     == 0)\r
561                 throw LogicExceptionImpl("Service::Repair", _("Service is not connected."));\r
562         if (dbfile.empty())\r
563                 throw LogicExceptionImpl("Service::Repair", _("Main database file must be specified."));\r
564 \r
565         IBS status;\r
566         SPB spb;\r
567 \r
568         spb.Insert(isc_action_svc_repair);\r
569         spb.InsertString(isc_spb_dbname, 2, dbfile.c_str());\r
570 \r
571         unsigned int mask;\r
572         if (flags & IBPP::rpValidateFull) mask = (isc_spb_rpr_full | isc_spb_rpr_validate_db);\r
573         else if (flags & IBPP::rpValidatePages) mask = isc_spb_rpr_validate_db;\r
574         else if (flags & IBPP::rpMendRecords) mask = isc_spb_rpr_mend_db;\r
575         else throw LogicExceptionImpl("Service::Repair",\r
576                 _("One of rpMendRecords, rpValidatePages, rpValidateFull is required."));\r
577 \r
578         if (flags & IBPP::rpReadOnly)                   mask |= isc_spb_rpr_check_db;\r
579         if (flags & IBPP::rpIgnoreChecksums)    mask |= isc_spb_rpr_ignore_checksum;\r
580         if (flags & IBPP::rpKillShadows)                mask |= isc_spb_rpr_kill_shadows;\r
581         \r
582         spb.InsertQuad(isc_spb_options, mask);\r
583 \r
584         (*gds.Call()->m_service_start)(status.Self(), &mHandle, 0, spb.Size(), spb.Self());\r
585         if (status.Errors())\r
586                 throw SQLExceptionImpl(status, "Service::Repair", _("isc_service_start failed"));\r
587 \r
588         Wait();\r
589 }\r
590 \r
591 void ServiceImpl::StartBackup(const std::string& dbfile,\r
592         const std::string& bkfile, IBPP::BRF flags)\r
593 {\r
594         if (gds.Call()->mGDSVersion < 60)\r
595                 throw LogicExceptionImpl("Service", _("Requires the version 6 of GDS32.DLL"));\r
596         if (mHandle     == 0)\r
597                 throw LogicExceptionImpl("Service::Backup", _("Service is not connected."));\r
598         if (dbfile.empty())\r
599                 throw LogicExceptionImpl("Service::Backup", _("Main database file must be specified."));\r
600         if (bkfile.empty())\r
601                 throw LogicExceptionImpl("Service::Backup", _("Backup file must be specified."));\r
602 \r
603         IBS status;\r
604         SPB spb;\r
605 \r
606         spb.Insert(isc_action_svc_backup);\r
607         spb.InsertString(isc_spb_dbname, 2, dbfile.c_str());\r
608         spb.InsertString(isc_spb_bkp_file, 2, bkfile.c_str());\r
609         if (flags & IBPP::brVerbose) spb.Insert(isc_spb_verbose);\r
610 \r
611         unsigned int mask = 0;\r
612         if (flags & IBPP::brIgnoreChecksums)    mask |= isc_spb_bkp_ignore_checksums;\r
613         if (flags & IBPP::brIgnoreLimbo)                mask |= isc_spb_bkp_ignore_limbo;\r
614         if (flags & IBPP::brMetadataOnly)               mask |= isc_spb_bkp_metadata_only;\r
615         if (flags & IBPP::brNoGarbageCollect)   mask |= isc_spb_bkp_no_garbage_collect;\r
616         if (flags & IBPP::brNonTransportable)   mask |= isc_spb_bkp_non_transportable;\r
617         if (flags & IBPP::brConvertExtTables)   mask |= isc_spb_bkp_convert;\r
618         if (mask != 0) spb.InsertQuad(isc_spb_options, mask);\r
619 \r
620         (*gds.Call()->m_service_start)(status.Self(), &mHandle, 0, spb.Size(), spb.Self());\r
621         if (status.Errors())\r
622                 throw SQLExceptionImpl(status, "Service::Backup", _("isc_service_start failed"));\r
623 }\r
624 \r
625 void ServiceImpl::StartRestore(const std::string& bkfile, const std::string& dbfile,\r
626         int     pagesize, IBPP::BRF flags)\r
627 {\r
628         if (gds.Call()->mGDSVersion < 60)\r
629                 throw LogicExceptionImpl("Service", _("Requires the version 6 of GDS32.DLL"));\r
630         if (mHandle     == 0)\r
631                 throw LogicExceptionImpl("Service::Restore", _("Service is not connected."));\r
632         if (bkfile.empty())\r
633                 throw LogicExceptionImpl("Service::Restore", _("Backup file must be specified."));\r
634         if (dbfile.empty())\r
635                 throw LogicExceptionImpl("Service::Restore", _("Main database file must be specified."));\r
636 \r
637         IBS status;\r
638         SPB spb;\r
639 \r
640         spb.Insert(isc_action_svc_restore);\r
641         spb.InsertString(isc_spb_bkp_file, 2, bkfile.c_str());\r
642         spb.InsertString(isc_spb_dbname, 2, dbfile.c_str());\r
643         if (flags & IBPP::brVerbose) spb.Insert(isc_spb_verbose);\r
644         if (pagesize != 0) spb.InsertQuad(isc_spb_res_page_size, pagesize);\r
645 \r
646         unsigned int mask;\r
647         if (flags & IBPP::brReplace) mask = isc_spb_res_replace;\r
648                 else mask = isc_spb_res_create; // Safe default mode\r
649 \r
650         if (flags & IBPP::brDeactivateIdx)      mask |= isc_spb_res_deactivate_idx;\r
651         if (flags & IBPP::brNoShadow)           mask |= isc_spb_res_no_shadow;\r
652         if (flags & IBPP::brNoValidity)         mask |= isc_spb_res_no_validity;\r
653         if (flags & IBPP::brPerTableCommit)     mask |= isc_spb_res_one_at_a_time;\r
654         if (flags & IBPP::brUseAllSpace)        mask |= isc_spb_res_use_all_space;\r
655         if (mask != 0) spb.InsertQuad(isc_spb_options, mask);\r
656 \r
657         (*gds.Call()->m_service_start)(status.Self(), &mHandle, 0, spb.Size(), spb.Self());\r
658         if (status.Errors())\r
659                 throw SQLExceptionImpl(status, "Service::Restore", _("isc_service_start failed"));\r
660 }\r
661 \r
662 const char* ServiceImpl::WaitMsg()\r
663 {\r
664         IBS status;\r
665         SPB req;\r
666         RB result(1024);\r
667 \r
668         if (gds.Call()->mGDSVersion < 60)\r
669                 throw LogicExceptionImpl("Service", _("Requires the version 6 of GDS32.DLL"));\r
670 \r
671         req.Insert(isc_info_svc_line);  // Request one line of textual output\r
672 \r
673         // _service_query will only block until a line of result is available\r
674         // (or until the end of the task if it does not report information)\r
675         (*gds.Call()->m_service_query)(status.Self(), &mHandle, 0, 0, 0,\r
676                 req.Size(),     req.Self(),     result.Size(), result.Self());\r
677         if (status.Errors())\r
678                 throw SQLExceptionImpl(status, "ServiceImpl::Wait", _("isc_service_query failed"));\r
679 \r
680         // If message length is zero bytes,     task is finished\r
681         if (result.GetString(isc_info_svc_line, mWaitMessage) == 0) return 0;\r
682 \r
683         // Task is not finished, but we have something to report\r
684         return mWaitMessage.c_str();\r
685 }\r
686 \r
687 void ServiceImpl::Wait()\r
688 {\r
689         IBS status;\r
690         SPB spb;\r
691         RB result(1024);\r
692         std::string msg;\r
693 \r
694         if (gds.Call()->mGDSVersion < 60)\r
695                 throw LogicExceptionImpl("Service", _("Requires the version 6 of GDS32.DLL"));\r
696 \r
697         spb.Insert(isc_info_svc_line);\r
698         for (;;)\r
699         {\r
700                 // Sleeps 1 millisecond upfront. This will release the remaining\r
701                 // timeslot of the thread. Doing so will give a good chance for small\r
702                 // services tasks to finish before we check if they are still running.\r
703                 // The deal is to limit (in that particular case) the number of loops\r
704                 // polling _service_query that will happen.\r
705 \r
706                 Sleep(1);\r
707 \r
708                 // _service_query will only block until a line of result is available\r
709                 // (or until the end of the task if it does not report information) \r
710                 (*gds.Call()->m_service_query)(status.Self(), &mHandle, 0, 0,   0,\r
711                         spb.Size(),     spb.Self(),     result.Size(), result.Self());\r
712                 if (status.Errors())\r
713                         throw SQLExceptionImpl(status, "ServiceImpl::Wait", _("isc_service_query failed"));\r
714 \r
715                 // If message length is zero bytes,     task is finished\r
716                 if (result.GetString(isc_info_svc_line, msg) == 0) return;\r
717 \r
718                 status.Reset();\r
719                 result.Reset();\r
720         }\r
721 }\r
722 \r
723 IBPP::IService* ServiceImpl::AddRef()\r
724 {\r
725         ASSERTION(mRefCount >= 0);\r
726         ++mRefCount;\r
727         return this;\r
728 }\r
729 \r
730 void ServiceImpl::Release()\r
731 {\r
732         // Release cannot throw, except in DEBUG builds on assertion\r
733         ASSERTION(mRefCount >= 0);\r
734         --mRefCount;\r
735         try { if (mRefCount <= 0) delete this; }\r
736                 catch (...) { }\r
737 }\r
738 \r
739 //      (((((((( OBJECT INTERNAL METHODS ))))))))\r
740 \r
741 void ServiceImpl::SetServerName(const char* newName)\r
742 {\r
743         if (newName == 0) mServerName.erase();\r
744         else mServerName = newName;\r
745 }\r
746 \r
747 void ServiceImpl::SetUserName(const char* newName)\r
748 {\r
749         if (newName == 0) mUserName.erase();\r
750         else mUserName = newName;\r
751 }\r
752 \r
753 void ServiceImpl::SetUserPassword(const char* newPassword)\r
754 {\r
755         if (newPassword == 0) mUserPassword.erase();\r
756         else mUserPassword = newPassword;\r
757 }\r
758 \r
759 ServiceImpl::ServiceImpl(const std::string& ServerName,\r
760                         const std::string& UserName, const std::string& UserPassword)\r
761         :       mRefCount(0), mHandle(0),\r
762                 mServerName(ServerName), mUserName(UserName), mUserPassword(UserPassword)\r
763 {\r
764 }\r
765 \r
766 ServiceImpl::~ServiceImpl()\r
767 {\r
768         try { if (Connected()) Disconnect(); }\r
769                 catch (...) { }\r
770 }\r
771 \r
772 //\r
773 //      Eof\r
774 //\r