LSSTApplications  11.0-24-g0a022a1,14.0+77,15.0,15.0+1
LSSTDataManagementBasePackage
DbStorageImpl.cc
Go to the documentation of this file.
1 // -*- lsst-c++ -*-
2 
3 /*
4  * LSST Data Management System
5  * Copyright 2008, 2009, 2010, 2016 LSST Corporation.
6  *
7  * This product includes software developed by the
8  * LSST Project (http://www.lsst.org/).
9  *
10  * This program is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation, either version 3 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the LSST License Statement and
21  * the GNU General Public License along with this program. If not,
22  * see <http://www.lsstcorp.org/LegalNotices/>.
23  */
24 
25 
40 #ifndef __GNUC__
41 # define __attribute__(x) /*NOTHING*/
42 #endif
43 static char const* SVNid __attribute__((unused)) = "$Id$";
44 
46 #include "boost/regex.hpp"
47 
48 #include <stdlib.h>
49 #include <unistd.h>
50 
51 #include <ctime>
52 #include <iostream>
53 #include <memory>
54 #include <sstream>
55 #include <vector>
56 
57 #include <mysql/mysql.h>
58 
59 #include "lsst/pex/exceptions.h"
62 #include "lsst/daf/base/DateTime.h"
63 #include "lsst/log/Log.h"
64 
65 namespace dafPer = lsst::daf::persistence;
66 namespace dafBase = lsst::daf::base;
68 namespace pexPolicy = lsst::pex::policy;
69 
70 namespace {
71 LOG_LOGGER _log = LOG_GET("daf.persistence.DbStorage");
72 }
73 
74 namespace lsst {
75 namespace daf {
76 namespace persistence {
77 
78 template <size_t N>
80 public:
81  static enum_field_types mysqlType;
82 };
83 
84 template <typename T>
86 public:
87  static enum_field_types mysqlType;
88  static bool isUnsigned;
89 };
90 
91 template<> enum_field_types
93 template<> enum_field_types
94  IntegerTypeTraits<2>::mysqlType = MYSQL_TYPE_SHORT;
95 template<> enum_field_types
97 template<> enum_field_types
98  IntegerTypeTraits<8>::mysqlType = MYSQL_TYPE_LONGLONG;
99 
100 template <typename N> enum_field_types
103 
104 template<> enum_field_types
106 template<> bool BoundVarTraits<bool>::isUnsigned = true;
107 
108 template<> bool BoundVarTraits<char>::isUnsigned = false;
111 template<> bool BoundVarTraits<short>::isUnsigned = false;
113 template<> bool BoundVarTraits<int>::isUnsigned = false;
115 template<> bool BoundVarTraits<long>::isUnsigned = false;
119 
120 template<> enum_field_types
122 template<> bool BoundVarTraits<float>::isUnsigned = false;
123 
124 template<> enum_field_types
126 template<> bool BoundVarTraits<double>::isUnsigned = false;
127 
128 template<> enum_field_types
131 
132 template<> enum_field_types
133  BoundVarTraits<std::string>::mysqlType = MYSQL_TYPE_VAR_STRING;
135 
136 }}} // namespace lsst::daf::persistence
137 
139 // BoundVar
141 
145  lsst::daf::base::Citizen(typeid(*this)), _data(0) {
146 }
147 
150 dafPer::BoundVar::BoundVar(void* location) :
151  lsst::daf::base::Citizen(typeid(*this)), _data(location) {
152 }
153 
157  lsst::daf::base::Citizen(typeid(*this)),
159  _length(src._length), _data(src._data) {
160 }
161 
163 // CONSTRUCTORS
165 
169  lsst::daf::base::Citizen(typeid(*this)), _db(0) {
170 }
171 
176  if (_db) {
177  mysql_close(_db);
178  _db = 0;
179  }
180 }
181 
186 }
187 
189 // SESSIONS
191 
197  // Set the timezone for any DATE/TIME/TIMESTAMP fields.
198  setenv("TZ", "UTC", 1);
199 
200  DbStorageLocation dbloc(location);
201 
202  if (_db) {
203  mysql_close(_db);
204  }
205  _db = mysql_init(0);
206 
207  unsigned int port = strtoul(dbloc.getPort().c_str(), 0, 10);
208  if (mysql_real_connect(_db,
209  dbloc.getHostname().c_str(),
210  dbloc.getUsername().c_str(),
211  dbloc.getPassword().c_str(),
212  dbloc.getDbName().c_str(),
213  port, 0, 0) == 0) {
214  error("Unable to connect to MySQL database: " + _location);
215  }
216 }
217 
222  startSession(location.locString());
223  _readonly = false;
224 }
225 
230  startSession(location.locString());
231  _readonly = true;
232 }
233 
237  if (_db == 0) error("Database session not initialized "
238  "in DbStorage::startTransaction()", false);
239  if (mysql_autocommit(_db, false)) error("Unable to turn off autocommit");
240 }
241 
245  if (_db == 0) error("Database session not initialized "
246  "in DbStorage::endTransaction()", false);
247  if (mysql_commit(_db)) error("Unable to commit transaction");
248  if (mysql_autocommit(_db, true)) error("Unable to turn on autocommit");
249 }
250 
252 // UTILITIES
254 
258  if (_db == 0) {
259  error("No DB connection for query: " + query, false);
260  }
261  LOGLS_DEBUG(_log, "Query: " << query);
262  if (mysql_query(_db, query.c_str()) != 0) {
263  error("Unable to execute query: " + query);
264  }
265 }
266 
270  std::string::size_type pos = name.find('.');
271  if (pos == std::string::npos) return '`' + name + '`';
272  return '`' + std::string(name, 0, pos) + "`.`" +
273  std::string(name, pos + 1) + '`';
274 }
275 
277  error(text + " - * " + mysql_stmt_error(_statement), false);
278 }
279 
280 void dafPer::DbStorageImpl::error(std::string const& text, bool mysqlCause) {
281  if (mysqlCause) {
282  throw LSST_EXCEPT(lsst::pex::exceptions::RuntimeError, text + " - * " + mysql_error(_db));
283  }
284  else {
286  }
287 }
288 
290  boost::shared_array<char> mem(new char[size]);
292  return mem.get();
293 }
294 
296 // TABLE OPERATIONS
298 
305  std::string const& templateName,
306  bool mayAlreadyExist) {
307  std::string query = "CREATE TABLE ";
308  if (mayAlreadyExist) query += "IF NOT EXISTS ";
309  query += quote(tableName) + " LIKE " + quote(templateName);
310  executeQuery(query);
311 }
312 
317  executeQuery("DROP TABLE " + quote(tableName));
318 }
319 
324  executeQuery("TRUNCATE TABLE " + quote(tableName));
325 }
326 
332  executeQuery(sqlStatement);
333 }
334 
336 // PERSISTENCE
338 
343  if (_readonly) {
344  error("Attempt to insert into read-only database", false);
345  }
346  _insertTable = tableName;
347  _inputVars.clear();
348 }
349 
354 template <typename T>
356  T const& value) {
357  BoundVarMap::iterator bv = _inputVars.find(columnName);
358  size_t size = sizeof(T);
359  if (bv == _inputVars.end()) {
360  bv = _inputVars.insert(
361  BoundVarMap::value_type(columnName,
362  BoundVar(allocateMemory(size)))).first;
363  }
364  else if (bv->second._length != size) {
365  bv->second._data = allocateMemory(size);
366  }
367  bv->second._type = BoundVarTraits<T>::mysqlType;
368  bv->second._isNull = false;
369  bv->second._isUnsigned = BoundVarTraits<T>::isUnsigned;
370  bv->second._length = size;
371  memcpy(bv->second._data, &value, size);
372 }
373 
374 template <>
376  std::string const& value) {
377  BoundVarMap::iterator bv = _inputVars.find(columnName);
378  size_t size = value.length();
379  if (bv == _inputVars.end()) {
380  bv = _inputVars.insert(
381  BoundVarMap::value_type(columnName,
382  BoundVar(allocateMemory(size)))).first;
383  }
384  else if (bv->second._length != size) {
385  bv->second._data = allocateMemory(size);
386  }
387  bv->second._type = BoundVarTraits<std::string>::mysqlType;
388  bv->second._isNull = false;
389  bv->second._isUnsigned = BoundVarTraits<std::string>::isUnsigned;
390  bv->second._length = size;
391  memcpy(bv->second._data, value.data(), size);
392 }
393 
394 template <>
396  dafBase::DateTime const& value) {
397  BoundVarMap::iterator bv = _inputVars.find(columnName);
398  size_t size = sizeof(MYSQL_TIME);
399  if (bv == _inputVars.end()) {
400  bv = _inputVars.insert(
401  BoundVarMap::value_type(columnName,
402  BoundVar(allocateMemory(size)))).first;
403  }
404  else if (bv->second._length != size) {
405  bv->second._data = allocateMemory(size);
406  }
408  bv->second._isNull = false;
409  bv->second._isUnsigned = BoundVarTraits<dafBase::DateTime>::isUnsigned;
410  bv->second._length = size;
411  struct tm v = value.gmtime(dafBase::DateTime::UTC);
412  MYSQL_TIME* t = reinterpret_cast<MYSQL_TIME*>(bv->second._data);
413  t->year = v.tm_year + 1900;
414  t->month = v.tm_mon + 1;
415  t->day = v.tm_mday;
416  t->hour = v.tm_hour;
417  t->minute = v.tm_min;
418  t->second = v.tm_sec;
419  t->neg = false;
420  t->second_part =
421  static_cast<unsigned long>((value.nsecs() % 1000000000LL) / 1000);
422 }
423 
428  BoundVarMap::iterator bv = _inputVars.find(columnName);
429  if (bv == _inputVars.end()) {
430  bv = _inputVars.insert(
431  BoundVarMap::value_type(columnName,
432  BoundVar(allocateMemory(1)))).first;
433  }
434  bv->second._isNull = true;
435  bv->second._length = 1;
436 }
437 
442  if (_readonly) {
443  error("Attempt to insert into read-only database", false);
444  }
445  if (_insertTable.empty()) error("Insert table not initialized in DbStorage::insertRow()", false);
446  if (_inputVars.empty()) error("No values to insert", false);
447 
448  std::string query = "INSERT INTO " + quote(_insertTable) + " (";
449 
450  std::unique_ptr<MYSQL_BIND[]> binder(new MYSQL_BIND[_inputVars.size()]);
451  memset(binder.get(), 0, _inputVars.size() * sizeof(MYSQL_BIND));
452 
453  int i = 0;
454  for (BoundVarMap::iterator it = _inputVars.begin();
455  it != _inputVars.end(); ++it) {
456  if (it != _inputVars.begin()) {
457  query += ", ";
458  }
459  query += quote(it->first);
460 
461  // Bind variables
462  MYSQL_BIND& bind(binder[i]);
463  BoundVar& bv(it->second);
464  if (bv._isNull) {
465  bind.buffer_type = MYSQL_TYPE_NULL;
466  }
467  else {
468  bind.buffer_type = bv._type;
469  bind.buffer = bv._data;
470  bind.buffer_length = bv._length;
471  bind.length = &(bv._length);
472  bind.is_null = 0;
473  bind.is_unsigned = bv._isUnsigned;
474  bind.error = 0;
475  }
476  ++i;
477  }
478  query += ") VALUES (";
479  for (size_t i = 0; i < _inputVars.size(); ++i) {
480  if (i != 0) {
481  query += ", ";
482  }
483  query += "?";
484  }
485  query += ")";
486 
487  // Execute statement
488  // Guard statement with mysql_stmt_close()
489  _statement = mysql_stmt_init(_db);
490  if (_statement == 0) {
491  error("Unable to initialize statement: " + query);
492  }
493  if (mysql_stmt_prepare(_statement, query.c_str(), query.length()) != 0) {
494  stError("Unable to prepare statement: " + query);
495  }
496  if (mysql_stmt_bind_param(_statement, binder.get())) {
497  stError("Unable to bind variables in: " + query);
498  }
499  if (mysql_stmt_execute(_statement) != 0) {
500  stError("Unable to execute statement: " + query);
501  }
502  mysql_stmt_close(_statement);
503  _statement = 0;
504 }
505 
507 // RETRIEVAL
509 
515  bool isExpr) {
516  if (_db == 0) error("Database session not initialized in DbStorage::setTableForQuery()", false);
518  _queryTables.push_back(isExpr ? tableName : quote(tableName));
519  _inputVars.clear();
520  _outputVars.clear();
521  _outColumns.clear();
523  _groupBy.clear();
524  _orderBy.clear();
525  _statement = 0;
526 }
527 
532  std::vector<std::string> const& tableNameList) {
533  if (_db == 0) error("Database session not initialized in DbStorage::setTableListForQuery()", false);
534  for (std::vector<std::string>::const_iterator it = tableNameList.begin();
535  it != tableNameList.end(); ++it) {
537  }
538  _inputVars.clear();
539  _outputVars.clear();
540  _outColumns.clear();
542  _groupBy.clear();
543  _orderBy.clear();
544  _statement = 0;
545 }
546 
555  bool isExpr) {
556  std::string col = isExpr ? columnName : quote(columnName);
557  _outColumns.push_back(col);
558 }
559 
568 template <typename T>
570  T* location, bool isExpr) {
571  std::string col = isExpr ? columnName : quote(columnName);
572  _outColumns.push_back(col);
573  size_t size = sizeof(T);
575  BoundVarMap::value_type(col, BoundVar(location)));
576  if (!pair.second) {
577  error("Duplicate column name requested: " + columnName, false);
578  }
579  BoundVar& bv = pair.first->second;
581  bv._isNull = false;
583  bv._length = size;
584 }
585 
586 template <>
588  std::string* location, bool isExpr) {
589  std::string col = isExpr ? columnName : quote(columnName);
590  _outColumns.push_back(col);
591  size_t size = 4096;
593  BoundVarMap::value_type(
594  col, BoundVar(allocateMemory(size + sizeof(std::string*)))));
595  if (!pair.second) {
596  error("Duplicate column name requested: " + columnName, false);
597  }
598  BoundVar& bv = pair.first->second;
599  *reinterpret_cast<std::string**>(bv._data) = location;
601  bv._isNull = false;
603  bv._length = size;
604 }
605 
606 template <>
608  dafBase::DateTime* location,
609  bool isExpr) {
610  std::string col = isExpr ? columnName : quote(columnName);
611  _outColumns.push_back(col);
612  size_t size = sizeof(MYSQL_TIME);
614  BoundVarMap::value_type(
615  col, BoundVar(allocateMemory(size + sizeof(dafBase::DateTime*)))));
616  if (!pair.second) {
617  error("Duplicate column name requested: " + columnName, false);
618  }
619  BoundVar& bv = pair.first->second;
620  *reinterpret_cast<dafBase::DateTime**>(bv._data) = location;
622  bv._isNull = false;
624  bv._length = size;
625 }
626 
632 template <typename T>
633 void dafPer::DbStorageImpl::condParam(std::string const& paramName, T const& value) {
634  setColumn<T>(paramName, value);
635 }
636 
642  if (!_orderBy.empty()) {
643  _orderBy += ", ";
644  }
645  _orderBy += expression;
646 }
647 
652  if (!_groupBy.empty()) {
653  _groupBy += ", ";
654  }
655  _groupBy += expression;
656 }
657 
664  _whereClause = whereClause;
665 }
666 
670  if (_outColumns.empty()) error("No output columns for query", false);
671 
672  // SELECT outVars FROM queryTables WHERE whereClause GROUP BY groupBy
673  // ORDER BY orderBy
674 
675  // SELECT clause
676  std::string query = "SELECT ";
678  it != _outColumns.end(); ++it) {
679  if (it != _outColumns.begin()) {
680  query += ", ";
681  }
682  query += *it;
683  }
684 
685  // FROM clause
686  query += " FROM ";
688  it != _queryTables.end(); ++it) {
689  if (it != _queryTables.begin()) {
690  query += ", ";
691  }
692  query += *it;
693  }
694 
695  // WHERE clause
696  std::vector<std::string> whereBindings;
697  if (!_whereClause.empty()) {
698  boost::regex re(":([A-Za-z_]+)");
699  std::string result;
701  boost::regex_iterator<std::string::iterator> m;
702  for (boost::regex_iterator<std::string::iterator> i(
704  i != boost::regex_iterator<std::string::iterator>(); ++i) {
705  m = i;
706  std::copy(m->prefix().first, m->prefix().second, out);
707  *out++ = '?';
708  assert(m->size() == 2);
709  whereBindings.push_back(m->str(1));
710  }
711  if (m != boost::regex_iterator<std::string::iterator>()) {
712  std::copy(m->suffix().first, m->suffix().second, out);
713  }
714  else {
716  }
717  query += " WHERE " + result;
718  }
719 
720  // GROUP BY clause
721  if (!_groupBy.empty()) query += " GROUP BY " + _groupBy;
722 
723  // ORDER BY clause
724  if (!_orderBy.empty()) query += " ORDER BY " + _orderBy;
725 
726 
727  // Create bindings for input WHERE clause variables, if any
728 
730  new MYSQL_BIND[whereBindings.size()]);
731  memset(inBinder.get(), 0, whereBindings.size() * sizeof(MYSQL_BIND));
732  for (size_t i = 0; i < whereBindings.size(); ++i) {
733  MYSQL_BIND& bind(inBinder[i]);
734  BoundVarMap::iterator it = _inputVars.find(whereBindings[i]);
735  if (it == _inputVars.end()) {
736  error("Unbound variable in WHERE clause: " + whereBindings[i],
737  false);
738  }
739  BoundVar& bv = it->second;
740  bind.buffer_type = bv._type;
741  bind.buffer = bv._data;
742  bind.buffer_length = bv._length;
743  bind.is_null = 0;
744  bind.is_unsigned = bv._isUnsigned;
745  bind.error = 0;
746  }
747 
748 
749  // Initialize and prepare statement
750 
751  _statement = mysql_stmt_init(_db);
752  if (!_statement) {
753  error("Unable to initialize prepared statement");
754  }
755 
756  if (mysql_stmt_prepare(_statement, query.c_str(), query.length()) != 0) {
757  stError("Unable to prepare statement: " + query);
758  }
759 
760 
761  // Check number of input parameters and bind them
762  unsigned int params = mysql_stmt_param_count(_statement);
763  if (_whereClause.empty()) {
764  if (params != 0) {
765  error("Unbound WHERE clause parameters: " + query, false);
766  }
767  }
768  else {
769  if (params != whereBindings.size()) {
770  error("Mismatch in number of WHERE clause parameters: " + query,
771  false);
772  }
773  if (mysql_stmt_bind_param(_statement, inBinder.get())) {
774  stError("Unable to bind WHERE parameters: " + query);
775  }
776  }
777 
778  // Check number of result columns
779  MYSQL_RES* queryMetadata = mysql_stmt_result_metadata(_statement);
780  if (!queryMetadata) {
781  stError("No query metadata: " + query);
782  }
783  _numResultFields = mysql_num_fields(queryMetadata);
784  if (static_cast<unsigned int>(_numResultFields) != _outColumns.size()) {
785  error("Mismatch in number of SELECT items: " + query, false);
786  }
787 
788 
789  // Execute query
790 
791  if (mysql_stmt_execute(_statement) != 0) {
792  stError("MySQL query failed: " + query);
793  }
794 
795 
796  // Create bindings for output variables
797 
798  _resultFields = mysql_fetch_fields(queryMetadata);
799 
800  std::unique_ptr<MYSQL_BIND[]> outBinder(new MYSQL_BIND[_numResultFields]);
801  memset(outBinder.get(), 0, _numResultFields * sizeof(MYSQL_BIND));
802  _fieldLengths.reset(new unsigned long[_numResultFields]);
803  _fieldNulls.reset(new my_bool[_numResultFields]);
804 
805  for (int i = 0; i < _numResultFields; ++i) {
806  MYSQL_BIND& bind(outBinder[i]);
807  if (_outputVars.empty()) {
808  bind.buffer_type = MYSQL_TYPE_STRING;
809  bind.buffer = 0;
810  bind.buffer_length = 0;
811  bind.length = &(_fieldLengths[i]);
812  bind.is_null = &(_fieldNulls[i]);
813  bind.is_unsigned = (_resultFields[i].flags & UNSIGNED_FLAG) != 0;
814  bind.error = 0;
815  }
816  else {
817  BoundVarMap::iterator it = _outputVars.find(_outColumns[i]);
818  if (it == _outputVars.end()) {
819  error("Unbound variable in SELECT clause: " + _outColumns[i],
820  false);
821  }
822  BoundVar& bv = it->second;
823 
824  bind.buffer_type = bv._type;
826  bind.buffer = reinterpret_cast<char*>(bv._data) +
827  sizeof(std::string*);
828  }
830  bind.buffer = reinterpret_cast<char*>(bv._data) +
831  sizeof(std::string*);
832  }
833  else {
834  bind.buffer = bv._data;
835  }
836  bind.buffer_length = bv._length;
837  bind.length = &(_fieldLengths[i]);
838  bind.is_null = &(_fieldNulls[i]);
839  bind.is_unsigned = bv._isUnsigned;
840  bind.error = 0;
841  }
842  }
843  if (mysql_stmt_bind_result(_statement, outBinder.get())) {
844  stError("Unable to bind results: " + query);
845  }
846 }
847 
852  if (_statement == 0) {
853  error("Statement not initialized in DbStorage::next()", false);
854  }
855  int ret = mysql_stmt_fetch(_statement);
856  if (ret == 0) {
857  // Fix up strings and DateTimes
858  if (!_outputVars.empty()) {
859  for (size_t i = 0; i < _outColumns.size(); ++i) {
860  BoundVarMap::iterator bvit = _outputVars.find(_outColumns[i]);
861  if (bvit == _outputVars.end()) {
862  error("Unbound variable in SELECT clause: " +
863  _outColumns[i], false);
864  }
865  BoundVar& bv = bvit->second;
867  **reinterpret_cast<std::string**>(bv._data) =
868  std::string(reinterpret_cast<char*>(bv._data) +
869  sizeof(std::string*), _fieldLengths[i]);
870  }
871  else if (bv._type ==
873  char* cp = reinterpret_cast<char*>(bv._data) +
874  sizeof(dafBase::DateTime*);
875  MYSQL_TIME* t = reinterpret_cast<MYSQL_TIME*>(cp);
876  **reinterpret_cast<dafBase::DateTime**>(bv._data) =
877  dafBase::DateTime(t->year, t->month, t->day,
878  t->hour, t->minute, t->second,
880  }
881  }
882  }
883  return true;
884  }
885  if (ret == MYSQL_NO_DATA) return false;
886  if (ret == MYSQL_DATA_TRUNCATED && _outputVars.empty()) return true;
887  stError("Error fetching next row");
888  return false;
889 }
890 
895 template <typename T>
897  if (pos > _numResultFields) {
899  os << "Nonexistent column: " << pos;
900  error(os.str(), false);
901  }
902  MYSQL_BIND bind;
903  memset(&bind, 0, sizeof(MYSQL_BIND));
904  static T t;
905  bind.buffer_type = BoundVarTraits<T>::mysqlType;
906  bind.is_unsigned = BoundVarTraits<T>::isUnsigned;
907  bind.buffer = &t;
908  bind.buffer_length = sizeof(T);
909  bind.length = &(_fieldLengths[pos]);
910  bind.is_null = &(_fieldNulls[pos]);
911  if (mysql_stmt_fetch_column(_statement, &bind, pos, 0)) {
913  os << "Error fetching column: " << pos;
914  error(os.str(), false);
915  }
916  return t;
917 }
918 
919 template <>
921  if (pos > _numResultFields) {
923  os << "Nonexistent column: " << pos;
924  error(os.str(), false);
925  }
926  MYSQL_BIND bind;
927  memset(&bind, 0, sizeof(MYSQL_BIND));
928  if (_resultFields[pos].type == MYSQL_TYPE_BIT) {
929  error("Invalid type for string retrieval", false);
930  }
931  std::unique_ptr<char[]> t(new char[_fieldLengths[pos]]);
932  bind.buffer_type = BoundVarTraits<std::string>::mysqlType;
933  bind.is_unsigned = BoundVarTraits<std::string>::isUnsigned;
934  bind.buffer = t.get();
935  bind.buffer_length = _fieldLengths[pos];
936  bind.length = &(_fieldLengths[pos]);
937  bind.is_null = &(_fieldNulls[pos]);
938  if (mysql_stmt_fetch_column(_statement, &bind, pos, 0)) {
940  os << "Error fetching string column: " << pos;
941  stError(os.str());
942  }
943  static std::string s;
944  s = std::string(t.get(), _fieldLengths[pos]);
945  return s;
946 }
947 
948 template <>
950  if (pos > _numResultFields) {
952  os << "Nonexistent column: " << pos;
953  error(os.str(), false);
954  }
955  MYSQL_BIND bind;
956  memset(&bind, 0, sizeof(MYSQL_BIND));
957  if (_resultFields[pos].type != MYSQL_TYPE_TIME &&
958  _resultFields[pos].type != MYSQL_TYPE_DATE &&
959  _resultFields[pos].type != MYSQL_TYPE_DATETIME &&
960  _resultFields[pos].type != MYSQL_TYPE_TIMESTAMP) {
961  error("Invalid type for DateTime retrieval", false);
962  }
963  static MYSQL_TIME t;
966  bind.buffer = &t;
967  bind.buffer_length = sizeof(MYSQL_TIME);
968  bind.length = &(_fieldLengths[pos]);
969  bind.is_null = &(_fieldNulls[pos]);
970  if (mysql_stmt_fetch_column(_statement, &bind, pos, 0)) {
972  os << "Error fetching DateTime column: " << pos;
973  stError(os.str());
974  }
975  static dafBase::DateTime v;
976  v = dafBase::DateTime(t.year, t.month, t.day, t.hour, t.minute, t.second,
978  return v;
979 }
980 
986  if (pos > _numResultFields) {
988  os << "Nonexistent column: " << pos;
989  error(os.str(), false);
990  }
991  return _fieldNulls[pos];
992 }
993 
997  mysql_stmt_close(_statement);
998  _statement = 0;
999 }
1000 
1001 
1002 // Explicit template member function instantiations
1003 // Ignore for doxygen processing.
1005 template void dafPer::DbStorageImpl::setColumn<>(std::string const& columnName, char const& value);
1006 template void dafPer::DbStorageImpl::setColumn<>(std::string const& columnName, short const& value);
1007 template void dafPer::DbStorageImpl::setColumn<>(std::string const& columnName, int const& value);
1008 template void dafPer::DbStorageImpl::setColumn<>(std::string const& columnName, long const& value);
1009 template void dafPer::DbStorageImpl::setColumn<>(std::string const& columnName, long long const& value);
1010 template void dafPer::DbStorageImpl::setColumn<>(std::string const& columnName, float const& value);
1011 template void dafPer::DbStorageImpl::setColumn<>(std::string const& columnName, double const& value);
1012 template void dafPer::DbStorageImpl::setColumn<>(std::string const& columnName, std::string const& value);
1013 template void dafPer::DbStorageImpl::setColumn<>(std::string const& columnName, bool const& value);
1014 template void dafPer::DbStorageImpl::setColumn<>(std::string const& columnName, dafBase::DateTime const& value);
1015 
1016 template void dafPer::DbStorageImpl::outParam<>(std::string const& columnName, char* location, bool isExpr);
1017 template void dafPer::DbStorageImpl::outParam<>(std::string const& columnName, short* location, bool isExpr);
1018 template void dafPer::DbStorageImpl::outParam<>(std::string const& columnName, int* location, bool isExpr);
1019 template void dafPer::DbStorageImpl::outParam<>(std::string const& columnName, long* location, bool isExpr);
1020 template void dafPer::DbStorageImpl::outParam<>(std::string const& columnName, long long* location, bool isExpr);
1021 template void dafPer::DbStorageImpl::outParam<>(std::string const& columnName, float* location, bool isExpr);
1022 template void dafPer::DbStorageImpl::outParam<>(std::string const& columnName, double* location, bool isExpr);
1023 template void dafPer::DbStorageImpl::outParam<>(std::string const& columnName, std::string* location, bool isExpr);
1024 template void dafPer::DbStorageImpl::outParam<>(std::string const& columnName, bool* location, bool isExpr);
1025 template void dafPer::DbStorageImpl::outParam<>(std::string const& columnName, dafBase::DateTime* location, bool isExpr);
1026 
1027 template void dafPer::DbStorageImpl::condParam<>(std::string const& paramName, char const& value);
1028 template void dafPer::DbStorageImpl::condParam<>(std::string const& paramName, short const& value);
1029 template void dafPer::DbStorageImpl::condParam<>(std::string const& paramName, int const& value);
1030 template void dafPer::DbStorageImpl::condParam<>(std::string const& paramName, long const& value);
1031 template void dafPer::DbStorageImpl::condParam<>(std::string const& paramName, long long const& value);
1032 template void dafPer::DbStorageImpl::condParam<>(std::string const& paramName, float const& value);
1033 template void dafPer::DbStorageImpl::condParam<>(std::string const& paramName, double const& value);
1034 template void dafPer::DbStorageImpl::condParam<>(std::string const& paramName, std::string const& value);
1035 template void dafPer::DbStorageImpl::condParam<>(std::string const& paramName, bool const& value);
1036 template void dafPer::DbStorageImpl::condParam<>(std::string const& paramName, dafBase::DateTime const& value);
1037 
1038 template char const& dafPer::DbStorageImpl::getColumnByPos<>(int pos);
1039 template short const& dafPer::DbStorageImpl::getColumnByPos<>(int pos);
1040 template int const& dafPer::DbStorageImpl::getColumnByPos<>(int pos);
1041 template long const& dafPer::DbStorageImpl::getColumnByPos<>(int pos);
1042 template long long const& dafPer::DbStorageImpl::getColumnByPos<>(int pos);
1043 template float const& dafPer::DbStorageImpl::getColumnByPos<>(int pos);
1044 template double const& dafPer::DbStorageImpl::getColumnByPos<>(int pos);
1045 template std::string const& dafPer::DbStorageImpl::getColumnByPos<>(int pos);
1046 template bool const& dafPer::DbStorageImpl::getColumnByPos<>(int pos);
1047 template dafBase::DateTime const& dafPer::DbStorageImpl::getColumnByPos<>(int pos);
std::shared_ptr< Policy > Ptr
Definition: Policy.h:172
solver_t * s
std::vector< boost::shared_array< char > > _bindingMemory
Memory for bound variables.
T empty(T... args)
T copy(T... args)
virtual void setQueryWhere(std::string const &whereClause)
Set the condition for the WHERE clause of the query.
T const & getColumnByPos(int pos)
Get the value of a column of the query result row by position.
DbStorageImpl(void)
Default constructor.
#define LOG_LOGGER
Definition: Log.h:712
Class for handling dates/times, including MJD, UTC, and TAI.
Definition: DateTime.h:62
virtual std::string const & getDbName(void) const
Accessor for database name.
table::Key< std::string > name
Definition: ApCorrMap.cc:71
virtual void setTableForInsert(std::string const &tableName)
Set the table to insert rows into.
void outParam(std::string const &columnName, T *location, bool isExpr)
Request a column in the query output and bind a destination location.
void setColumn(std::string const &columnName, T const &value)
Set the value to insert in a given column.
std::vector< std::string > _queryTables
Names of tables to select from.
struct tm gmtime(Timescale scale) const
Get date as a tm struct, with truncated fractional seconds.
Definition: DateTime.cc:482
virtual void executeSql(std::string const &sqlStatement)
Execute an arbitrary SQL statement.
Class for logical location of a persisted Persistable instance.
virtual void endTransaction(void)
End a transaction.
virtual void setPolicy(pexPolicy::Policy::Ptr policy)
Allow a Policy to be used to configure the DbStorage.
std::string const & locString(void) const
Accessor.
boost::shared_array< unsigned long > _fieldLengths
Space for lengths of result fields.
virtual void finishQuery(void)
Indicate that query processing is finished.
virtual void outColumn(std::string const &columnName, bool isExpr)
Request a column in the query output.
virtual std::string const & getHostname(void) const
Accessor for database hostname.
int _numResultFields
Number of result fields.
T end(T... args)
virtual void groupBy(std::string const &expression)
Request that the query output be grouped by an expression.
virtual void startSession(std::string const &location)
Start a database session.
virtual std::string const & getPassword(void) const
Accessor for password.
BoundVar(void)
Default constructor.
STL class.
virtual ~DbStorageImpl(void)
Destructor.
LSST DM logging module built on log4cxx.
Include files required for standard LSST Exception handling.
T push_back(T... args)
Location of a persisted Persistable instance in a database.
MYSQL * _db
MySQL database connection pointer.
virtual void startTransaction(void)
Start a transaction.
T data(T... args)
#define LOGLS_DEBUG(logger, message)
Log a debug-level message using an iostream-based interface.
Definition: Log.h:617
A base class for image defects.
Definition: cameraGeom.dox:3
virtual std::string const & getUsername(void) const
Accessor for username.
long long nsecs(Timescale scale=TAI) const
Get date as nanoseconds since the unix epoch.
Definition: DateTime.cc:460
void error(std::string const &text, bool mysqlCaused=true)
virtual std::string const & getPort(void) const
Accessor for database port number.
bool columnIsNull(int pos)
Determine if the value of a column is NULL.
virtual void setRetrieveLocation(LogicalLocation const &location)
Set the database location to retrieve from.
T str(T... args)
MYSQL_STMT * _statement
Prepared query statement.
T clear(T... args)
void condParam(std::string const &paramName, T const &value)
Bind a value to a WHERE condition parameter.
boost::shared_array< my_bool > _fieldNulls
Space for null flags of result fields.
virtual void query(void)
Execute the query.
Interface for DateTime class.
virtual void setTableListForQuery(std::vector< std::string > const &tableNameList)
Set a list of tables to query (multiple-table queries).
MYSQL_FIELD * _resultFields
Query result field metadata.
virtual void orderBy(std::string const &expression)
Request that the query output be sorted by an expression.
T get(T... args)
T insert(T... args)
virtual void truncateTable(std::string const &tableName)
Truncate a table.
T find(T... args)
std::string _location
Database location string saved for use by raw MySQL interface.
T length(T... args)
#define LSST_EXCEPT(type,...)
Create an exception with a given type and message and optionally other arguments (dependent on the ty...
Definition: Exception.h:46
virtual void setColumnToNull(std::string const &columnName)
Set a given column to NULL.
STL class.
Citizen(const std::type_info &)
Definition: Citizen.cc:174
T begin(T... args)
T c_str(T... args)
std::string quote(std::string const &name)
Quote a name in ANSI-standard fashion.
virtual void createTableFromTemplate(std::string const &tableName, std::string const &templateName, bool mayAlreadyExist)
Create a new table from an existing template table.
virtual bool next(void)
Move to the next (first) row of the query result.
void stError(std::string const &text)
BoundVarMap _inputVars
Input variable bindings.
Interface for DbStorageImpl class.
BoundVarMap _outputVars
Output variable bindings.
virtual void setPersistLocation(LogicalLocation const &location)
Set the database location to persist to.
void executeQuery(std::string const &query)
Execute a query string.
virtual void dropTable(std::string const &tableName)
Drop a table.
#define LOG_GET(logger)
Returns a Log object associated with logger.
Definition: Log.h:83
Interface for LogicalLocation class.
bool _readonly
Remember if we are supposed to be read-only.
std::vector< std::string > _outColumns
#define __attribute__(x)
int col
Definition: CR.cc:156
virtual void insertRow(void)
Insert the row.
std::string _insertTable
Name of table into which to insert.
Interface for DbStorageLocation class.
virtual void setTableForQuery(std::string const &tableName, bool isExpr)
Set the table to query (single-table queries only).