1 /* $Id: nst_database.cpp 515877 2016-10-06 14:29:20Z satskyse $
2  * ===========================================================================
3  *
4  *                            PUBLIC DOMAIN NOTICE
5  *               National Center for Biotechnology Information
6  *
7  *  This software/database is a "United States Government Work" under the
8  *  terms of the United States Copyright Act.  It was written as part of
9  *  the author's official duties as a United States Government employee and
10  *  thus cannot be copyrighted.  This software/database is freely available
11  *  to the public for use. The National Library of Medicine and the U.S.
12  *  Government have not placed any restriction on its use or reproduction.
13  *
14  *  Although all reasonable efforts have been taken to ensure the accuracy
15  *  and reliability of the software and data, the NLM and the U.S.
16  *  Government do not and cannot warrant the performance or results that
17  *  may be obtained by using this software or data. The NLM and the U.S.
18  *  Government disclaim all warranties, express or implied, including
19  *  warranties of performance, merchantability or fitness for any particular
20  *  purpose.
21  *
22  *  Please cite the author in any work or product based on this material.
23  *
24  * ===========================================================================
25  *
26  * Author:  Sergey Satskiy
27  *
28  */
29 
30 #include <ncbi_pch.hpp>
31 
32 #include <corelib/ncbistd.hpp>
33 #include <corelib/resource_info.hpp>
34 #include <connect/services/json_over_uttp.hpp>
35 #include <connect/services/netstorage.hpp>
36 #include "nst_database.hpp"
37 #include "nst_exception.hpp"
38 #include "nst_application.hpp"
39 #include "nst_server.hpp"
40 #include "nst_clients.hpp"
41 #include "nst_config.hpp"
42 #include "nst_perf_logging.hpp"
43 #include "nst_constants.hpp"
44 
45 
46 BEGIN_NCBI_SCOPE
47 
48 
CNSTDatabase(CNetStorageServer * server)49 CNSTDatabase::CNSTDatabase(CNetStorageServer *  server)
50     : m_Server(server), m_Db(NULL), m_Connected(false),
51       m_RestoreConnectionThread(NULL),
52       m_SPTimeout(default_execute_sp_timeout)
53 {
54     // true: this is initialization time
55     x_CreateDatabase(true);
56     try {
57         m_RestoreConnectionThread.Reset(new CNSTDBConnectionThread(
58                                                 m_Connected, m_Db,
59                                                 this, m_DbLock));
60         m_RestoreConnectionThread->Run();
61     } catch (...) {
62         if (m_Db != NULL)
63             delete m_Db;
64         throw;
65     }
66 
67     // It might be that the DB has not been created because the database
68     // password could not be decrypted. In this case we need to try again every
69     // 100 seconds. These tries are made in the restore connection thread so
70     // let's wake it up here.
71     if (m_Db == NULL)
72         m_RestoreConnectionThread->Wakeup();
73 }
74 
75 
InitialConnect(void)76 void CNSTDatabase::InitialConnect(void)
77 {
78     if (m_Db != NULL && !m_Connected) {
79         try {
80             m_Db->Connect();
81             m_Connected = true;
82         } catch (const CException &  ex) {
83             m_Server->RegisterAlert(eDBConnect, "DB connection error: " +
84                                                 string(ex.what()));
85             ERR_POST(ex);
86             m_RestoreConnectionThread->Wakeup();
87         } catch (const exception &  ex) {
88             m_Server->RegisterAlert(eDBConnect, "DB connection error: " +
89                                                 string(ex.what()));
90             ERR_POST("Exception while connecting to the database: " <<
91                      ex.what());
92             m_RestoreConnectionThread->Wakeup();
93         } catch (...) {
94             m_Server->RegisterAlert(eDBConnect, "Unknown DB connection error");
95             ERR_POST("Unknown exception while connecting to the database");
96             m_RestoreConnectionThread->Wakeup();
97         }
98     }
99 }
100 
101 
~CNSTDatabase(void)102 CNSTDatabase::~CNSTDatabase(void)
103 {
104     m_RestoreConnectionThread->Stop();
105     m_RestoreConnectionThread->Join();
106     m_RestoreConnectionThread.Reset(0);
107 
108     if (m_Db != NULL) {
109         if (m_Connected)
110             m_Db->Close();
111         delete m_Db;
112     }
113 }
114 
115 
116 CJsonNode
SetParameters(const IRegistry & reg)117 CNSTDatabase::SetParameters(const IRegistry &  reg)
118 {
119     // The only parameter which could be changed is a SP execution timeout
120     double      current_timeout = m_SPTimeout.GetAsDouble();
121     double      new_timeout = reg.GetDouble("database",
122                                             "execute_sp_timeout",
123                                             default_execute_sp_timeout,
124                                             0, IRegistry::eReturn);
125     if (current_timeout == new_timeout)
126         return CJsonNode::NewNullNode();
127 
128     CJsonNode       diff = CJsonNode::NewObjectNode();
129     CJsonNode       values = CJsonNode::NewObjectNode();
130 
131     values.SetByKey("Old", CJsonNode::NewDoubleNode(current_timeout));
132     values.SetByKey("New", CJsonNode::NewDoubleNode(new_timeout));
133     diff.SetByKey("execute_sp_timeout", values);
134 
135     CFastMutexGuard     lock(m_SPTimeoutMutex);
136     m_SPTimeout.Set(new_timeout);
137     return diff;
138 }
139 
140 
141 int
ExecSP_CreateClient(const string & client,Int8 & client_id)142 CNSTDatabase::ExecSP_CreateClient(const string &  client, Int8 &  client_id)
143 {
144     const string        proc_name = "CreateClient";
145     CNSTPreciseTime     start = CNSTPreciseTime::Current();
146     try {
147         x_PreCheckConnection();
148 
149         int     status;
150         try {
151             CDatabase   db = m_Db->Clone();
152             CQuery      query = db.NewQuery();
153 
154             client_id = k_UndefinedClientID;
155             query.SetParameter("@client_name", client);
156             query.SetOutputParameter("@client_id", eSDB_Int8);
157 
158             query.ExecuteSP(proc_name, GetExecuteSPTimeout());
159             query.VerifyDone();
160             status = x_CheckStatus(query, proc_name);
161 
162             if (status == kSPStatusOK)
163                 client_id = query.GetParameter("@client_id").AsInt8();
164             else
165                 client_id = k_UndefinedClientID;
166 
167             g_DoPerfLogging("MS_SQL_" + proc_name,
168                             CNSTPreciseTime::Current() - start,
169                             CRequestStatus::e200_Ok);
170             return status;
171         } catch (const std::exception &  ex) {
172             m_Server->RegisterAlert(eDB, proc_name + " DB error: " + ex.what());
173             x_PostCheckConnection();
174             throw;
175         } catch (...) {
176             m_Server->RegisterAlert(eDB, proc_name + " unknown DB error");
177             x_PostCheckConnection();
178             throw;
179         }
180     } catch (...) {
181         g_DoPerfLogging("MS_SQL_" + proc_name,
182                         CNSTPreciseTime::Current() - start,
183                         CRequestStatus::e500_InternalServerError);
184         throw;
185     }
186 }
187 
188 
189 int
ExecSP_CreateUser(const CNSTUserID & user,Int8 & user_id)190 CNSTDatabase::ExecSP_CreateUser(const CNSTUserID &  user, Int8 &  user_id)
191 {
192     const string        proc_name = "CreateUser";
193     CNSTPreciseTime     start = CNSTPreciseTime::Current();
194     try {
195         x_PreCheckConnection();
196 
197         int     status;
198         try {
199             CDatabase   db = m_Db->Clone();
200             CQuery      query = db.NewQuery();
201 
202             user_id = k_UndefinedUserID;
203             query.SetParameter("@user_name", user.GetName());
204             query.SetParameter("@user_namespace", user.GetNamespace());
205             query.SetOutputParameter("@user_id", eSDB_Int8);
206 
207             query.ExecuteSP(proc_name, GetExecuteSPTimeout());
208             query.VerifyDone();
209             status = x_CheckStatus(query, proc_name);
210 
211             if (status == kSPStatusOK)
212                 user_id = query.GetParameter("@user_id").AsInt8();
213             else
214                 user_id = k_UndefinedUserID;
215 
216             g_DoPerfLogging("MS_SQL_" + proc_name,
217                             CNSTPreciseTime::Current() - start,
218                             CRequestStatus::e200_Ok);
219             return status;
220         } catch (const std::exception &  ex) {
221             m_Server->RegisterAlert(eDB, proc_name + " DB error: " + ex.what());
222             x_PostCheckConnection();
223             throw;
224         } catch (...) {
225             m_Server->RegisterAlert(eDB, proc_name + " unknown DB error");
226             x_PostCheckConnection();
227             throw;
228         }
229     } catch (...) {
230         g_DoPerfLogging("MS_SQL_" + proc_name,
231                         CNSTPreciseTime::Current() - start,
232                         CRequestStatus::e500_InternalServerError);
233         throw;
234     }
235 }
236 
237 
238 int
ExecSP_CreateObjectWithClientID(const string & object_key,const string & object_loc,Int8 size,Int8 client_id,Int8 user_id,const TNSTDBValue<CTimeSpan> ttl,bool & size_was_null)239 CNSTDatabase::ExecSP_CreateObjectWithClientID(
240             const string &  object_key,
241             const string &  object_loc, Int8  size,
242             Int8  client_id, Int8  user_id,
243             const TNSTDBValue<CTimeSpan>  ttl,
244             bool &  size_was_null)
245 {
246     // To avoid extending the list of resources in applog_perf
247     // two names are used: actual DB proc and how it looks in applog_perf
248     const string        proc_name = "CreateObjectWithClientID_v2";
249     const string        proc_name_for_perf_log = "CreateObjectWithClientID";
250     CNSTPreciseTime     start = CNSTPreciseTime::Current();
251     try {
252         x_PreCheckConnection();
253 
254         int     status;
255         try {
256             CNetStorageObjectLoc    object_loc_struct(
257                                                 m_Server->GetCompoundIDPool(),
258                                                 object_loc);
259             CDatabase               db = m_Db->Clone();
260             CQuery                  query = db.NewQuery();
261 
262             query.SetParameter("@object_key", object_key);
263             query.SetParameter("@object_create_tm",
264                                object_loc_struct.GetCreationTime());
265             query.SetParameter("@object_loc", object_loc);
266             query.SetParameter("@object_size", size);
267             query.SetParameter("@client_id", client_id);
268             query.SetParameter("@user_id", user_id);
269             query.SetOutputParameter("@size_was_null", eSDB_Int4);
270 
271             if (ttl.m_IsNull)
272                 query.SetNullParameter("@object_expiration", eSDB_DateTime);
273             else
274                 query.SetParameter("@object_expiration",
275                                    CTime(CTime::eCurrent) + ttl.m_Value);
276 
277             query.ExecuteSP(proc_name, GetExecuteSPTimeout());
278             query.VerifyDone();
279 
280             status = x_CheckStatus(query, proc_name);
281             g_DoPerfLogging("MS_SQL_" + proc_name_for_perf_log,
282                             CNSTPreciseTime::Current() - start,
283                             CRequestStatus::e200_Ok);
284 
285             if (status == kSPStatusOK) {
286                 size_was_null = (query.
287                                     GetParameter("@size_was_null").
288                                         AsInt4() != 0);
289             }
290             return status;
291         } catch (const std::exception &  ex) {
292             m_Server->RegisterAlert(eDB, proc_name + " DB error: " + ex.what());
293             x_PostCheckConnection();
294             throw;
295         } catch (...) {
296             m_Server->RegisterAlert(eDB, proc_name + " unknown DB error");
297             x_PostCheckConnection();
298             throw;
299         }
300     } catch (...) {
301         g_DoPerfLogging("MS_SQL_" + proc_name_for_perf_log,
302                         CNSTPreciseTime::Current() - start,
303                         CRequestStatus::e500_InternalServerError);
304         throw;
305     }
306 }
307 
308 
309 int
ExecSP_UpdateObjectOnWrite(const string & object_key,const string & object_loc,Int8 size,Int8 client_id,Int8 user_id,const TNSTDBValue<CTimeSpan> & ttl,const TNSTDBValue<CTimeSpan> & prolong_on_write,const TNSTDBValue<CTime> & object_expiration,bool & size_was_null)310 CNSTDatabase::ExecSP_UpdateObjectOnWrite(
311             const string &  object_key,
312             const string &  object_loc, Int8  size,
313             Int8  client_id, Int8  user_id,
314             const TNSTDBValue<CTimeSpan> &  ttl,
315             const TNSTDBValue<CTimeSpan> &  prolong_on_write,
316             const TNSTDBValue<CTime> &  object_expiration,
317             bool &  size_was_null)
318 {
319     // Calculate separate expirations for two cases:
320     // - record is found
321     // - record is not found
322     // It is easier to do in C++ than in MS SQL stored procedure
323     CTime                   current_time(CTime::eCurrent);
324     TNSTDBValue<CTime>      exp_record_found;
325     TNSTDBValue<CTime>      exp_record_not_found;
326     x_CalculateExpiration(current_time, ttl, prolong_on_write,
327                           object_expiration,
328                           exp_record_found, exp_record_not_found);
329 
330     const string        proc_name = "UpdateObjectOnWrite";
331     CNSTPreciseTime     start = CNSTPreciseTime::Current();
332     try {
333         x_PreCheckConnection();
334 
335         int     status;
336         try {
337             CDatabase               db = m_Db->Clone();
338             CQuery                  query = db.NewQuery();
339 
340             query.SetParameter("@object_key", object_key);
341             query.SetParameter("@object_loc", object_loc);
342             query.SetParameter("@object_size", size);
343             query.SetParameter("@client_id", client_id);
344             query.SetParameter("@user_id", user_id);
345             query.SetParameter("@current_time", current_time);
346             query.SetOutputParameter("@size_was_null", eSDB_Int4);
347 
348             if (exp_record_found.m_IsNull)
349                 query.SetNullParameter("@object_exp_if_found",
350                                        eSDB_DateTime);
351             else
352                 query.SetParameter("@object_exp_if_found",
353                                    exp_record_found.m_Value);
354             if (exp_record_not_found.m_IsNull)
355                 query.SetNullParameter("@object_exp_if_not_found",
356                                        eSDB_DateTime);
357             else
358                 query.SetParameter("@object_exp_if_not_found",
359                                    exp_record_not_found.m_Value);
360 
361             query.ExecuteSP(proc_name, GetExecuteSPTimeout());
362             query.VerifyDone();
363 
364             status = x_CheckStatus(query, proc_name);
365             g_DoPerfLogging("MS_SQL_" + proc_name,
366                             CNSTPreciseTime::Current() - start,
367                             CRequestStatus::e200_Ok);
368 
369             if (status == kSPStatusOK) {
370                 size_was_null = (query.
371                                     GetParameter("@size_was_null").
372                                         AsInt4() != 0);
373             }
374             return status;
375         } catch (const std::exception &  ex) {
376             m_Server->RegisterAlert(eDB, proc_name + " DB error: " + ex.what());
377             x_PostCheckConnection();
378             throw;
379         } catch (...) {
380             m_Server->RegisterAlert(eDB, proc_name + " unknown DB error");
381             x_PostCheckConnection();
382             throw;
383         }
384     } catch (...) {
385         g_DoPerfLogging("MS_SQL_" + proc_name,
386                         CNSTPreciseTime::Current() - start,
387                         CRequestStatus::e500_InternalServerError);
388         throw;
389     }
390 }
391 
392 
393 int
ExecSP_UpdateUserKeyObjectOnWrite(const string & object_key,const string & object_loc,Int8 size,Int8 client_id,const TNSTDBValue<CTimeSpan> & ttl,const TNSTDBValue<CTimeSpan> & prolong_on_write,const TNSTDBValue<CTime> & object_expiration)394 CNSTDatabase::ExecSP_UpdateUserKeyObjectOnWrite(
395             const string &  object_key,
396             const string &  object_loc, Int8  size, Int8  client_id,
397             const TNSTDBValue<CTimeSpan> &  ttl,
398             const TNSTDBValue<CTimeSpan> &  prolong_on_write,
399             const TNSTDBValue<CTime> &  object_expiration)
400 {
401     // Calculate separate expirations for two cases:
402     // - record is found
403     // - record is not found
404     // It is easier to do in C++ than in MS SQL stored procedure
405     CTime                   current_time(CTime::eCurrent);
406     TNSTDBValue<CTime>      exp_record_found;
407     TNSTDBValue<CTime>      exp_record_not_found;
408     x_CalculateExpiration(current_time, ttl, prolong_on_write,
409                           object_expiration,
410                           exp_record_found, exp_record_not_found);
411 
412     const string    proc_name = "UpdateUserKeyObjectOnWrite";
413     CNSTPreciseTime     start = CNSTPreciseTime::Current();
414     try {
415         x_PreCheckConnection();
416 
417         int     status;
418         try {
419             CDatabase               db = m_Db->Clone();
420             CQuery                  query = db.NewQuery();
421 
422             query.SetParameter("@object_key", object_key);
423             query.SetParameter("@object_loc", object_loc);
424             query.SetParameter("@object_size", size);
425             query.SetParameter("@client_id", client_id);
426             query.SetParameter("@current_time", current_time);
427 
428             if (exp_record_found.m_IsNull)
429                 query.SetNullParameter("@object_exp_if_found",
430                                        eSDB_DateTime);
431             else
432                 query.SetParameter("@object_exp_if_found",
433                                    exp_record_found.m_Value);
434             if (exp_record_not_found.m_IsNull)
435                 query.SetNullParameter("@object_exp_if_not_found",
436                                        eSDB_DateTime);
437             else
438                 query.SetParameter("@object_exp_if_not_found",
439                                    exp_record_not_found.m_Value);
440 
441             query.ExecuteSP(proc_name, GetExecuteSPTimeout());
442             query.VerifyDone();
443 
444             status = x_CheckStatus(query, proc_name);
445             g_DoPerfLogging("MS_SQL_" + proc_name,
446                             CNSTPreciseTime::Current() - start,
447                             CRequestStatus::e200_Ok);
448             return status;
449         } catch (const std::exception &  ex) {
450             m_Server->RegisterAlert(eDB, proc_name + " DB error: " + ex.what());
451             x_PostCheckConnection();
452             throw;
453         } catch (...) {
454             m_Server->RegisterAlert(eDB, proc_name + " unknown DB error");
455             x_PostCheckConnection();
456             throw;
457         }
458     } catch (...) {
459         g_DoPerfLogging("MS_SQL_" + proc_name,
460                         CNSTPreciseTime::Current() - start,
461                         CRequestStatus::e500_InternalServerError);
462         throw;
463     }
464 }
465 
466 
467 int
ExecSP_UpdateObjectOnRead(const string & object_key,const string & object_loc,Int8 size,Int8 client_id,const TNSTDBValue<CTimeSpan> & ttl,const TNSTDBValue<CTimeSpan> & prolong_on_read,const TNSTDBValue<CTime> & object_expiration,bool & size_was_null)468 CNSTDatabase::ExecSP_UpdateObjectOnRead(
469             const string &  object_key,
470             const string &  object_loc,
471             Int8  size, Int8  client_id,
472             const TNSTDBValue<CTimeSpan> &  ttl,
473             const TNSTDBValue<CTimeSpan> &  prolong_on_read,
474             const TNSTDBValue<CTime> &  object_expiration,
475             bool &  size_was_null)
476 {
477     // Calculate separate expirations for two cases:
478     // - record is found
479     // - record is not found
480     // It is easier to do in C++ than in MS SQL stored procedure
481     CTime                   current_time(CTime::eCurrent);
482     TNSTDBValue<CTime>      exp_record_found;
483     TNSTDBValue<CTime>      exp_record_not_found;
484     x_CalculateExpiration(current_time, ttl, prolong_on_read,
485                           object_expiration,
486                           exp_record_found, exp_record_not_found);
487 
488     const string        proc_name = "UpdateObjectOnRead";
489     CNSTPreciseTime     start = CNSTPreciseTime::Current();
490 
491     size_was_null = true;
492     try {
493         x_PreCheckConnection();
494 
495         int     status;
496         try {
497             CDatabase               db = m_Db->Clone();
498             CQuery                  query = db.NewQuery();
499 
500             query.SetParameter("@object_key", object_key);
501             query.SetParameter("@object_loc", object_loc);
502             query.SetParameter("@object_size", size);
503             query.SetParameter("@client_id", client_id);
504             query.SetParameter("@current_time", current_time);
505             query.SetOutputParameter("@size_was_null", eSDB_Int4);
506 
507             if (exp_record_found.m_IsNull)
508                 query.SetNullParameter("@object_exp_if_found",
509                                        eSDB_DateTime);
510             else
511                 query.SetParameter("@object_exp_if_found",
512                                    exp_record_found.m_Value);
513             if (exp_record_not_found.m_IsNull)
514                 query.SetNullParameter("@object_exp_if_not_found",
515                                        eSDB_DateTime);
516             else
517                 query.SetParameter("@object_exp_if_not_found",
518                                    exp_record_not_found.m_Value);
519 
520             query.ExecuteSP(proc_name, GetExecuteSPTimeout());
521             query.VerifyDone();
522 
523             status = x_CheckStatus(query, proc_name);
524             g_DoPerfLogging("MS_SQL_" + proc_name,
525                             CNSTPreciseTime::Current() - start,
526                             CRequestStatus::e200_Ok);
527 
528             if (status == kSPStatusOK) {
529                 size_was_null = (query.
530                                     GetParameter("@size_was_null").
531                                         AsInt4() != 0);
532             }
533             return status;
534         } catch (const std::exception &  ex) {
535             m_Server->RegisterAlert(eDB, proc_name + " DB error: " + ex.what());
536             x_PostCheckConnection();
537             throw;
538         } catch (...) {
539             m_Server->RegisterAlert(eDB, proc_name + " unknown DB error");
540             x_PostCheckConnection();
541             throw;
542         }
543     } catch (...) {
544         g_DoPerfLogging("MS_SQL_" + proc_name,
545                         CNSTPreciseTime::Current() - start,
546                         CRequestStatus::e500_InternalServerError);
547         throw;
548     }
549 }
550 
551 
552 int
ExecSP_UpdateObjectOnRelocate(const string & object_key,const string & object_loc,Int8 client_id,const TNSTDBValue<CTimeSpan> & ttl,const TNSTDBValue<CTimeSpan> & prolong_on_relocate,const TNSTDBValue<CTime> & object_expiration)553 CNSTDatabase::ExecSP_UpdateObjectOnRelocate(
554             const string &  object_key,
555             const string &  object_loc, Int8  client_id,
556             const TNSTDBValue<CTimeSpan> &  ttl,
557             const TNSTDBValue<CTimeSpan> &  prolong_on_relocate,
558             const TNSTDBValue<CTime> &  object_expiration)
559 {
560     // Calculate separate expirations for two cases:
561     // - record is found
562     // - record is not found
563     // It is easier to do in C++ than in MS SQL stored procedure
564     CTime                   current_time(CTime::eCurrent);
565     TNSTDBValue<CTime>      exp_record_found;
566     TNSTDBValue<CTime>      exp_record_not_found;
567     x_CalculateExpiration(current_time, ttl, prolong_on_relocate,
568                           object_expiration,
569                           exp_record_found, exp_record_not_found);
570 
571     const string        proc_name = "UpdateObjectOnRelocate";
572     CNSTPreciseTime     start = CNSTPreciseTime::Current();
573     try {
574         x_PreCheckConnection();
575 
576         int     status;
577         try {
578             CDatabase               db = m_Db->Clone();
579             CQuery                  query = db.NewQuery();
580 
581             query.SetParameter("@object_key", object_key);
582             query.SetParameter("@object_loc", object_loc);
583             query.SetParameter("@client_id", client_id);
584             query.SetParameter("@current_time", current_time);
585 
586             if (exp_record_found.m_IsNull)
587                 query.SetNullParameter("@object_exp_if_found",
588                                        eSDB_DateTime);
589             else
590                 query.SetParameter("@object_exp_if_found",
591                                    exp_record_found.m_Value);
592             if (exp_record_not_found.m_IsNull)
593                 query.SetNullParameter("@object_exp_if_not_found",
594                                        eSDB_DateTime);
595             else
596                 query.SetParameter("@object_exp_if_not_found",
597                                    exp_record_not_found.m_Value);
598 
599             query.ExecuteSP(proc_name, GetExecuteSPTimeout());
600             query.VerifyDone();
601 
602             status = x_CheckStatus(query, proc_name);
603             g_DoPerfLogging("MS_SQL_" + proc_name,
604                             CNSTPreciseTime::Current() - start,
605                             CRequestStatus::e200_Ok);
606             return status;
607         } catch (const std::exception &  ex) {
608             m_Server->RegisterAlert(eDB, proc_name + " DB error: " + ex.what());
609             x_PostCheckConnection();
610             throw;
611         } catch (...) {
612             m_Server->RegisterAlert(eDB, proc_name + " unknown DB error");
613             x_PostCheckConnection();
614             throw;
615         }
616     } catch (...) {
617         g_DoPerfLogging("MS_SQL_" + proc_name,
618                         CNSTPreciseTime::Current() - start,
619                         CRequestStatus::e500_InternalServerError);
620         throw;
621     }
622 }
623 
624 
625 int
UpdateExpirationIfExists(const string & object_key,const TNSTDBValue<CTimeSpan> & ttl,const TNSTDBValue<CTimeSpan> & prolong_on_read,const TNSTDBValue<CTime> & object_expiration)626 CNSTDatabase::UpdateExpirationIfExists(
627                         const string &  object_key,
628                         const TNSTDBValue<CTimeSpan> &  ttl,
629                         const TNSTDBValue<CTimeSpan> &  prolong_on_read,
630                         const TNSTDBValue<CTime> &  object_expiration)
631 {
632     // Here the only expiration for the case a record is found needs to be
633     // calculated. The procedure however is a generic one and calculates the
634     // expiration for a not found record. Use it and ignore the second
635     // calculated value.
636     CTime                   current_time(CTime::eCurrent);
637     TNSTDBValue<CTime>      exp_record_found;
638     TNSTDBValue<CTime>      exp_record_not_found;
639     x_CalculateExpiration(current_time, ttl, prolong_on_read,
640                           object_expiration,
641                           exp_record_found, exp_record_not_found);
642 
643     const string        proc_name = "SetObjectExpiration";
644     CNSTPreciseTime     start = CNSTPreciseTime::Current();
645     try {
646         x_PreCheckConnection();
647 
648         int     status;
649         try {
650             CDatabase               db = m_Db->Clone();
651             CQuery                  query = db.NewQuery();
652 
653             query.SetParameter("@object_key", object_key);
654 
655             if (exp_record_found.m_IsNull)
656                 query.SetNullParameter("@expiration", eSDB_DateTime);
657             else
658                 query.SetParameter("@expiration", exp_record_found.m_Value);
659             query.SetParameter("@create_if_not_found", 0, eSDB_Int4);
660 
661             query.SetNullParameter("@object_loc", eSDB_String);
662             query.SetNullParameter("@client_id", eSDB_Int8);
663             query.SetOutputParameter("@object_size", eSDB_Int8);
664             query.SetNullParameter("@ttl", eSDB_Int8);
665 
666             query.ExecuteSP(proc_name, GetExecuteSPTimeout());
667             query.VerifyDone();
668 
669             status = x_CheckStatus(query, proc_name);
670 
671             g_DoPerfLogging("MS_SQL_" + proc_name,
672                             CNSTPreciseTime::Current() - start,
673                             CRequestStatus::e200_Ok);
674             return status;
675         } catch (const std::exception &  ex) {
676             m_Server->RegisterAlert(eDB, proc_name + " DB error: " + ex.what());
677             x_PostCheckConnection();
678             throw;
679         } catch (...) {
680             m_Server->RegisterAlert(eDB, proc_name + " unknown DB error");
681             x_PostCheckConnection();
682             throw;
683         }
684     } catch (...) {
685         g_DoPerfLogging("MS_SQL_" + proc_name,
686                         CNSTPreciseTime::Current() - start,
687                         CRequestStatus::e500_InternalServerError);
688         throw;
689     }
690 }
691 
692 
693 int
ExecSP_UpdateUserIDForObject(const string & object_key,Int8 user_id)694 CNSTDatabase::ExecSP_UpdateUserIDForObject(const string &  object_key,
695                                            Int8  user_id)
696 {
697     const string        proc_name = "UpdateUserIDForObject";
698     CNSTPreciseTime     start = CNSTPreciseTime::Current();
699     try {
700         x_PreCheckConnection();
701 
702         try {
703             CDatabase               db = m_Db->Clone();
704             CQuery                  query = db.NewQuery();
705 
706             query.SetParameter("@object_key", object_key);
707             query.SetParameter("@u_id", user_id);
708 
709             query.ExecuteSP(proc_name, GetExecuteSPTimeout());
710             query.VerifyDone();
711 
712             int     status = x_CheckStatus(query, proc_name);
713             g_DoPerfLogging("MS_SQL_" + proc_name,
714                             CNSTPreciseTime::Current() - start,
715                             CRequestStatus::e200_Ok);
716             return status;
717         } catch (const std::exception &  ex) {
718             m_Server->RegisterAlert(eDB, proc_name + " DB error: " + ex.what());
719             x_PostCheckConnection();
720             throw;
721         } catch (...) {
722             m_Server->RegisterAlert(eDB, proc_name + " unknown DB error");
723             x_PostCheckConnection();
724             throw;
725         }
726     } catch (...) {
727         g_DoPerfLogging("MS_SQL_" + proc_name,
728                         CNSTPreciseTime::Current() - start,
729                         CRequestStatus::e500_InternalServerError);
730         throw;
731     }
732 }
733 
734 
735 int
ExecSP_RemoveObject(const string & object_key)736 CNSTDatabase::ExecSP_RemoveObject(const string &  object_key)
737 {
738     const string        proc_name = "RemoveObject";
739     CNSTPreciseTime     start = CNSTPreciseTime::Current();
740     try {
741         x_PreCheckConnection();
742 
743         int     status;
744         try {
745             CDatabase               db = m_Db->Clone();
746             CQuery                  query = db.NewQuery();
747 
748             query.SetParameter("@object_key", object_key);
749 
750             query.ExecuteSP(proc_name, GetExecuteSPTimeout());
751             query.VerifyDone();
752 
753             status = x_CheckStatus(query, proc_name);
754             g_DoPerfLogging("MS_SQL_" + proc_name,
755                             CNSTPreciseTime::Current() - start,
756                             CRequestStatus::e200_Ok);
757             return status;
758         } catch (const std::exception &  ex) {
759             m_Server->RegisterAlert(eDB, proc_name + " DB error: " + ex.what());
760             x_PostCheckConnection();
761             throw;
762         } catch (...) {
763             m_Server->RegisterAlert(eDB, proc_name + " unknown DB error");
764             x_PostCheckConnection();
765             throw;
766         }
767     } catch (...) {
768         g_DoPerfLogging("MS_SQL_" + proc_name,
769                         CNSTPreciseTime::Current() - start,
770                         CRequestStatus::e500_InternalServerError);
771         throw;
772     }
773 }
774 
775 
776 int
ExecSP_SetExpiration(const string & object_key,const TNSTDBValue<CTimeSpan> & ttl,bool create_if_not_found,const string & object_loc,Int8 client_id,TNSTDBValue<Int8> & object_size)777 CNSTDatabase::ExecSP_SetExpiration(const string &  object_key,
778                                    const TNSTDBValue<CTimeSpan> &  ttl,
779                                    bool  create_if_not_found,
780                                    const string &  object_loc,
781                                    Int8  client_id,
782                                    TNSTDBValue<Int8> &  object_size)
783 {
784     const string        proc_name = "SetObjectExpiration";
785     CNSTPreciseTime     start = CNSTPreciseTime::Current();
786     try {
787         x_PreCheckConnection();
788 
789         int     status;
790         try {
791             CDatabase               db = m_Db->Clone();
792             CQuery                  query = db.NewQuery();
793 
794             query.SetParameter("@object_key", object_key);
795 
796             if (ttl.m_IsNull) {
797                 query.SetNullParameter("@expiration", eSDB_DateTime);
798                 query.SetNullParameter("@ttl", eSDB_Int8);
799             } else {
800                 query.SetParameter("@expiration", CTime(CTime::eCurrent) +
801                                                   ttl.m_Value);
802                 query.SetParameter("@ttl",
803                                    static_cast<Int8>(ttl.m_Value.GetAsDouble()));
804             }
805             query.SetParameter("@create_if_not_found", create_if_not_found,
806                                eSDB_Int4);
807             query.SetParameter("@object_loc", object_loc);
808             query.SetParameter("@client_id", client_id);
809             query.SetOutputParameter("@object_size", eSDB_Int8);
810 
811             query.ExecuteSP(proc_name, GetExecuteSPTimeout());
812             query.VerifyDone();
813 
814             status = x_CheckStatus(query, proc_name);
815 
816             if (status == kSPStatusOK) {
817                 object_size.m_IsNull = query.GetParameter("@object_size").
818                                                                     IsNull();
819                 if (!object_size.m_IsNull)
820                     object_size.m_Value = query.GetParameter("@object_size").
821                                                                     AsInt8();
822             }
823 
824             g_DoPerfLogging("MS_SQL_" + proc_name,
825                             CNSTPreciseTime::Current() - start,
826                             CRequestStatus::e200_Ok);
827             return status;
828         } catch (const std::exception &  ex) {
829             m_Server->RegisterAlert(eDB, proc_name + " DB error: " + ex.what());
830             x_PostCheckConnection();
831             throw;
832         } catch (...) {
833             m_Server->RegisterAlert(eDB, proc_name + " unknown DB error");
834             x_PostCheckConnection();
835             throw;
836         }
837     } catch (...) {
838         g_DoPerfLogging("MS_SQL_" + proc_name,
839                         CNSTPreciseTime::Current() - start,
840                         CRequestStatus::e500_InternalServerError);
841         throw;
842     }
843 }
844 
845 
846 int
ExecSP_AddAttribute(const string & object_key,const string & object_loc,const string & attr_name,const string & attr_value,Int8 client_id,bool create_if_not_found,const TNSTDBValue<CTimeSpan> & ttl)847 CNSTDatabase::ExecSP_AddAttribute(const string &  object_key,
848                                   const string &  object_loc,
849                                   const string &  attr_name,
850                                   const string &  attr_value,
851                                   Int8  client_id,
852                                   bool  create_if_not_found,
853                                   const TNSTDBValue<CTimeSpan> &  ttl)
854 {
855     const string        proc_name = "AddAttribute";
856     CNSTPreciseTime     start = CNSTPreciseTime::Current();
857     try {
858         x_PreCheckConnection();
859 
860         int     status;
861         try {
862             CDatabase               db = m_Db->Clone();
863             CQuery                  query = db.NewQuery();
864 
865             query.SetParameter("@object_key", object_key);
866             query.SetParameter("@attr_name", attr_name);
867             query.SetParameter("@attr_value", attr_value, eSDB_Binary);
868             query.SetParameter("@client_id", client_id);
869             query.SetParameter("@create_if_not_found", create_if_not_found,
870                                eSDB_Int4);
871             query.SetParameter("@object_loc", object_loc);
872 
873             if (ttl.m_IsNull)
874                 query.SetNullParameter("@object_expiration", eSDB_DateTime);
875             else
876                 query.SetParameter("@object_expiration",
877                                    CTime(CTime::eCurrent) + ttl.m_Value);
878 
879             query.ExecuteSP(proc_name, GetExecuteSPTimeout());
880             query.VerifyDone();
881 
882             status = x_CheckStatus(query, proc_name);
883             g_DoPerfLogging("MS_SQL_" + proc_name,
884                             CNSTPreciseTime::Current() - start,
885                             CRequestStatus::e200_Ok);
886             return status;
887         } catch (const std::exception &  ex) {
888             m_Server->RegisterAlert(eDB, proc_name + " DB error: " + ex.what());
889             x_PostCheckConnection();
890             throw;
891         } catch (...) {
892             m_Server->RegisterAlert(eDB, proc_name + " unknown DB error");
893             x_PostCheckConnection();
894             throw;
895         }
896     } catch (...) {
897         g_DoPerfLogging("MS_SQL_" + proc_name,
898                         CNSTPreciseTime::Current() - start,
899                         CRequestStatus::e500_InternalServerError);
900         throw;
901     }
902 }
903 
904 
905 int
ExecSP_GetAttributeNames(const string & object_key,vector<string> & attr_names)906 CNSTDatabase::ExecSP_GetAttributeNames(const string &  object_key,
907                                        vector<string> &  attr_names)
908 {
909     const string        proc_name = "GetAttributeNames";
910     CNSTPreciseTime     start = CNSTPreciseTime::Current();
911     try {
912         x_PreCheckConnection();
913 
914         int     status;
915         try {
916             CDatabase               db = m_Db->Clone();
917             CQuery                  query = db.NewQuery();
918 
919             query.SetParameter("@object_key", object_key);
920             query.ExecuteSP(proc_name, GetExecuteSPTimeout());
921 
922             // NOTE: reading result recordset must be done before getting the
923             //       status code. And it is safe to iterate even if a recordset
924             //       is not there
925             ITERATE(CQuery, qit, query.SingleSet()) {
926                 attr_names.push_back(qit["name"].AsString());
927             }
928             query.VerifyDone();
929 
930             status = x_CheckStatus(query, proc_name);
931             g_DoPerfLogging("MS_SQL_" + proc_name,
932                             CNSTPreciseTime::Current() - start,
933                             CRequestStatus::e200_Ok);
934             return status;
935         } catch (const std::exception &  ex) {
936             m_Server->RegisterAlert(eDB, proc_name + " DB error: " + ex.what());
937             x_PostCheckConnection();
938             throw;
939         } catch (...) {
940             m_Server->RegisterAlert(eDB, proc_name + " unknown DB error");
941             x_PostCheckConnection();
942             throw;
943         }
944     } catch (...) {
945         g_DoPerfLogging("MS_SQL_" + proc_name,
946                         CNSTPreciseTime::Current() - start,
947                         CRequestStatus::e500_InternalServerError);
948         throw;
949     }
950 }
951 
952 
953 int
ExecSP_GetAttribute(const string & object_key,const string & attr_name,bool need_update,string & value)954 CNSTDatabase::ExecSP_GetAttribute(const string &  object_key,
955                                   const string &  attr_name,
956                                   bool            need_update,
957                                   string &        value)
958 {
959     const string        proc_name = "GetAttribute";
960     CNSTPreciseTime     start = CNSTPreciseTime::Current();
961     try {
962         x_PreCheckConnection();
963 
964         int     status;
965         try {
966             CDatabase               db = m_Db->Clone();
967             CQuery                  query = db.NewQuery();
968 
969             query.SetParameter("@object_key", object_key);
970             query.SetParameter("@attr_name", attr_name);
971             query.SetParameter("@need_update", need_update,
972                                eSDB_Int4);
973             query.SetOutputParameter("@attr_value", eSDB_Binary);
974 
975             query.ExecuteSP(proc_name, GetExecuteSPTimeout());
976             query.VerifyDone();
977             status = x_CheckStatus(query, proc_name);
978 
979             if (status == kSPStatusOK)
980                 value = query.GetParameter("@attr_value").AsString();
981             else
982                 value = "";
983             g_DoPerfLogging("MS_SQL_" + proc_name,
984                             CNSTPreciseTime::Current() - start,
985                             CRequestStatus::e200_Ok);
986             return status;
987         } catch (const std::exception &  ex) {
988             m_Server->RegisterAlert(eDB, proc_name + " DB error: " + ex.what());
989             x_PostCheckConnection();
990             throw;
991         } catch (...) {
992             m_Server->RegisterAlert(eDB, proc_name + " unknown DB error");
993             x_PostCheckConnection();
994             throw;
995         }
996     } catch (...) {
997         g_DoPerfLogging("MS_SQL_" + proc_name,
998                         CNSTPreciseTime::Current() - start,
999                         CRequestStatus::e500_InternalServerError);
1000         throw;
1001     }
1002 }
1003 
1004 
1005 int
ExecSP_DelAttribute(const string & object_key,const string & attr_name)1006 CNSTDatabase::ExecSP_DelAttribute(const string &  object_key,
1007                                   const string &  attr_name)
1008 {
1009     const string        proc_name = "DelAttribute";
1010     CNSTPreciseTime     start = CNSTPreciseTime::Current();
1011     try {
1012         x_PreCheckConnection();
1013 
1014         int     status;
1015         try {
1016             CDatabase               db = m_Db->Clone();
1017             CQuery                  query = db.NewQuery();
1018 
1019             query.SetParameter("@object_key", object_key);
1020             query.SetParameter("@attr_name", attr_name);
1021 
1022             query.ExecuteSP(proc_name, GetExecuteSPTimeout());
1023             query.VerifyDone();
1024 
1025             status = x_CheckStatus(query, proc_name);
1026             g_DoPerfLogging("MS_SQL_" + proc_name,
1027                             CNSTPreciseTime::Current() - start,
1028                             CRequestStatus::e200_Ok);
1029             return status;
1030         } catch (const std::exception &  ex) {
1031             m_Server->RegisterAlert(eDB, proc_name + " DB error: " + ex.what());
1032             x_PostCheckConnection();
1033             throw;
1034         } catch (...) {
1035             m_Server->RegisterAlert(eDB, proc_name + " unknown DB error");
1036             x_PostCheckConnection();
1037             throw;
1038         }
1039     } catch (...) {
1040         g_DoPerfLogging("MS_SQL_" + proc_name,
1041                         CNSTPreciseTime::Current() - start,
1042                         CRequestStatus::e500_InternalServerError);
1043         throw;
1044     }
1045 }
1046 
1047 
1048 int
ExecSP_GetObjectFixedAttributes(const string & object_key,TNSTDBValue<CTime> & expiration,TNSTDBValue<CTime> & creation,TNSTDBValue<CTime> & obj_read,TNSTDBValue<CTime> & obj_write,TNSTDBValue<CTime> & attr_read,TNSTDBValue<CTime> & attr_write,TNSTDBValue<Int8> & read_count,TNSTDBValue<Int8> & write_count,TNSTDBValue<string> & client_name,TNSTDBValue<string> & user_namespace,TNSTDBValue<string> & user_name,TNSTDBValue<Int8> & obj_ttl)1049 CNSTDatabase::ExecSP_GetObjectFixedAttributes(
1050                                 const string &          object_key,
1051                                 TNSTDBValue<CTime> &    expiration,
1052                                 TNSTDBValue<CTime> &    creation,
1053                                 TNSTDBValue<CTime> &    obj_read,
1054                                 TNSTDBValue<CTime> &    obj_write,
1055                                 TNSTDBValue<CTime> &    attr_read,
1056                                 TNSTDBValue<CTime> &    attr_write,
1057                                 TNSTDBValue<Int8> &     read_count,
1058                                 TNSTDBValue<Int8> &     write_count,
1059                                 TNSTDBValue<string> &   client_name,
1060                                 TNSTDBValue<string> &   user_namespace,
1061                                 TNSTDBValue<string> &   user_name,
1062                                 TNSTDBValue<Int8> &     obj_ttl
1063                                               )
1064 {
1065     const string        proc_name = "GetObjectFixedAttributes";
1066     CNSTPreciseTime     start = CNSTPreciseTime::Current();
1067     try {
1068         x_PreCheckConnection();
1069 
1070         int     status;
1071         try {
1072             CDatabase               db = m_Db->Clone();
1073             CQuery                  query = db.NewQuery();
1074 
1075             query.SetParameter("@object_key", object_key);
1076             query.SetOutputParameter("@expiration", eSDB_DateTime);
1077             query.SetOutputParameter("@creation", eSDB_DateTime);
1078             query.SetOutputParameter("@obj_read", eSDB_DateTime);
1079             query.SetOutputParameter("@obj_write", eSDB_DateTime);
1080             query.SetOutputParameter("@attr_read", eSDB_DateTime);
1081             query.SetOutputParameter("@attr_write", eSDB_DateTime);
1082             query.SetOutputParameter("@read_cnt", eSDB_Int8);
1083             query.SetOutputParameter("@write_cnt", eSDB_Int8);
1084             query.SetOutputParameter("@client_name", eSDB_String);
1085             query.SetOutputParameter("@user_namespace", eSDB_String);
1086             query.SetOutputParameter("@user_name", eSDB_String);
1087             query.SetOutputParameter("@obj_ttl", eSDB_Int8);
1088 
1089             query.ExecuteSP(proc_name, GetExecuteSPTimeout());
1090             query.VerifyDone();
1091             status = x_CheckStatus(query, proc_name);
1092 
1093             if (status == kSPStatusOK) {
1094                 expiration.m_IsNull = query.GetParameter("@expiration").
1095                                                                 IsNull();
1096                 if (!expiration.m_IsNull)
1097                     expiration.m_Value = query.GetParameter("@expiration").
1098                                                                 AsDateTime();
1099                 creation.m_IsNull = query.GetParameter("@creation").IsNull();
1100                 if (!creation.m_IsNull)
1101                     creation.m_Value = query.GetParameter("@creation").
1102                                                                 AsDateTime();
1103                 obj_read.m_IsNull = query.GetParameter("@obj_read").IsNull();
1104                 if (!obj_read.m_IsNull)
1105                     obj_read.m_Value = query.GetParameter("@obj_read").
1106                                                                 AsDateTime();
1107                 obj_write.m_IsNull = query.GetParameter("@obj_write").IsNull();
1108                 if (!obj_write.m_IsNull)
1109                     obj_write.m_Value = query.GetParameter("@obj_write").
1110                                                                 AsDateTime();
1111                 attr_read.m_IsNull = query.GetParameter("@attr_read").IsNull();
1112                 if (!attr_read.m_IsNull)
1113                     attr_read.m_Value = query.GetParameter("@attr_read").
1114                                                                 AsDateTime();
1115                 attr_write.m_IsNull = query.GetParameter("@attr_write").
1116                                                                 IsNull();
1117                 if (!attr_write.m_IsNull)
1118                     attr_write.m_Value = query.GetParameter("@attr_write").
1119                                                                 AsDateTime();
1120                 read_count.m_IsNull = query.GetParameter("@read_cnt").IsNull();
1121                 if (!read_count.m_IsNull)
1122                     read_count.m_Value = query.GetParameter("@read_cnt").
1123                                                                 AsInt8();
1124                 write_count.m_IsNull = query.GetParameter("@write_cnt").
1125                                                                 IsNull();
1126                 if (!write_count.m_IsNull)
1127                     write_count.m_Value = query.GetParameter("@write_cnt").
1128                                                                 AsInt8();
1129                 client_name.m_IsNull = query.GetParameter("@client_name").
1130                                                                 IsNull();
1131                 if (!client_name.m_IsNull)
1132                     client_name.m_Value = query.GetParameter("@client_name").
1133                                                                 AsString();
1134                 user_namespace.m_IsNull = query.GetParameter("@user_namespace").
1135                                                                 IsNull();
1136                 if (!user_namespace.m_IsNull)
1137                     user_namespace.m_Value = query.
1138                                                 GetParameter("@user_namespace").
1139                                                                 AsString();
1140                 user_name.m_IsNull = query.GetParameter("@user_name").
1141                                                                 IsNull();
1142                 if (!user_name.m_IsNull)
1143                     user_name.m_Value = query.GetParameter("@user_name").
1144                                                                 AsString();
1145 
1146                 obj_ttl.m_IsNull = query.GetParameter("@obj_ttl").
1147                                                                 IsNull();
1148                 if (!obj_ttl.m_IsNull)
1149                     obj_ttl.m_Value = query.GetParameter("@obj_ttl").
1150                                                                 AsInt8();
1151             }
1152             g_DoPerfLogging("MS_SQL_" + proc_name,
1153                             CNSTPreciseTime::Current() - start,
1154                             CRequestStatus::e200_Ok);
1155             return status;
1156         } catch (const std::exception &  ex) {
1157             m_Server->RegisterAlert(eDB, proc_name + " DB error: " + ex.what());
1158             x_PostCheckConnection();
1159             throw;
1160         } catch (...) {
1161             m_Server->RegisterAlert(eDB, proc_name + " unknown DB error");
1162             x_PostCheckConnection();
1163             throw;
1164         }
1165     } catch (...) {
1166         g_DoPerfLogging("MS_SQL_" + proc_name,
1167                         CNSTPreciseTime::Current() - start,
1168                         CRequestStatus::e500_InternalServerError);
1169         throw;
1170     }
1171 }
1172 
1173 
1174 int
ExecSP_GetObjectExpiration(const string & object_key,TNSTDBValue<CTime> & expiration,TNSTDBValue<Int8> & individual_object_ttl)1175 CNSTDatabase::ExecSP_GetObjectExpiration(
1176                         const string &        object_key,
1177                         TNSTDBValue<CTime> &  expiration,
1178                         TNSTDBValue<Int8> &  individual_object_ttl)
1179 {
1180     const string        proc_name = "GetObjectExpiration";
1181     CNSTPreciseTime     start = CNSTPreciseTime::Current();
1182     try {
1183         x_PreCheckConnection();
1184 
1185         int     status;
1186         try {
1187             CDatabase               db = m_Db->Clone();
1188             CQuery                  query = db.NewQuery();
1189 
1190             query.SetParameter("@object_key", object_key);
1191             query.SetOutputParameter("@expiration", eSDB_DateTime);
1192             query.SetOutputParameter("@ttl", eSDB_Int8);
1193 
1194             query.ExecuteSP(proc_name, GetExecuteSPTimeout());
1195             query.VerifyDone();
1196             status = x_CheckStatus(query, proc_name);
1197 
1198             if (status == kSPStatusOK) {
1199                 expiration.m_IsNull = query.GetParameter("@expiration").
1200                                                                 IsNull();
1201                 if (!expiration.m_IsNull)
1202                     expiration.m_Value = query.GetParameter("@expiration").
1203                                                                 AsDateTime();
1204                 individual_object_ttl.m_IsNull = query.GetParameter("@ttl").
1205                                                                 IsNull();
1206                 if (!individual_object_ttl.m_IsNull)
1207                     individual_object_ttl.m_Value = query.GetParameter("@ttl").
1208                                                                 AsInt8();
1209             }
1210             g_DoPerfLogging("MS_SQL_" + proc_name,
1211                             CNSTPreciseTime::Current() - start,
1212                             CRequestStatus::e200_Ok);
1213             return status;
1214         } catch (const std::exception &  ex) {
1215             m_Server->RegisterAlert(eDB, proc_name + " DB error: " + ex.what());
1216             x_PostCheckConnection();
1217             throw;
1218         } catch (...) {
1219             m_Server->RegisterAlert(eDB, proc_name + " unknown DB error");
1220             x_PostCheckConnection();
1221             throw;
1222         }
1223     } catch (...) {
1224         g_DoPerfLogging("MS_SQL_" + proc_name,
1225                         CNSTPreciseTime::Current() - start,
1226                         CRequestStatus::e500_InternalServerError);
1227         throw;
1228     }
1229 }
1230 
1231 
1232 map<string, string>
ExecSP_GetGeneralDBInfo(void)1233 CNSTDatabase::ExecSP_GetGeneralDBInfo(void)
1234 {
1235     map<string, string>     result;
1236     const string            proc_name = "sp_spaceused";
1237     CNSTPreciseTime         start = CNSTPreciseTime::Current();
1238     try {
1239         x_PreCheckConnection();
1240 
1241         try {
1242             CDatabase               db = m_Db->Clone();
1243             CQuery                  query = db.NewQuery();
1244 
1245             query.ExecuteSP(proc_name, GetExecuteSPTimeout());
1246 
1247             // sp_spaceused provides two recordsets 1 record each, e.g.
1248             // NETSTORAGE   224.88 MB   98.34 MB
1249             // 1696 KB   752 KB  736 KB  208 KB
1250             ITERATE(CQuery, qit, query.SingleSet()) {
1251                 for (size_t  k = 1; k <= qit.GetTotalColumns(); ++k) {
1252                     string  columnName = qit.GetColumnName(k);
1253                     result[columnName] = qit[k].AsString();
1254                 }
1255             }
1256             query.VerifyDone();
1257 
1258             g_DoPerfLogging("MS_SQL_" + proc_name,
1259                             CNSTPreciseTime::Current() - start,
1260                             CRequestStatus::e200_Ok);
1261             return result;
1262         } catch (const std::exception &  ex) {
1263             m_Server->RegisterAlert(eDB, proc_name + " DB error: " + ex.what());
1264             x_PostCheckConnection();
1265             throw;
1266         } catch (...) {
1267             m_Server->RegisterAlert(eDB, proc_name + " unknown DB error");
1268             x_PostCheckConnection();
1269             throw;
1270         }
1271     } catch (...) {
1272         g_DoPerfLogging("MS_SQL_" + proc_name,
1273                         CNSTPreciseTime::Current() - start,
1274                         CRequestStatus::e500_InternalServerError);
1275         throw;
1276     }
1277 }
1278 
1279 
1280 map<string, string>
ExecSP_GetStatDBInfo(void)1281 CNSTDatabase::ExecSP_GetStatDBInfo(void)
1282 {
1283     map<string, string>     result;
1284     const string            proc_name = "GetStatInfo";
1285     CNSTPreciseTime         start = CNSTPreciseTime::Current();
1286     try {
1287         x_PreCheckConnection();
1288 
1289         try {
1290             CDatabase               db = m_Db->Clone();
1291             CQuery                  query = db.NewQuery();
1292 
1293             query.ExecuteSP(proc_name, GetExecuteSPTimeout());
1294 
1295             ITERATE(CQuery, qit, query.SingleSet()) {
1296                 for (size_t  k = 1; k <= qit.GetTotalColumns(); ++k) {
1297                     string  columnName = qit.GetColumnName(k);
1298                     result[columnName] = qit[k].AsString();
1299                 }
1300             }
1301             query.VerifyDone();
1302 
1303             g_DoPerfLogging("MS_SQL_" + proc_name,
1304                             CNSTPreciseTime::Current() - start,
1305                             CRequestStatus::e200_Ok);
1306             return result;
1307         } catch (const std::exception &  ex) {
1308             m_Server->RegisterAlert(eDB, proc_name + " DB error: " + ex.what());
1309             x_PostCheckConnection();
1310             throw;
1311         } catch (...) {
1312             m_Server->RegisterAlert(eDB, proc_name + " unknown DB error");
1313             x_PostCheckConnection();
1314             throw;
1315         }
1316     } catch (...) {
1317         g_DoPerfLogging("MS_SQL_" + proc_name,
1318                         CNSTPreciseTime::Current() - start,
1319                         CRequestStatus::e500_InternalServerError);
1320         throw;
1321     }
1322 }
1323 
1324 
1325 int
ExecSP_GetClientObjects(const string & client_name,TNSTDBValue<Int8> limit,Int8 & total,vector<string> & locators)1326 CNSTDatabase::ExecSP_GetClientObjects(const string &  client_name,
1327                                       TNSTDBValue<Int8>  limit,
1328                                       Int8 &  total,
1329                                       vector<string> &  locators)
1330 {
1331     const string            proc_name = "GetClientObjects";
1332     CNSTPreciseTime         start = CNSTPreciseTime::Current();
1333     try {
1334         x_PreCheckConnection();
1335 
1336         int     status;
1337         try {
1338             CDatabase               db = m_Db->Clone();
1339             CQuery                  query = db.NewQuery();
1340 
1341             query.SetParameter("@client_name", client_name);
1342             if (limit.m_IsNull)
1343                 query.SetNullParameter("@limit", eSDB_Int8);
1344             else
1345                 query.SetParameter("@limit", limit.m_Value);
1346             query.SetOutputParameter("@total_object_cnt", eSDB_Int8);
1347 
1348             query.ExecuteSP(proc_name, GetExecuteSPTimeout());
1349 
1350             // NOTE: reading result recordset must be done before getting the
1351             //       status code
1352             ITERATE(CQuery, qit, query.SingleSet()) {
1353                 locators.push_back(qit["object_loc"].AsString());
1354             }
1355 
1356             if (!query.GetParameter("@total_object_cnt").IsNull())
1357                 total = query.GetParameter("@total_object_cnt").AsInt8();
1358             query.VerifyDone();
1359 
1360             status = x_CheckStatus(query, proc_name);
1361             g_DoPerfLogging("MS_SQL_" + proc_name,
1362                             CNSTPreciseTime::Current() - start,
1363                             CRequestStatus::e200_Ok);
1364             return status;
1365         } catch (const std::exception &  ex) {
1366             m_Server->RegisterAlert(eDB, proc_name + " DB error: " + ex.what());
1367             x_PostCheckConnection();
1368             throw;
1369         } catch (...) {
1370             m_Server->RegisterAlert(eDB, proc_name + " unknown DB error");
1371             x_PostCheckConnection();
1372             throw;
1373         }
1374     } catch (...) {
1375         g_DoPerfLogging("MS_SQL_" + proc_name,
1376                         CNSTPreciseTime::Current() - start,
1377                         CRequestStatus::e500_InternalServerError);
1378         throw;
1379     }
1380 }
1381 
1382 
1383 int
ExecSP_GetUserObjects(const string & user_name,const string & user_name_space,TNSTDBValue<Int8> limit,Int8 & total,vector<string> & locators)1384 CNSTDatabase::ExecSP_GetUserObjects(const string &  user_name,
1385                                     const string &  user_name_space,
1386                                     TNSTDBValue<Int8>  limit,
1387                                     Int8 &  total,
1388                                     vector<string> &  locators)
1389 {
1390     const string            proc_name = "GetUserObjects";
1391     CNSTPreciseTime         start = CNSTPreciseTime::Current();
1392     try {
1393         x_PreCheckConnection();
1394 
1395         int     status;
1396         try {
1397             CDatabase               db = m_Db->Clone();
1398             CQuery                  query = db.NewQuery();
1399 
1400             query.SetParameter("@user_name", user_name);
1401             query.SetParameter("@user_name_space", user_name_space);
1402             if (limit.m_IsNull)
1403                 query.SetNullParameter("@limit", eSDB_Int8);
1404             else
1405                 query.SetParameter("@limit", limit.m_Value);
1406             query.SetOutputParameter("@total_object_cnt", eSDB_Int8);
1407 
1408             query.ExecuteSP(proc_name, GetExecuteSPTimeout());
1409 
1410             // NOTE: reading result recordset must be done before getting the
1411             //       status code
1412             ITERATE(CQuery, qit, query.SingleSet()) {
1413                 locators.push_back(qit["object_loc"].AsString());
1414             }
1415 
1416             if (!query.GetParameter("@total_object_cnt").IsNull())
1417                 total = query.GetParameter("@total_object_cnt").AsInt8();
1418             query.VerifyDone();
1419 
1420             status = x_CheckStatus(query, proc_name);
1421             g_DoPerfLogging("MS_SQL_" + proc_name,
1422                             CNSTPreciseTime::Current() - start,
1423                             CRequestStatus::e200_Ok);
1424             return status;
1425         } catch (const std::exception &  ex) {
1426             m_Server->RegisterAlert(eDB, proc_name + " DB error: " + ex.what());
1427             x_PostCheckConnection();
1428             throw;
1429         } catch (...) {
1430             m_Server->RegisterAlert(eDB, proc_name + " unknown DB error");
1431             x_PostCheckConnection();
1432             throw;
1433         }
1434     } catch (...) {
1435         g_DoPerfLogging("MS_SQL_" + proc_name,
1436                         CNSTPreciseTime::Current() - start,
1437                         CRequestStatus::e500_InternalServerError);
1438         throw;
1439     }
1440 }
1441 
1442 
1443 int
ExecSP_GetClients(vector<string> & names)1444 CNSTDatabase::ExecSP_GetClients(vector<string> &  names)
1445 {
1446     const string            proc_name = "GetClients";
1447     CNSTPreciseTime         start = CNSTPreciseTime::Current();
1448     try {
1449         x_PreCheckConnection();
1450 
1451         int     status;
1452         try {
1453             CDatabase               db = m_Db->Clone();
1454             CQuery                  query = db.NewQuery();
1455 
1456             query.ExecuteSP(proc_name, GetExecuteSPTimeout());
1457 
1458             // NOTE: reading result recordset must be done before getting the
1459             //       status code. And it is safe to iterate over a recordset
1460             //       even if there is no one.
1461             ITERATE(CQuery, qit, query.SingleSet()) {
1462                 names.push_back(qit["name"].AsString());
1463             }
1464             query.VerifyDone();
1465 
1466             status = x_CheckStatus(query, proc_name);
1467             g_DoPerfLogging("MS_SQL_" + proc_name,
1468                             CNSTPreciseTime::Current() - start,
1469                             CRequestStatus::e200_Ok);
1470             return status;
1471         } catch (const std::exception &  ex) {
1472             m_Server->RegisterAlert(eDB, proc_name + " DB error: " + ex.what());
1473             x_PostCheckConnection();
1474             throw;
1475         } catch (...) {
1476             m_Server->RegisterAlert(eDB, proc_name + " unknown DB error");
1477             x_PostCheckConnection();
1478             throw;
1479         }
1480     } catch (...) {
1481         g_DoPerfLogging("MS_SQL_" + proc_name,
1482                         CNSTPreciseTime::Current() - start,
1483                         CRequestStatus::e500_InternalServerError);
1484         throw;
1485     }
1486 }
1487 
1488 
1489 int
ExecSP_GetUsers(vector<pair<string,string>> & users)1490 CNSTDatabase::ExecSP_GetUsers(vector< pair<string, string> > &  users)
1491 {
1492     const string            proc_name = "GetUsers";
1493     CNSTPreciseTime         start = CNSTPreciseTime::Current();
1494     try {
1495         x_PreCheckConnection();
1496 
1497         int     status;
1498         try {
1499             CDatabase               db = m_Db->Clone();
1500             CQuery                  query = db.NewQuery();
1501 
1502             query.ExecuteSP(proc_name, GetExecuteSPTimeout());
1503 
1504             // NOTE: reading result recordset must be done before getting the
1505             //       status code. And it is safe to iterate over a recordset
1506             //       even if there is no one.
1507             ITERATE(CQuery, qit, query.SingleSet()) {
1508                 users.push_back(make_pair(qit["name"].AsString(),
1509                                           qit["name_space"].AsString()));
1510             }
1511             query.VerifyDone();
1512 
1513             status = x_CheckStatus(query, proc_name);
1514             g_DoPerfLogging("MS_SQL_" + proc_name,
1515                             CNSTPreciseTime::Current() - start,
1516                             CRequestStatus::e200_Ok);
1517             return status;
1518         } catch (const std::exception &  ex) {
1519             m_Server->RegisterAlert(eDB, proc_name + " DB error: " + ex.what());
1520             x_PostCheckConnection();
1521             throw;
1522         } catch (...) {
1523             m_Server->RegisterAlert(eDB, proc_name + " unknown DB error");
1524             x_PostCheckConnection();
1525             throw;
1526         }
1527     } catch (...) {
1528         g_DoPerfLogging("MS_SQL_" + proc_name,
1529                         CNSTPreciseTime::Current() - start,
1530                         CRequestStatus::e500_InternalServerError);
1531         throw;
1532     }
1533 }
1534 
1535 
1536 int
ExecSP_DoesObjectExist(const string & object_key)1537 CNSTDatabase::ExecSP_DoesObjectExist(const string &  object_key)
1538 {
1539     const string        proc_name = "DoesObjectExist";
1540     CNSTPreciseTime     start = CNSTPreciseTime::Current();
1541     try {
1542         x_PreCheckConnection();
1543 
1544         int     status;
1545         try {
1546             CDatabase               db = m_Db->Clone();
1547             CQuery                  query = db.NewQuery();
1548 
1549             query.SetParameter("@object_key", object_key);
1550 
1551             query.ExecuteSP(proc_name, GetExecuteSPTimeout());
1552             query.VerifyDone();
1553 
1554             status = x_CheckStatus(query, proc_name);
1555             g_DoPerfLogging("MS_SQL_" + proc_name,
1556                             CNSTPreciseTime::Current() - start,
1557                             CRequestStatus::e200_Ok);
1558             return status;
1559         } catch (const std::exception &  ex) {
1560             m_Server->RegisterAlert(eDB, proc_name + " DB error: " + ex.what());
1561             x_PostCheckConnection();
1562             throw;
1563         } catch (...) {
1564             m_Server->RegisterAlert(eDB, proc_name + " unknown DB error");
1565             x_PostCheckConnection();
1566             throw;
1567         }
1568     } catch (...) {
1569         g_DoPerfLogging("MS_SQL_" + proc_name,
1570                         CNSTPreciseTime::Current() - start,
1571                         CRequestStatus::e500_InternalServerError);
1572         throw;
1573     }
1574 }
1575 
1576 
1577 int
ExecSP_GetObjectSizeAndLocator(const string & object_key,TNSTDBValue<Int8> & object_size,TNSTDBValue<string> & object_locator)1578 CNSTDatabase::ExecSP_GetObjectSizeAndLocator(
1579                                     const string &  object_key,
1580                                     TNSTDBValue<Int8> &  object_size,
1581                                     TNSTDBValue<string> &  object_locator)
1582 {
1583     const string        proc_name = "GetObjectSizeAndLocator";
1584     CNSTPreciseTime     start = CNSTPreciseTime::Current();
1585     try {
1586         x_PreCheckConnection();
1587 
1588         int     status;
1589         try {
1590             CDatabase   db = m_Db->Clone();
1591             CQuery      query = db.NewQuery();
1592             query.SetParameter("@object_key", object_key);
1593             query.SetOutputParameter("@object_size", eSDB_Int8);
1594             query.SetOutputParameter("@object_locator", eSDB_String);
1595 
1596             query.ExecuteSP(proc_name, GetExecuteSPTimeout());
1597             query.VerifyDone();
1598             status = x_CheckStatus(query, proc_name);
1599 
1600             if (status == kSPStatusOK) {
1601                 object_size.m_IsNull = query.
1602                                     GetParameter("@object_size").IsNull();
1603                 if (!object_size.m_IsNull)
1604                     object_size.m_Value = query.
1605                                     GetParameter("@object_size").AsInt8();
1606                 object_locator.m_IsNull = query.
1607                                     GetParameter("@object_locator").IsNull();
1608                 if (!object_locator.m_IsNull)
1609                     object_locator.m_Value = query.
1610                                     GetParameter("@object_locator").AsString();
1611             }
1612 
1613             g_DoPerfLogging("MS_SQL_" + proc_name,
1614                             CNSTPreciseTime::Current() - start,
1615                             CRequestStatus::e200_Ok);
1616             return status;
1617         } catch (const std::exception &  ex) {
1618             m_Server->RegisterAlert(eDB, proc_name + " DB error: " + ex.what());
1619             x_PostCheckConnection();
1620             throw;
1621         } catch (...) {
1622             m_Server->RegisterAlert(eDB, proc_name + " unknown DB error");
1623             x_PostCheckConnection();
1624             throw;
1625         }
1626     } catch (...) {
1627         g_DoPerfLogging("MS_SQL_" + proc_name,
1628                         CNSTPreciseTime::Current() - start,
1629                         CRequestStatus::e500_InternalServerError);
1630         throw;
1631     }
1632 }
1633 
1634 
1635 int
ExecSP_GetObjectSize(const string & object_key,TNSTDBValue<Int8> & object_size)1636 CNSTDatabase::ExecSP_GetObjectSize(const string &  object_key,
1637                                    TNSTDBValue<Int8> &  object_size)
1638 {
1639     const string        proc_name = "GetObjectSize";
1640     CNSTPreciseTime     start = CNSTPreciseTime::Current();
1641     try {
1642         x_PreCheckConnection();
1643 
1644         int     status;
1645         try {
1646             CDatabase   db = m_Db->Clone();
1647             CQuery      query = db.NewQuery();
1648 
1649             query.SetParameter("@object_key", object_key);
1650             query.SetOutputParameter("@object_size", eSDB_Int8);
1651 
1652             query.ExecuteSP(proc_name, GetExecuteSPTimeout());
1653             query.VerifyDone();
1654             status = x_CheckStatus(query, proc_name);
1655 
1656             if (status == kSPStatusOK) {
1657                 object_size.m_IsNull = query.GetParameter("@object_size").
1658                                                                     IsNull();
1659                 if (!object_size.m_IsNull)
1660                     object_size.m_Value = query.GetParameter("@object_size").
1661                                                                     AsInt8();
1662             }
1663 
1664             g_DoPerfLogging("MS_SQL_" + proc_name,
1665                             CNSTPreciseTime::Current() - start,
1666                             CRequestStatus::e200_Ok);
1667             return status;
1668         } catch (const std::exception &  ex) {
1669             m_Server->RegisterAlert(eDB, proc_name + " DB error: " + ex.what());
1670             x_PostCheckConnection();
1671             throw;
1672         } catch (...) {
1673             m_Server->RegisterAlert(eDB, proc_name + " unknown DB error");
1674             x_PostCheckConnection();
1675             throw;
1676         }
1677     } catch (...) {
1678         g_DoPerfLogging("MS_SQL_" + proc_name,
1679                         CNSTPreciseTime::Current() - start,
1680                         CRequestStatus::e500_InternalServerError);
1681         throw;
1682     }
1683 }
1684 
1685 
1686 int
ExecSP_UpdateObjectSizeIfNULL(const string & object_key,TNSTDBValue<Int8> & object_size)1687 CNSTDatabase::ExecSP_UpdateObjectSizeIfNULL(const string &  object_key,
1688                                             TNSTDBValue<Int8> &  object_size)
1689 {
1690     const string        proc_name = "UpdateObjectSizeIfNULL";
1691     CNSTPreciseTime     start = CNSTPreciseTime::Current();
1692     try {
1693         x_PreCheckConnection();
1694 
1695         int     status;
1696         try {
1697             CDatabase   db = m_Db->Clone();
1698             CQuery      query = db.NewQuery();
1699 
1700             query.SetParameter("@object_key", object_key);
1701             query.SetOutputParameter("@object_size", eSDB_Int8);
1702 
1703             query.ExecuteSP(proc_name, GetExecuteSPTimeout());
1704             query.VerifyDone();
1705             status = x_CheckStatus(query, proc_name);
1706 
1707             if (status == kSPStatusOK) {
1708                 object_size.m_IsNull = query.GetParameter("@object_size").
1709                                                                     IsNull();
1710                 if (!object_size.m_IsNull)
1711                     object_size.m_Value = query.GetParameter("@object_size").
1712                                                                     AsInt8();
1713             }
1714 
1715             g_DoPerfLogging("MS_SQL_" + proc_name,
1716                             CNSTPreciseTime::Current() - start,
1717                             CRequestStatus::e200_Ok);
1718             return status;
1719         } catch (const std::exception &  ex) {
1720             m_Server->RegisterAlert(eDB, proc_name + " DB error: " + ex.what());
1721             x_PostCheckConnection();
1722             throw;
1723         } catch (...) {
1724             m_Server->RegisterAlert(eDB, proc_name + " unknown DB error");
1725             x_PostCheckConnection();
1726             throw;
1727         }
1728     } catch (...) {
1729         g_DoPerfLogging("MS_SQL_" + proc_name,
1730                         CNSTPreciseTime::Current() - start,
1731                         CRequestStatus::e500_InternalServerError);
1732         throw;
1733     }
1734 }
1735 
1736 
x_PreCheckConnection(void)1737 void CNSTDatabase::x_PreCheckConnection(void)
1738 {
1739     CFastMutexGuard     guard(m_DbLock);
1740 
1741     if (m_Db == NULL || !m_Connected)
1742         NCBI_THROW(CNetStorageServerException, eDatabaseError,
1743                    "There is no connection to metadata information database");
1744 
1745     // It is possible that a connection has been lost and restored while there
1746     // were no activities
1747     if (!m_Db->IsConnected(CDatabase::eFastCheck)) {
1748         try {
1749             m_Db->Close();
1750             m_Db->Connect();
1751         } catch (...) {
1752             // To avoid interfering the connection restoring thread nothing is
1753             // done here. Basically the fact that we are here means there is no
1754             // connection anymore. The exception is suppressed however a stored
1755             // procedure execution exception will be generated a few moments
1756             // later and a normal procedure of the connection restoration will
1757             // be activated.
1758         }
1759     }
1760 }
1761 
1762 
x_PostCheckConnection(void)1763 void CNSTDatabase::x_PostCheckConnection(void)
1764 {
1765     CFastMutexGuard     guard(m_DbLock);
1766 
1767     if (m_Db == NULL)
1768         return;     // It must never happened - the existance of the m_Db is
1769                     // checked in the pre condition
1770 
1771     if (!m_Db->IsConnected(CDatabase::eFastCheck)) {
1772         m_Connected = false;
1773         m_Server->RegisterAlert(eDBConnect, "Database connection lost");
1774         ERR_POST(Critical << "Database connection has been lost");
1775         m_RestoreConnectionThread->Wakeup();
1776     }
1777 }
1778 
1779 
x_CheckStatus(CQuery & query,const string & procedure)1780 int  CNSTDatabase::x_CheckStatus(CQuery &  query,
1781                                  const string &  procedure)
1782 {
1783     int     status = query.GetStatus();
1784     if (status > 0)
1785         NCBI_THROW(CNetStorageServerException, eDatabaseError,
1786                    "Error executing " + procedure + " stored "
1787                    "procedure (return code " + NStr::NumericToString(status) +
1788                    "). See MS SQL log for details.");
1789     return status;
1790 }
1791 
1792 
x_ReadDbAccessInfo(bool is_initialization)1793 bool  CNSTDatabase::x_ReadDbAccessInfo(bool  is_initialization)
1794 {
1795     CNetStorageDApp *       app = dynamic_cast<CNetStorageDApp*>
1796                                         (CNcbiApplication::Instance());
1797     const CNcbiRegistry &   reg  = app->GetConfig();
1798 
1799     m_DbAccessInfo.m_Service = reg.GetString("database", "service", "");
1800     m_DbAccessInfo.m_Database = reg.GetString("database", "database", "");
1801     m_DbAccessInfo.m_UserName = reg.GetString("database", "user_name", "");
1802     m_SPTimeout = CTimeout(reg.GetDouble("database",
1803                                          "execute_sp_timeout",
1804                                          default_execute_sp_timeout,
1805                                          0, IRegistry::eReturn));
1806 
1807     // Try to decrypt
1808     try {
1809         m_DbAccessInfo.m_Password = reg.GetEncryptedString("database",
1810                                               "password",
1811                                               IRegistry::fPlaintextAllowed);
1812     } catch (const CRegistryException &  ex) {
1813         if (is_initialization) {
1814             if (ex.GetErrCode() == CRegistryException::eDecryptionFailed) {
1815                 m_Server->RegisterAlert(eDecryptDBPass, string(ex.what()));
1816                 ERR_POST(Critical << "Decrypting [database]/password "
1817                          "error: " << ex);
1818             }
1819         }
1820         return false;
1821     }
1822     return true;
1823 }
1824 
1825 
x_CreateDatabase(bool is_initialization)1826 void  CNSTDatabase::x_CreateDatabase(bool  is_initialization)
1827 {
1828     if (x_ReadDbAccessInfo(is_initialization)) {
1829         string  uri = "dbapi://" + m_DbAccessInfo.m_UserName +
1830                       ":" + m_DbAccessInfo.m_Password +
1831                       "@" + m_DbAccessInfo.m_Service +
1832                       "/" + m_DbAccessInfo.m_Database;
1833 
1834         CSDB_ConnectionParam    db_params(uri);
1835         m_Db = new CDatabase(db_params);
1836     }
1837 }
1838 
1839 
1840 // Calculates the new object expiration for two cases:
1841 // - object is found in the DB
1842 // - object is not found in the DB (and thus should be created)
1843 void
x_CalculateExpiration(const CTime & current_time,const TNSTDBValue<CTimeSpan> & ttl,const TNSTDBValue<CTimeSpan> & prolong,const TNSTDBValue<CTime> & object_expiration,TNSTDBValue<CTime> & exp_record_found,TNSTDBValue<CTime> & exp_record_not_found)1844 CNSTDatabase::x_CalculateExpiration(
1845                             const CTime &  current_time,
1846                             const TNSTDBValue<CTimeSpan> &  ttl,
1847                             const TNSTDBValue<CTimeSpan> &  prolong,
1848                             const TNSTDBValue<CTime> &  object_expiration,
1849                             TNSTDBValue<CTime> &  exp_record_found,
1850                             TNSTDBValue<CTime> &  exp_record_not_found)
1851 {
1852     if (prolong.m_IsNull) {
1853         // This could happen only if:
1854         // - a prolong is configured as a <multiplier> ttl
1855         // - service TTL is configured as infinity
1856         // - the object individual TTL is not set
1857         exp_record_found.m_IsNull = true;
1858         exp_record_not_found.m_IsNull = true;
1859         return;
1860     }
1861 
1862     // Here: prolong value is finite
1863     CTimeSpan   prolong_val = prolong.m_Value;
1864 
1865     if (prolong_val.IsEmpty()) {
1866         // Prolong time has NOT been configured
1867         if (object_expiration.m_IsNull) {
1868             exp_record_found.m_IsNull = true;
1869             if (ttl.m_IsNull) {
1870                 exp_record_not_found.m_IsNull = true;
1871             } else {
1872                 exp_record_not_found.m_IsNull = false;
1873                 exp_record_not_found.m_Value = current_time + ttl.m_Value;
1874             }
1875         } else {
1876             exp_record_found.m_IsNull = false;
1877             exp_record_found.m_Value = object_expiration.m_Value;
1878 
1879             // Record exists (otherwise the object_expiration is NULL).
1880             // So the expiration for the case the record is not found is
1881             // not strictly required. However, to be on the safe side set it
1882             // too.
1883             if (ttl.m_IsNull) {
1884                 exp_record_not_found.m_IsNull = true;
1885             } else {
1886                 exp_record_not_found.m_IsNull = false;
1887                 exp_record_not_found.m_Value = current_time + ttl.m_Value;
1888             }
1889         }
1890     } else {
1891         // Prolong time has been configured
1892         if (object_expiration.m_IsNull) {
1893             exp_record_found.m_IsNull = true;
1894             if (ttl.m_IsNull) {
1895                 exp_record_not_found.m_IsNull = true;
1896             } else {
1897                 exp_record_not_found.m_IsNull = false;
1898                 if (ttl.m_Value > prolong_val)
1899                     exp_record_not_found.m_Value = current_time + ttl.m_Value;
1900                 else
1901                     exp_record_not_found.m_Value = current_time + prolong_val;
1902             }
1903         } else {
1904             exp_record_found.m_IsNull = false;
1905             if (object_expiration.m_Value > current_time + prolong_val)
1906                 exp_record_found.m_Value = object_expiration.m_Value;
1907             else
1908                 exp_record_found.m_Value = current_time + prolong_val;
1909 
1910             // Record exists (otherwise the object_expiration is NULL).
1911             // So the expiration for the case the record is not found is
1912             // not strictly required. However, to be on the safe side set it
1913             // too.
1914             if (ttl.m_IsNull) {
1915                 exp_record_not_found.m_IsNull = true;
1916             } else {
1917                 exp_record_not_found.m_IsNull = false;
1918                 if (ttl.m_Value > prolong_val)
1919                     exp_record_not_found.m_Value = current_time + ttl.m_Value;
1920                 else
1921                     exp_record_not_found.m_Value = current_time + prolong_val;
1922             }
1923         }
1924     }
1925 }
1926 
1927 
1928 CTimeout
GetExecuteSPTimeout(void)1929 CNSTDatabase::GetExecuteSPTimeout(void)
1930 {
1931     CFastMutexGuard     lock(m_SPTimeoutMutex);
1932     return m_SPTimeout;
1933 }
1934 
1935 
1936 END_NCBI_SCOPE
1937 
1938