NCBI C++ ToolKit
blobstore.cpp
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* $Id: blobstore.cpp 94021 2021-06-15 17:20:38Z ucko $
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: Vladimir Soussov
27  *
28  */
29 
30 #include <ncbi_pch.hpp>
31 #include <corelib/rwstream.hpp>
32 #include <util/compress/stream.hpp>
33 #include <util/compress/zlib.hpp>
34 #include <util/compress/bzip2.hpp>
39 
41 
42 ////////////////////////////////////////////////////////////////////////////////
44 {
45  try {
47  m_Blob.Truncate();
48  return true;
49  }
50  catch (CDB_Exception& e) {
51  CDB_UserHandler_Stream myExHandler(&cerr);
52 
53  myExHandler.HandleIt(&e);
54  return false;
55  }
56 }
57 
59  size_t image_limit, TFlags flags)
60 {
61  m_Con= con;
62  m_dMaker= d_maker;
63  m_Limit= (image_limit > 1)? image_limit : (16*1024*1024);
64  m_LogIt= ((flags & fLogBlobs) != 0);
65  m_DelDesc= ((flags & fOwnDescr) != 0);
66  m_DelCon= ((flags & fOwnCon) != 0);
67 }
68 
70  size_t count,
71  size_t* bytes_written)
72 {
73  size_t n= m_Blob.Append(buf, count);
74  if(bytes_written) *bytes_written= n;
75  if(m_Blob.Size() > m_Limit) {
76  // blob is off limit
77  if( !storeBlob() ) {
78  if (bytes_written != NULL) {
79  *bytes_written = 0;
80  }
81  return eRW_Error;
82  }
83  }
84  return eRW_Success;
85 }
86 
88 {
89  if(m_Blob.Size() > 0) {
90  if(!storeBlob()) return eRW_Error;
91  }
92  return eRW_Success;
93 }
94 
96 {
97  Flush();
98  if(m_DelDesc) {
99  m_dMaker->Fini();
100  delete m_dMaker;
101  }
102  if(m_DelCon) {
103  delete m_Con;
104  }
105 }
106 
107 ////////////////////////////////////////////////////////////////////////////////
109  I_BaseCmd* cmd,
110  I_Connection* con)
111 : m_Res(res)
112 , m_Cmd(cmd)
113 , m_Con(con)
114 , m_ItemNum(0)
115 , m_AllDone(false)
116 {
117 }
118 
119 
121 {
122  delete m_Res;
123  delete m_Cmd;
124  delete m_Con;
125 }
126 
127 
128 ERW_Result CBlobReader::Read(void* buf, size_t count, size_t* bytes_read)
129 {
130  size_t n= 0;
131  size_t rn= 0;
133  if(m_AllDone) {
134  r= eRW_Eof;
135  }
136  else try {
137  bool isNull;
138  do {
139  n= m_Res->ReadItem(buf, count, &isNull);
140  if(n >= count) { // we did all we need
141  if(bytes_read) *bytes_read= rn+n;
142  return r;
143  }
144  // need to read the tail from other items
145  rn+= n;
146  count-= n;
147  buf= ((char*)buf)+n;
148  n= 0;
149 
150  if(m_ItemNum == m_Res->CurrentItemNo()) {
151  // we should not be here, but just in case
152  if(!m_Res->SkipItem()) m_ItemNum= -1;
153  else ++m_ItemNum;
154  }
155  else m_ItemNum= m_Res->CurrentItemNo();
156  if((m_ItemNum < 0 ||
157  (unsigned int)m_ItemNum >= m_Res->NofItems()) &&
158  m_Res->Fetch()) {
159  m_ItemNum= 0; // starting next row
160  }
161  }
162  while(m_ItemNum >= 0 &&
163  (unsigned int)m_ItemNum < m_Res->NofItems());
164 
165  m_AllDone= true; // nothing to read any more
166  r = eRW_Eof;
167 
168  } catch (CDB_Exception&) {
169  m_AllDone= true;
170  r = eRW_Error;
171  }
172 
173  if(bytes_read) *bytes_read= n + rn;
174  return r;
175 }
176 
178 {
179  if(count) *count= 0;
181 }
182 
183 
184 ////////////////////////////////////////////////////////////////////////////////
186  const string& server,
187  const string& user,
188  const string& passwd,
189  const string& query)
190 {
191  m_Conn= 0;
192  m_Cmd= 0;
193  m_Res= 0;
194  try {
195  m_Conn= pCntxt->Connect(server, user, passwd, 0, true);
197  m_Cmd->Send();
198  while(m_Cmd->HasMoreResults()) {
199  m_Res=m_Cmd->Result();
200  if(!m_Res) continue;
201  if(m_Res->ResultType() != eDB_RowResult) {
202  delete m_Res;
203  continue;
204  }
205  if(m_Res->Fetch()) {
206  m_IsGood= true;
207  return;
208  }
209  }
210  } catch (CDB_Exception& e) {
211  CDB_UserHandler_Stream myExHandler(&cerr);
212 
213  myExHandler.HandleIt(&e);
214  }
215  m_IsGood= false;
216 }
217 
219 {
220  if(m_IsGood) {
221  unique_ptr<CBlobReader> bReader(new CBlobReader(m_Res));
222  unique_ptr<CRStream> iStream(new CRStream(bReader.get()));
223  unique_ptr<CCompressionStreamProcessor> zProc;
224 
225  switch(cm) {
226  case eZLib:
229  break;
230  case eBZLib:
233  break;
234  default:
235  zProc.reset();
236  }
237 
238  if(zProc.get()) {
239  unique_ptr<CCompressionIStream> zStream(new CCompressionIStream(*iStream, zProc.get()));
240  s << zStream->rdbuf();
241  }
242  else {
243  s << iStream->rdbuf();
244  }
245 
246  m_IsGood = m_Res->Fetch();
247 
248  return true;
249  }
250  return false;
251 }
252 
254 {
255  delete m_Res;
256  delete m_Cmd;
257  delete m_Conn;
258 }
259 
260 ////////////////////////////////////////////////////////////////////////////////
262  const string& server,
263  const string& user,
264  const string& passwd,
265  IBlobDescriptorMaker* d_maker)
266 {
267  m_Conn= 0;
268  try {
269  m_Conn= pCntxt->Connect(server, user, passwd, 0, true);
270  m_dMaker= d_maker;
271  m_IsGood= true;
272  return;
273  } catch (CDB_Exception& e) {
274  CDB_UserHandler_Stream myExHandler(&cerr);
275 
276  myExHandler.HandleIt(&e);
277  }
278  m_IsGood= false;
279 }
280 
281 bool CBlobLoader::Load(istream& s, ECompressMethod cm, size_t image_limit, bool log_it)
282 {
283  if(m_IsGood && m_dMaker->Init(m_Conn)) {
284  unique_ptr<CBlobWriter> bWriter(new CBlobWriter(m_Conn, m_dMaker, image_limit, log_it));
285  unique_ptr<CWStream> oStream(new CWStream(bWriter.get()));
286  unique_ptr<CCompressionStreamProcessor> zProc;
287 
288  switch(cm) {
289  case eZLib:
292  break;
293  case eBZLib:
296  break;
297  default:
298  zProc.reset();
299  }
300 
301  if(zProc.get()) {
302  unique_ptr<CCompressionOStream> zStream(new CCompressionOStream(*oStream, zProc.get()));
303  *zStream << s.rdbuf();
304  }
305  else {
306  *oStream << s.rdbuf();
307  }
308 
309  return m_dMaker->Fini();
310  }
311 
312  return false;
313 
314 }
315 
316 
317 ////////////////////////////////////////////////////////////////////////////////
319  const string& key_col_name,
320  const string& num_col_name,
321  const string blob_column[],
322  bool is_text,
323  const CTempString& table_hint) :
324  CSimpleBlobStore(table_name, key_col_name, num_col_name, blob_column,
325  TFlags(is_text ? fIsText : kDefaults), table_hint)
326 {
327 }
328 
330  const string& key_col_name,
331  const string& num_col_name,
332  const string blob_column[],
333  TFlags flags,
334  const CTempString& table_hint) :
335  m_TableName(table_name), m_KeyColName(key_col_name),
336  m_NumColName(num_col_name), m_TableHint(table_hint),
337  m_RowNum(0), m_Desc(table_name, kEmptyStr, kEmptyStr), m_Flags(flags)
338 {
339  m_Con= 0;
340  m_Cmd= 0;
341  for(m_nofDataCols= 0; !blob_column[m_nofDataCols].empty(); m_nofDataCols++);
342  if(m_nofDataCols) {
343  int i;
344  string init_val((flags & fIsText) != 0 ? "' '" : "0x0");
345  string data_names, data_values, updates;
346  const char* delim = kEmptyCStr;
347  m_DataColName= new string[m_nofDataCols];
348  for(i= 0; i < m_nofDataCols; i++) {
349  m_DataColName[i]= blob_column[i];
350  data_names += delim + blob_column[i];
351  data_values += delim + init_val;
352  updates += ' ' + blob_column[i] + " = " + init_val + ',';
353  delim = ", ";
354  }
355  updates[updates.size() - 1] = '\n';
356 #if 0
357  // Full safety requires the WITH(HOLDLOCK), but Sybase doesn't
358  // support locking hints in this context.
359  m_sCMD = "MERGE " + m_TableName + " WITH(HOLDLOCK) AS t\n";
360  m_sCMD += " USING (VALUES (" + data_values + "))\n";
361  m_sCMD += " AS s (" + data_names + ")\n";
362  m_sCMD += " ON t." + m_KeyColName + " = @key\n";
363  m_sCMD += " AND t." + m_NumColName + " = @n\n";
364  m_sCMD += " WHEN MATCHED THEN UPDATE SET" + updates;
365  if ((flags & fPreallocated) == 0) {
366  m_sCMD += " WHEN NOT MATCHED THEN\n";
367  m_sCMD += " INSERT (" + m_KeyColName + ", " + m_NumColName;
368  m_sCMD += ", " + data_names + ")\n";
369  m_sCMD += " VALUES (@key, @n, " + data_values + ")";
370  }
371 #else
372  m_sCMD = "UPDATE " + m_TableName + " SET " + updates;
373  m_sCMD += " WHERE " + m_KeyColName + " = @key\n";
374  m_sCMD += " AND " + m_NumColName + " = @n\n";
375  if ((flags & fPreallocated) == 0) {
376  m_sCMD += "IF @@ROWCOUNT = 0\n";
377  m_sCMD += " INSERT INTO " + m_TableName + " (" + m_KeyColName;
378  m_sCMD += ", " + m_NumColName + ", " + data_names + ")\n";
379  m_sCMD += " SELECT @key, @n, " + data_values + "\n";
380  m_sCMD += " WHERE NOT EXISTS (SELECT " + m_NumColName;
381  m_sCMD += " FROM " + m_TableName + " WHERE ";
382  m_sCMD += m_KeyColName + " = @key AND " + m_NumColName + " = @n)";
383  }
384 #endif
385  }
386  else m_DataColName= 0;
387 }
388 
390 {
391  delete [] m_DataColName;
392  delete m_Cmd;
393 }
394 
396 {
397  m_Con= con;
398  m_ImageNum= 0;
399  if(m_Key.IsNULL() || (m_nofDataCols < 1)) return false;
400 
401  if ( !m_TableHint.empty() && NStr::StartsWith(m_sCMD, "UPDATE ")) {
402  impl::CConnection* conn_impl
403  = dynamic_cast<impl::CConnection*>(&con->GetExtraFeatures());
404  if (conn_impl != NULL
405  && conn_impl->GetServerType() == CDBConnParams::eMSSqlServer) {
406  string repl = ' ' + m_TableName + " WITH(" + m_TableHint + ") ";
407  NStr::ReplaceInPlace(m_sCMD, ' ' + m_TableName + ' ', repl, 0, 2);
408  }
409  }
410 
412  m_Cmd->SetParam("@key", &m_Key);
413  m_Cmd->BindParam("@n", &m_RowNum);
414  m_Cmd->Send(); // sending command to update/insert row
415  m_Cmd->DumpResults(); // we don't expect any useful results
417  "No rows preallocated for key " + m_Key.AsString()
418  + " in table " + m_TableName,
419  1000030);
420  return true;
421 }
422 
423 /*
424 UPDATE T SET b1 = 0x0, ..., bn = 0x0 WHERE key = @key AND n = @n
425 IF @@ROWCOUNT = 0
426  INSERT INTO T (key, n, b1, ..., bn)
427  SELECT @key, @n, 0x0, ..., 0x0
428  WHERE NOT EXISTS (SELECT n FROM T WHERE key = @key AND n = @n)
429 */
431 {
433  int i = m_ImageNum % m_nofDataCols;
434  if(i == 0) { // prepare new row
435  if(m_RowNum.Value() > 0) {
436  m_Cmd->Send(); // sending command to update/insert row
437  m_Cmd->DumpResults(); // we don't expect any useful results
439  "No more rows preallocated for key "
440  + m_Key.AsString() + " in table " + m_TableName,
441  1000040);
442  }
443 
444  string s = m_KeyColName + "= '";
445  s.append(m_Key.AsString());
446  s += "' AND " + m_NumColName + "=";
447  char buf[32];
448  sprintf(buf, "%ld", (long) m_RowNum.Value());
449  s.append(buf);
450 
452  }
454  m_ImageNum++;
455  return m_Desc;
456 }
457 
459 {
460  if(m_nofDataCols > 0) {
461  delete m_Cmd;
462  string table_and_hint = m_TableName;
463  if ( !m_TableHint.empty() ) {
464  impl::CConnection* conn_impl
465  = dynamic_cast<impl::CConnection*>(&m_Con->GetExtraFeatures());
466  if (conn_impl != NULL
467  && conn_impl->GetServerType() == CDBConnParams::eMSSqlServer) {
468  table_and_hint += " WITH(" + m_TableHint + ')';
469  }
470  }
471 
472  int i= m_ImageNum % m_nofDataCols;
473  string clear_extras;
474  if ((m_Flags & fPreallocated) == 0) {
475  clear_extras = "DELETE " + table_and_hint;
476  } else {
477  clear_extras = "UPDATE " + table_and_hint + " SET";
478  for (int j = 0; j < m_nofDataCols; ++j) {
479  clear_extras += (j ? ", " : " ") + m_DataColName[j] + "=NULL";
480  }
481  }
482  clear_extras += (" WHERE " + m_KeyColName + " = @key AND "
483  + m_NumColName + " > @n");
484  if(i || m_ImageNum == 0) { // we need to clean-up the current row
485  string s= "update " + table_and_hint + " set";
486  for(int j= i; j < m_nofDataCols; j++) {
487  s+= ((i != j)? ", ":" ") + m_DataColName[j] + " = NULL";
488  }
489  s+= " where " + m_KeyColName + " = @key AND " + m_NumColName +
490  " = @n " + clear_extras;
491  m_Cmd= m_Con->LangCmd(s);
492  }
493  else {
494  m_Cmd= m_Con->LangCmd(clear_extras);
495  }
496  m_Cmd->SetParam("@key", &m_Key);
497  m_Cmd->BindParam("@n", &m_RowNum);
498  m_Cmd->Send(); // sending command
499  m_Cmd->DumpResults(); // we don't expect any useful results
500  delete m_Cmd;
501  m_Cmd= 0;
502  return true;
503  }
504  return false;
505 }
506 
507 
508 /***************************************************************************************
509  * CBlobStoreBase - the abstract base interface to deal with reading and writing
510  * BLOB data from a C++ application.
511  */
512 
514  ECompressMethod cm,
515  size_t image_limit,
516  bool log_it)
517  : CBlobStoreBase(table_name, cm, image_limit,
518  CSimpleBlobStore::TFlags(
519  log_it ? CSimpleBlobStore::fLogBlobs
520  : CSimpleBlobStore::kDefaults))
521 {
522 }
523 
525  ECompressMethod cm,
526  size_t image_limit,
527  CSimpleBlobStore::TFlags flags)
528  :m_Table(table_name), m_Cm(cm), m_Limit(image_limit), m_Flags(flags),
529  m_KeyColName(kEmptyStr), m_NumColName(kEmptyStr), m_ReadQuery(kEmptyStr),
530  m_BlobColumn(NULL), m_NofBC(0)
531 {
532 }
533 
535 {
536  delete[] m_BlobColumn;
537 }
538 
539 void
541 {
542  if(m_BlobColumn) {
543  delete[] m_BlobColumn;
544  m_BlobColumn = NULL;
545  }
546 
547  CDB_Connection* con = GetConn();
548 
549  /* derive information regarding the table */
550  string sql = "SELECT * FROM " + m_Table + " WHERE 1=0";
551  unique_ptr<CDB_LangCmd> lcmd(con->LangCmd(sql));
552  if(!lcmd->Send()) {
553  ReleaseConn(con);
554  DATABASE_DRIVER_ERROR("Failed to send a command to the server: " + sql,
555  1000030);
556  }
557 
558  unsigned int n;
559 
560  while(lcmd->HasMoreResults()) {
561  CDB_Result* r= lcmd->Result();
562  if(!r) continue;
563  if(r->ResultType() == eDB_RowResult) {
564  n= r->NofItems();
565  if(n < 2) {
566  delete r;
567  continue;
568  }
569 
570  m_BlobColumn= new string[n];
571 
572  for(unsigned int j= 0; j < n; j++) {
573  switch (r->ItemDataType(j)) {
574  case eDB_VarChar:
575  case eDB_Char:
576  case eDB_LongChar:
577  m_KeyColName= r->ItemName(j);
578  break;
579 
580  case eDB_Int:
581  case eDB_SmallInt:
582  case eDB_TinyInt:
583  case eDB_BigInt:
584  m_NumColName= r->ItemName(j);
585  break;
586 
587  case eDB_Text:
588  case eDB_VarCharMax:
590  m_BlobColumn[m_NofBC++] = r->ItemName(j);
591  break;
592 
593  case eDB_Image:
594  case eDB_VarBinaryMax:
595  m_Flags &= ~CSimpleBlobStore::fIsText;
596  m_BlobColumn[m_NofBC++]= r->ItemName(j);
597  break;
598  default:;
599  }
600  }
602  while(r->Fetch());
603  }
604  delete r;
605  }
606 
607  lcmd.reset();
608  ReleaseConn(con);
609 
610  if((m_NofBC < 1) || m_KeyColName.empty()) {
611  DATABASE_DRIVER_ERROR( "Table "+m_Table+" cannot be used for BlobStore", 1000040 );
612  }
613 }
614 
615 void
616 CBlobStoreBase::SetTableDescr(const string& tableName,
617  const string& keyColName,
618  const string& numColName,
619  const string* blobColNames,
620  unsigned nofBC,
621  bool isText)
622 {
623  if(m_BlobColumn)
624  {
625  delete[] m_BlobColumn;
626  m_BlobColumn = NULL;
627  }
628 
629  m_ReadQuery = "";
630 
631  m_Table = tableName;
632  m_KeyColName = keyColName;
633  m_NumColName = numColName;
634  m_NofBC = nofBC;
635  if (isText) {
637  } else {
638  m_Flags &= ~CSimpleBlobStore::fIsText;
639  }
640 
641  if((m_NofBC < 1) || m_KeyColName.empty())
642  {
643  DATABASE_DRIVER_ERROR( "Table "+m_Table+" cannot be used for BlobStore", 1000040 );
644  }
645 
646  m_BlobColumn = new string[m_NofBC+1];
648 
649  for(unsigned i=0; i<m_NofBC; ++i)
650  m_BlobColumn[i] = blobColNames[i];
651 }
652 
653 void
655 {
656  string s("set TEXTSIZE ");
657  s += NStr::NumericToString(textSize);
658  unique_ptr<CDB_LangCmd> lcmd(pConn->LangCmd(s));
659 
660  if(!lcmd->Send())
661  {
662  DATABASE_DRIVER_ERROR("Failed to send a command to the server: " + s,
663  1000035);
664  }
665 
666  while(lcmd->HasMoreResults())
667  {
668  unique_ptr<CDB_Result> r(lcmd->Result());
669  if(!r.get()) continue;
670  if(r->ResultType() == eDB_StatusResult)
671  {
672  while(r->Fetch())
673  {
674  CDB_Int status;
675  r->GetItem(&status);
676  if(status.Value() != 0)
677  {
678  DATABASE_DRIVER_ERROR( "Wrong status for " + s, 1000036 );
679  }
680  }
681  }
682  else {
683  while(r->Fetch());
684  }
685  }
686 }
687 
689 {
691 
692  m_ReadQuery = "select ";
693  for(unsigned i= 0; i < m_NofBC; i++)
694  {
695  if(i) m_ReadQuery+= ", ";
697  }
698  m_ReadQuery += " from " + m_Table;
699  if ( !table_hint.empty() ) {
700  impl::CConnection* conn_impl
701  = dynamic_cast<impl::CConnection*>(&GetConn()->GetExtraFeatures());
702  if (conn_impl != NULL
703  && conn_impl->GetServerType() == CDBConnParams::eMSSqlServer) {
704  m_ReadQuery += string(" WITH(") + table_hint + ')';
705  }
706  }
707  m_ReadQuery += " where " + m_KeyColName + "=@blob_id";
708  if(!m_NumColName.empty())
709  {
710  m_ReadQuery+= " order by " + m_NumColName + " ASC";
711  }
712 }
713 
714 
715 bool CBlobStoreBase::Exists(const string& blob_id)
716 {
717  CDB_Connection* con = GetConn();
718 
719  /* check the key */
720  string sql = ("IF EXISTS(SELECT * FROM " + m_Table + " WHERE "
721  + m_KeyColName + "='" + blob_id + "') SELECT 1");
722  unique_ptr<CDB_LangCmd> lcmd(con->LangCmd(sql));
723  if(!lcmd->Send()) {
724  lcmd.reset();
725  ReleaseConn(con);
726  DATABASE_DRIVER_ERROR("Failed to send a command to the server: " + sql,
727  1000030);
728  }
729 
730  bool re = false;
731 
732  while(lcmd->HasMoreResults()) {
733  unique_ptr<CDB_Result> r(lcmd->Result());
734  if(!r.get()) continue;
735  if(r->ResultType() == eDB_RowResult) {
736  while(r->Fetch())
737  re= true;
738  }
739  }
740 
741  lcmd.reset();
742  ReleaseConn(con);
743 
744  return re;
745 }
746 
747 void CBlobStoreBase::Delete(const string& blob_id)
748 {
749  CDB_Connection* con = GetConn();
750 
751  /* check the key */
752  string sql = ("DELETE " + m_Table + " WHERE " + m_KeyColName + "='"
753  + blob_id + "'");
754  unique_ptr<CDB_LangCmd> lcmd(con->LangCmd(sql));
755  if(!lcmd->Send()) {
756  lcmd.reset();
757  ReleaseConn(con);
758  DATABASE_DRIVER_ERROR("Failed to send a command to the server: " + sql,
759  1000030);
760  }
761 
762  lcmd->DumpResults();
763 
764  lcmd.reset();
765  ReleaseConn(con);
766 }
767 
768 istream* CBlobStoreBase::OpenForRead(const string& blob_id,
769  const CTempString& table_hint)
770 {
771  CDB_Connection* con = GetConn();
772 
773  if(m_ReadQuery.empty()) {
774  GenReadQuery(table_hint);
775  }
776 
777  unique_ptr<CDB_LangCmd> lcmd(con->LangCmd(m_ReadQuery));
778  CDB_VarChar blob_key(blob_id);
779  lcmd->BindParam("@blob_id", &blob_key);
780 
781  if(!lcmd->Send()) {
782  lcmd.reset();
783  ReleaseConn(con);
784  DATABASE_DRIVER_ERROR("Failed to send a command to the server: "
785  + m_ReadQuery + " (with @blob_id = " + blob_id
786  + ')', 1000030);
787  }
788 
789  while(lcmd->HasMoreResults()) {
790  unique_ptr<CDB_Result> r(lcmd->Result());
791 
792  if(!r.get()) {
793  continue;
794  }
795 
796  if(r->ResultType() != eDB_RowResult) {
797  continue;
798  }
799 
800  if(r->Fetch()) {
801  // creating a stream
802  CBlobReader* bReader = new CBlobReader(r.release(), lcmd.release(), ReleaseConn(0) ? con : 0);
803  unique_ptr<CRStream> iStream(new CRStream(bReader, 0, 0, CRWStreambuf::fOwnReader));
804  unique_ptr<CCompressionStreamProcessor> zProc;
805 
806  switch(m_Cm) {
807  case eZLib:
810  break;
811  case eBZLib:
814  break;
815  default:
816  return iStream.release();
817  }
818 
819  return new CCompressionIStream(*iStream.release(),
820  zProc.release(),
822  }
823  }
824 
825  lcmd.reset();
826  ReleaseConn(con);
827 
828  return 0;
829 }
830 
831 ostream* CBlobStoreBase::OpenForWrite(const string& blob_id,
832  const CTempString& table_hint)
833 {
834  CDB_Connection* con = GetConn();
835 
836  unique_ptr<CSimpleBlobStore> sbs
838  m_BlobColumn, m_Flags, table_hint));
839  sbs->SetKey(blob_id);
840  // CBlobLoader* bload= new CBlobLoader(my_context, server_name, user_name, passwd, &sbs);
841  if(sbs->Init(con)) {
843  if ((m_Flags & CSimpleBlobStore::fLogBlobs) != 0) {
844  bwflags |= CBlobWriter::fLogBlobs;
845  }
846  if (ReleaseConn(0)) {
847  bwflags |= CBlobWriter::fOwnCon;
848  }
849  CBlobWriter* bWriter = new CBlobWriter(con, sbs.release(), m_Limit,
850  bwflags);
851  unique_ptr<CWStream> oStream(new CWStream(bWriter, 0, 0, CRWStreambuf::fOwnWriter));
852  unique_ptr<CCompressionStreamProcessor> zProc;
853 
854  switch(m_Cm) {
855  case eZLib:
858  break;
859  case eBZLib:
862  break;
863  default:
864  return oStream.release();
865  }
866 
867  return new CCompressionOStream(*oStream.release(),
868  zProc.release(),
870  }
871 
872  ReleaseConn(con);
873 
874  return 0;
875 }
876 
877 
878 
879 /***************************************************************************************
880  * CBlobStoreStatic - the simple interface to deal with reading and writing
881  * BLOB data from a C++ application.
882  * It uses connection to DB from an external pool.
883  */
884 
886  const string& table_name,
887  ECompressMethod cm,
888  size_t image_limit,
889  bool log_it)
890  : CBlobStoreStatic(pConn, table_name, cm, image_limit,
891  CSimpleBlobStore::TFlags(
892  log_it ? CSimpleBlobStore::fLogBlobs
893  : CSimpleBlobStore::kDefaults))
894 {
895 }
896 
898  const string& table_name,
899  ECompressMethod cm,
900  size_t image_limit,
901  CSimpleBlobStore::TFlags flags)
902  : CBlobStoreBase(table_name, cm, image_limit, flags),
903  m_pConn(pConn)
904 {
905  ReadTableDescr();
907 }
908 
910  const string& tableName,
911  const string& keyColName,
912  const string& numColName,
913  const string* blobColNames,
914  unsigned nofBC,
915  bool isText,
916  ECompressMethod cm,
917  size_t image_limit,
918  bool log_it)
919  : CBlobStoreStatic(pConn, tableName, keyColName, numColName, blobColNames,
920  nofBC,
921  CSimpleBlobStore::TFlags(
922  (isText ? CSimpleBlobStore::fIsText
923  : CSimpleBlobStore::kDefaults) |
924  (log_it ? CSimpleBlobStore::fLogBlobs
925  : CSimpleBlobStore::kDefaults)),
926  cm, image_limit)
927 {
928 }
929 
931  const string& tableName,
932  const string& keyColName,
933  const string& numColName,
934  const string* blobColNames,
935  unsigned nofBC,
936  CSimpleBlobStore::TFlags flags,
937  ECompressMethod cm,
938  size_t image_limit)
939  :CBlobStoreBase("", cm, image_limit, flags),
940  m_pConn(pConn)
941 {
942  SetTableDescr(tableName, keyColName, numColName, blobColNames, nofBC,
945 }
946 
947 
950 {
951  if(!m_pConn)
952  DATABASE_DRIVER_ERROR( "Bad connection to SQL server", 1000020 );
953  return m_pConn;
954 }
955 
957 {
958 }
959 
960 
961 
962 /***************************************************************************************
963  * CBlobStoreDynamic - the simple interface to deal with reading and writing
964  * BLOB data from a C++ application.
965  * It uses an internal connections pool and ask pool for a connection each time before
966  * connection use.
967  */
968 
969 
971  const string& server,
972  const string& user,
973  const string& passwd,
974  const string& table_name,
975  ECompressMethod cm,
976  size_t image_limit,
977  bool log_it)
978  : CBlobStoreDynamic(pCntxt, server, user, passwd, table_name, cm,
979  image_limit,
980  CSimpleBlobStore::TFlags(
981  log_it ? CSimpleBlobStore::fLogBlobs
982  : CSimpleBlobStore::kDefaults))
983 {
984 }
985 
987  const string& server,
988  const string& user,
989  const string& passwd,
990  const string& table_name,
991  ECompressMethod cm,
992  size_t image_limit,
993  CSimpleBlobStore::TFlags flags)
994  :CBlobStoreBase(table_name, cm, image_limit, flags),
995  m_Cntxt(pCntxt), m_Server(server), m_User(user), m_Passwd(passwd),
996  m_Pool(server+user+table_name)
997 {
998  if(!m_Cntxt)
999  {
1000  DATABASE_DRIVER_ERROR( "Null pointer to driver context", 1000010 );
1001  }
1002  m_Cntxt->SetMaxBlobSize(image_limit>0 ? image_limit : 0x1FFFFE);
1003  ReadTableDescr();
1004 }
1005 
1007 {
1008 }
1009 
1010 
1013 {
1014  if(!m_Cntxt)
1015  {
1016  DATABASE_DRIVER_ERROR( "Null pointer to driver context", 1000010 );
1017  }
1018  CDB_Connection* pConn =
1019  m_Cntxt->Connect(m_Server, m_User, m_Passwd, 0, true, m_Pool);
1020  if(!pConn)
1021  {
1022  DATABASE_DRIVER_ERROR( "Cannot open connection to SQL server", 1000020 );
1023  }
1024  SetTextSizeServerSide(pConn);
1025 
1026  return pConn;
1027 }
1028 
1029 bool
1031 {
1032  if(pConn)
1033  delete pConn;
1034  return true;
1035 }
1036 
USING_NCBI_SCOPE
Definition: blobstore.cpp:40
ECompressMethod
Definition: blobstore.hpp:40
@ eZLib
Definition: blobstore.hpp:42
@ eBZLib
Definition: blobstore.hpp:43
CBZip2Compressor – bzip2 based compressor.
Definition: bzip2.hpp:436
CBZip2Decompressor – bzip2 based decompressor.
Definition: bzip2.hpp:477
CDB_Connection * m_Conn
Definition: blobstore.hpp:180
IBlobDescriptorMaker * m_dMaker
Definition: blobstore.hpp:181
bool Load(istream &s, ECompressMethod cm=eNone, size_t image_limit=0, bool log_it=false)
Definition: blobstore.cpp:281
virtual ERW_Result PendingCount(size_t *count)
Return the number of bytes ready to be read from input device without blocking.
Definition: blobstore.cpp:177
virtual ~CBlobReader()
Definition: blobstore.cpp:120
I_Connection * m_Con
Definition: blobstore.hpp:74
virtual ERW_Result Read(void *buf, size_t count, size_t *bytes_read=0)
Read as many as count bytes into a buffer pointed to by buf argument.
Definition: blobstore.cpp:128
bool m_AllDone
Definition: blobstore.hpp:76
I_BaseCmd * m_Cmd
Definition: blobstore.hpp:73
CDB_Result * m_Res
Definition: blobstore.hpp:72
CDB_LangCmd * m_Cmd
Definition: blobstore.hpp:154
bool Dump(ostream &s, ECompressMethod cm=eNone)
Definition: blobstore.cpp:218
CDB_Result * m_Res
Definition: blobstore.hpp:155
CDB_Connection * m_Conn
Definition: blobstore.hpp:153
void ReadTableDescr()
Definition: blobstore.cpp:540
string m_KeyColName
Definition: blobstore.hpp:331
void Delete(const string &blob_id)
Definition: blobstore.cpp:747
virtual ~CBlobStoreBase()
Definition: blobstore.cpp:534
void SetTextSizeServerSide(CDB_Connection *pConn, size_t textSize=2147483647)
Definition: blobstore.cpp:654
unsigned m_NofBC
Definition: blobstore.hpp:335
ECompressMethod m_Cm
Definition: blobstore.hpp:328
virtual CDB_Connection * GetConn()=0
CBlobStoreBase(const string &table_name, ECompressMethod cm, size_t image_limit, bool log_it)
Definition: blobstore.cpp:513
virtual bool ReleaseConn(CDB_Connection *)=0
void SetTableDescr(const string &tableName, const string &keyColName, const string &numColName, const string *blobColNames, unsigned nofBC, bool isText=false)
Definition: blobstore.cpp:616
ostream * OpenForWrite(const string &blob_id, const CTempString &table_hint=kEmptyStr)
Obtain an output stream for a specific BLOB.
Definition: blobstore.cpp:831
string m_NumColName
Definition: blobstore.hpp:332
istream * OpenForRead(const string &blob_id, const CTempString &table_hint=kEmptyStr)
Obtain an input stream for a specific BLOB.
Definition: blobstore.cpp:768
virtual void GenReadQuery(const CTempString &table_hint)
Definition: blobstore.cpp:688
bool Exists(const string &blob_id)
Definition: blobstore.cpp:715
CSimpleBlobStore::TFlags m_Flags
Definition: blobstore.hpp:330
string * m_BlobColumn
Definition: blobstore.hpp:334
string m_ReadQuery
Definition: blobstore.hpp:333
virtual ~CBlobStoreDynamic()
Definition: blobstore.cpp:1006
virtual bool ReleaseConn(CDB_Connection *)
Definition: blobstore.cpp:1030
I_DriverContext * m_Cntxt
Definition: blobstore.hpp:432
CBlobStoreDynamic(I_DriverContext *pCntxt, const string &server, const string &user, const string &passwd, const string &table_name, ECompressMethod cm=eNone, size_t image_limit=IMAGE_LIMIT_16MB, CSimpleBlobStore::TFlags flags=CSimpleBlobStore::kDefaults)
Definition: blobstore.cpp:986
virtual CDB_Connection * GetConn()
Definition: blobstore.cpp:1012
virtual CDB_Connection * GetConn()
Definition: blobstore.cpp:949
CDB_Connection * m_pConn
Definition: blobstore.hpp:391
virtual ~CBlobStoreStatic()
Definition: blobstore.cpp:956
CBlobStoreStatic(CDB_Connection *pConn, const string &table_name, ECompressMethod cm=eNone, size_t image_limit=IMAGE_LIMIT_16MB, CSimpleBlobStore::TFlags flags=CSimpleBlobStore::kDefaults)
Definition: blobstore.cpp:897
virtual ERW_Result Flush(void)
Flush pending data (if any) down to output device.
Definition: blobstore.cpp:87
virtual ~CBlobWriter()
Definition: blobstore.cpp:95
CDB_Image m_Blob
Definition: blobstore.hpp:127
virtual ERW_Result Write(const void *buf, size_t count, size_t *bytes_written=0)
Write up to count bytes from the buffer pointed to by buf argument onto output device.
Definition: blobstore.cpp:69
IBlobDescriptorMaker * m_dMaker
Definition: blobstore.hpp:128
bool storeBlob(void)
Definition: blobstore.cpp:43
size_t m_Limit
Definition: blobstore.hpp:129
bool m_DelDesc
Definition: blobstore.hpp:132
CDB_Connection * m_Con
Definition: blobstore.hpp:130
CDB_Exception –.
Definition: exception.hpp:118
Note about the "buf_size" parameter for streams in this API.
Definition: rwstream.hpp:122
@ fOwnReader
Own the underlying reader.
Definition: rwstreambuf.hpp:66
@ fOwnWriter
Own the underlying writer.
Definition: rwstreambuf.hpp:67
virtual I_BlobDescriptor & BlobDescriptor(void)
Definition: blobstore.cpp:430
CDB_VarChar m_Key
Definition: blobstore.hpp:241
virtual bool Init(CDB_Connection *con)
Definition: blobstore.cpp:395
virtual bool Fini(void)
Definition: blobstore.cpp:458
virtual ~CSimpleBlobStore()
Definition: blobstore.cpp:389
CDB_Connection * m_Con
Definition: blobstore.hpp:237
CDB_LangCmd * m_Cmd
Definition: blobstore.hpp:238
string * m_DataColName
Definition: blobstore.hpp:236
CDB_BlobDescriptor m_Desc
Definition: blobstore.hpp:243
@ fIsText
(N)TEXT or (N)VARCHAR(MAX)
Definition: blobstore.hpp:201
@ fLogBlobs
Enable server-side logging.
Definition: blobstore.hpp:202
@ fPreallocated
Don't create rows or clean up excess rows.
Definition: blobstore.hpp:203
CSimpleBlobStore(const string &table_name, const string &key_col_name, const string &num_col_name, const string blob_column[], TFlags flags=kDefaults, const CTempString &table_hint=kEmptyStr)
Definition: blobstore.cpp:329
CTempString implements a light-weight string on top of a storage buffer whose lifetime management is ...
Definition: tempstr.hpp:65
Writer-based output stream.
Definition: rwstream.hpp:171
CZipCompressor – zlib based compressor.
Definition: zlib.hpp:658
CZipDecompressor – zlib based decompressor.
Definition: zlib.hpp:712
virtual bool Fini(void)=0
virtual I_BlobDescriptor & BlobDescriptor(void)=0
virtual bool Init(CDB_Connection *con)=0
I_BaseCmd::
Definition: interfaces.hpp:436
I_BlobDescriptor::
Definition: interfaces.hpp:369
I_Connection::
CDBConnParams::EServerType GetServerType(void)
static uch flags
static CS_COMMAND * cmd
Definition: ct_dynamic.c:26
#define false
Definition: bool.h:36
static const char table_name[]
Definition: bcp.c:249
static char sql[1024]
Definition: putdata.c:19
string
Definition: cgiapp.hpp:690
#define NULL
Definition: ncbistd.hpp:225
@ eDelete
Do delete processor object.
Definition: stream.hpp:211
#define DATABASE_DRIVER_ERROR(message, err_code)
Definition: exception.hpp:740
#define CHECK_DRIVER_ERROR(failed, message, err_code)
Definition: exception.hpp:765
virtual bool HandleIt(CDB_Exception *ex)
Handle the exceptions resulting from a native API call, one-by-one.
Definition: exception.cpp:765
CDB_Connection * Connect(const string &srv_name, const string &user_name, const string &passwd, TConnectionMode mode, bool reusable=false, const string &pool_name=kEmptyStr)
Create new connection to specified server (or service) within this context.
Definition: interfaces.cpp:295
virtual bool SetMaxBlobSize(size_t nof_bytes)=0
Set maximal size for BLOB data.
@ eDB_StatusResult
Definition: interfaces.hpp:390
@ eDB_RowResult
Definition: interfaces.hpp:387
virtual EDB_ResType ResultType() const
Get type of the result.
Definition: public.cpp:609
virtual I_ConnectionExtra & GetExtraFeatures(void)
Get interface for extra features that could be implemented in the driver.
Definition: public.cpp:568
virtual CDB_Result * Result()
Get result set.
Definition: public.cpp:777
bool SetParam(const string &name, CDB_Object *value)
Definition: public.hpp:616
virtual int RowCount() const
Get the number of rows affected by the command.
Definition: public.cpp:795
bool BindParam(const string &name, CDB_Object *value)
Definition: public.hpp:609
virtual bool Send()
Send command to the server.
Definition: public.cpp:751
virtual bool SendData(I_BlobDescriptor &desc, CDB_Stream &lob, bool log_it=true)
Shortcut to send text and image to the server without using the "Send-data" command (SendDataCmd)
Definition: public.cpp:395
virtual int CurrentItemNo() const
Return current item number we can retrieve (0,1,...)
Definition: public.cpp:666
virtual void DumpResults()
Dump the results of the command If result processor is installed for this connection,...
Definition: public.cpp:801
virtual bool SkipItem()
Skip result item.
Definition: public.cpp:696
virtual CDB_LangCmd * LangCmd(const string &lang_query)
Make language command.
Definition: public.cpp:355
void SetColumnName(const string &name)
Definition: public.hpp:994
virtual size_t ReadItem(void *buffer, size_t buffer_size, bool *is_null=0)
Read a result item body (for BLOB columns, mostly).
Definition: public.cpp:684
void SetSearchConditions(const string &cond)
Definition: public.hpp:996
virtual unsigned int NofItems() const
Get # of items (columns) in the result.
Definition: public.cpp:623
virtual bool HasMoreResults() const
Definition: public.cpp:783
virtual bool Fetch()
Fetch next row.
Definition: public.cpp:655
virtual size_t Append(const void *buff, size_t nof_bytes)
Definition: types.cpp:2002
Int4 Value() const
Definition: types.hpp:373
virtual void Truncate(size_t nof_bytes=kMax_Int)
Definition: types.cpp:2019
const string & AsString(void) const
Definition: types.hpp:517
virtual size_t Size() const
Definition: types.cpp:2014
bool IsNULL() const
Definition: types.hpp:303
@ eDB_Char
Definition: types.hpp:58
@ eDB_VarChar
Definition: types.hpp:57
@ eDB_TinyInt
Definition: types.hpp:55
@ eDB_LongChar
Definition: types.hpp:70
@ eDB_Image
Definition: types.hpp:67
@ eDB_Int
Definition: types.hpp:53
@ eDB_VarCharMax
Definition: types.hpp:72
@ eDB_BigInt
Definition: types.hpp:56
@ eDB_Text
Definition: types.hpp:66
@ eDB_SmallInt
Definition: types.hpp:54
@ eDB_VarBinaryMax
Definition: types.hpp:73
int32_t Int4
4-byte (32-bit) signed integer
Definition: ncbitype.h:102
ERW_Result
Result codes for I/O operations.
@ eRW_NotImplemented
Action / information is not available.
@ eRW_Eof
End of data, should be considered permanent.
@ eRW_Error
Unrecoverable error, no retry possible.
@ eRW_Success
Everything is okay, I/O completed.
#define kEmptyStr
Definition: ncbistr.hpp:123
bool empty(void) const
Return true if the represented string is empty (i.e., the length is zero)
Definition: tempstr.hpp:334
static bool StartsWith(const CTempString str, const CTempString start, ECase use_case=eCase)
Check if a string starts with a specified prefix value.
Definition: ncbistr.hpp:5406
static enable_if< is_arithmetic< TNumeric >::value||is_convertible< TNumeric, Int8 >::value, string >::type NumericToString(TNumeric value, TNumToStringFlags flags=0, int base=10)
Convert numeric value to string.
Definition: ncbistr.hpp:673
static string & ReplaceInPlace(string &src, const string &search, const string &replace, SIZE_TYPE start_pos=0, SIZE_TYPE max_replace=0, SIZE_TYPE *num_replace=0)
Replace occurrences of a substring within a string.
Definition: ncbistr.cpp:3396
const char *const kEmptyCStr
Empty "C" string (points to a '\0').
Definition: ncbistr.cpp:68
char * buf
int i
yy_size_t n
double r(size_t dimension_, const Int4 *score_, const double *prob_, double theta_)
#define count
Reader-writer based streams.
static string query
ZLib Compression API.
Modified on Fri Sep 20 14:58:30 2024 by modify_doxy.py rev. 669887