LSSTApplications  10.0+286,10.0+36,10.0+46,10.0-2-g4f67435,10.1+152,10.1+37,11.0,11.0+1,11.0-1-g47edd16,11.0-1-g60db491,11.0-1-g7418c06,11.0-2-g04d2804,11.0-2-g68503cd,11.0-2-g818369d,11.0-2-gb8b8ce7
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 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 #include <ctime>
48 #include <iostream>
49 #include <sstream>
50 #include <stdlib.h>
51 #include <unistd.h>
52 #include <vector>
53 
54 #include <mysql/mysql.h>
55 
56 #include "lsst/pex/exceptions.h"
57 #include "lsst/pex/logging/Trace.h"
60 #include "lsst/daf/base/DateTime.h"
61 
62 namespace dafPer = lsst::daf::persistence;
63 namespace dafBase = lsst::daf::base;
64 namespace pexExcept = lsst::pex::exceptions;
65 namespace pexPolicy = lsst::pex::policy;
66 
67 namespace lsst {
68 namespace daf {
69 namespace persistence {
70 
71 template <size_t N>
73 public:
74  static enum_field_types mysqlType;
75 };
76 
77 template <typename T>
79 public:
80  static enum_field_types mysqlType;
81  static bool isUnsigned;
82 };
83 
84 template<> enum_field_types
86 template<> enum_field_types
87  IntegerTypeTraits<2>::mysqlType = MYSQL_TYPE_SHORT;
88 template<> enum_field_types
90 template<> enum_field_types
91  IntegerTypeTraits<8>::mysqlType = MYSQL_TYPE_LONGLONG;
92 
93 template <typename N> enum_field_types
96 
97 template<> enum_field_types
99 template<> bool BoundVarTraits<bool>::isUnsigned = true;
100 
101 template<> bool BoundVarTraits<char>::isUnsigned = false;
104 template<> bool BoundVarTraits<short>::isUnsigned = false;
106 template<> bool BoundVarTraits<int>::isUnsigned = false;
108 template<> bool BoundVarTraits<long>::isUnsigned = false;
112 
113 template<> enum_field_types
115 template<> bool BoundVarTraits<float>::isUnsigned = false;
116 
117 template<> enum_field_types
119 template<> bool BoundVarTraits<double>::isUnsigned = false;
120 
121 template<> enum_field_types
124 
125 template<> enum_field_types
126  BoundVarTraits<std::string>::mysqlType = MYSQL_TYPE_VAR_STRING;
128 
129 }}} // namespace lsst::daf::persistence
130 
132 // BoundVar
134 
138  lsst::daf::base::Citizen(typeid(*this)), _data(0) {
139 }
140 
143 dafPer::BoundVar::BoundVar(void* location) :
144  lsst::daf::base::Citizen(typeid(*this)), _data(location) {
145 }
146 
150  lsst::daf::base::Citizen(typeid(*this)),
151  _type(src._type), _isNull(src._isNull), _isUnsigned(src._isUnsigned),
152  _length(src._length), _data(src._data) {
153 }
154 
156 // CONSTRUCTORS
158 
162  lsst::daf::base::Citizen(typeid(*this)), _db(0) {
163 }
164 
169  if (_db) {
170  mysql_close(_db);
171  _db = 0;
172  }
173 }
174 
179 }
180 
182 // SESSIONS
184 
189 void dafPer::DbStorageImpl::startSession(std::string const& location) {
190  // Set the timezone for any DATE/TIME/TIMESTAMP fields.
191  setenv("TZ", "UTC", 1);
192 
193  DbStorageLocation dbloc(location);
194 
195  if (_db) {
196  mysql_close(_db);
197  }
198  _db = mysql_init(0);
199 
200  unsigned int port = strtoul(dbloc.getPort().c_str(), 0, 10);
201  if (mysql_real_connect(_db,
202  dbloc.getHostname().c_str(),
203  dbloc.getUsername().c_str(),
204  dbloc.getPassword().c_str(),
205  dbloc.getDbName().c_str(),
206  port, 0, 0) == 0) {
207  error("Unable to connect to MySQL database: " + _location);
208  }
209 }
210 
215  startSession(location.locString());
216  _readonly = false;
217 }
218 
223  startSession(location.locString());
224  _readonly = true;
225 }
226 
230  if (_db == 0) error("Database session not initialized "
231  "in DbStorage::startTransaction()", false);
232  if (mysql_autocommit(_db, false)) error("Unable to turn off autocommit");
233 }
234 
238  if (_db == 0) error("Database session not initialized "
239  "in DbStorage::endTransaction()", false);
240  if (mysql_commit(_db)) error("Unable to commit transaction");
241  if (mysql_autocommit(_db, true)) error("Unable to turn on autocommit");
242 }
243 
245 // UTILITIES
247 
250 void dafPer::DbStorageImpl::executeQuery(std::string const& query) {
251  if (_db == 0) {
252  error("No DB connection for query: " + query, false);
253  }
254  lsst::pex::logging::TTrace<5>("daf.persistence.DbStorage",
255  "Query: " + query);
256  if (mysql_query(_db, query.c_str()) != 0) {
257  error("Unable to execute query: " + query);
258  }
259 }
260 
263 std::string dafPer::DbStorageImpl::quote(std::string const& name) {
264  std::string::size_type pos = name.find('.');
265  if (pos == std::string::npos) return '`' + name + '`';
266  return '`' + std::string(name, 0, pos) + "`.`" +
267  std::string(name, pos + 1) + '`';
268 }
269 
270 void dafPer::DbStorageImpl::stError(std::string const& text) {
271  error(text + " - * " + mysql_stmt_error(_statement), false);
272 }
273 
274 void dafPer::DbStorageImpl::error(std::string const& text, bool mysqlCause) {
275  if (mysqlCause) {
276  throw LSST_EXCEPT(lsst::pex::exceptions::RuntimeError, text + " - * " + mysql_error(_db));
277  }
278  else {
279  throw LSST_EXCEPT(lsst::pex::exceptions::RuntimeError, text);
280  }
281 }
282 
284  boost::shared_array<char> mem(new char[size]);
285  _bindingMemory.push_back(mem);
286  return mem.get();
287 }
288 
290 // TABLE OPERATIONS
292 
298 void dafPer::DbStorageImpl::createTableFromTemplate(std::string const& tableName,
299  std::string const& templateName,
300  bool mayAlreadyExist) {
301  std::string query = "CREATE TABLE ";
302  if (mayAlreadyExist) query += "IF NOT EXISTS ";
303  query += quote(tableName) + " LIKE " + quote(templateName);
304  executeQuery(query);
305 }
306 
310 void dafPer::DbStorageImpl::dropTable(std::string const& tableName) {
311  executeQuery("DROP TABLE " + quote(tableName));
312 }
313 
317 void dafPer::DbStorageImpl::truncateTable(std::string const& tableName) {
318  executeQuery("TRUNCATE TABLE " + quote(tableName));
319 }
320 
325 void dafPer::DbStorageImpl::executeSql(std::string const& sqlStatement) {
326  executeQuery(sqlStatement);
327 }
328 
330 // PERSISTENCE
332 
336 void dafPer::DbStorageImpl::setTableForInsert(std::string const& tableName) {
337  if (_readonly) {
338  error("Attempt to insert into read-only database", false);
339  }
340  _insertTable = tableName;
341  _inputVars.clear();
342 }
343 
348 template <typename T>
349 void dafPer::DbStorageImpl::setColumn(std::string const& columnName,
350  T const& value) {
351  BoundVarMap::iterator bv = _inputVars.find(columnName);
352  size_t size = sizeof(T);
353  if (bv == _inputVars.end()) {
354  bv = _inputVars.insert(
355  BoundVarMap::value_type(columnName,
356  BoundVar(allocateMemory(size)))).first;
357  }
358  else if (bv->second._length != size) {
359  bv->second._data = allocateMemory(size);
360  }
361  bv->second._type = BoundVarTraits<T>::mysqlType;
362  bv->second._isNull = false;
363  bv->second._isUnsigned = BoundVarTraits<T>::isUnsigned;
364  bv->second._length = size;
365  memcpy(bv->second._data, &value, size);
366 }
367 
368 template <>
369 void dafPer::DbStorageImpl::setColumn(std::string const& columnName,
370  std::string const& value) {
371  BoundVarMap::iterator bv = _inputVars.find(columnName);
372  size_t size = value.length();
373  if (bv == _inputVars.end()) {
374  bv = _inputVars.insert(
375  BoundVarMap::value_type(columnName,
376  BoundVar(allocateMemory(size)))).first;
377  }
378  else if (bv->second._length != size) {
379  bv->second._data = allocateMemory(size);
380  }
381  bv->second._type = BoundVarTraits<std::string>::mysqlType;
382  bv->second._isNull = false;
383  bv->second._isUnsigned = BoundVarTraits<std::string>::isUnsigned;
384  bv->second._length = size;
385  memcpy(bv->second._data, value.data(), size);
386 }
387 
388 template <>
389 void dafPer::DbStorageImpl::setColumn(std::string const& columnName,
390  dafBase::DateTime const& value) {
391  BoundVarMap::iterator bv = _inputVars.find(columnName);
392  size_t size = sizeof(MYSQL_TIME);
393  if (bv == _inputVars.end()) {
394  bv = _inputVars.insert(
395  BoundVarMap::value_type(columnName,
396  BoundVar(allocateMemory(size)))).first;
397  }
398  else if (bv->second._length != size) {
399  bv->second._data = allocateMemory(size);
400  }
402  bv->second._isNull = false;
403  bv->second._isUnsigned = BoundVarTraits<dafBase::DateTime>::isUnsigned;
404  bv->second._length = size;
405  struct tm v = value.gmtime();
406  MYSQL_TIME* t = reinterpret_cast<MYSQL_TIME*>(bv->second._data);
407  t->year = v.tm_year + 1900;
408  t->month = v.tm_mon + 1;
409  t->day = v.tm_mday;
410  t->hour = v.tm_hour;
411  t->minute = v.tm_min;
412  t->second = v.tm_sec;
413  t->neg = false;
414  t->second_part =
415  static_cast<unsigned long>((value.nsecs() % 1000000000LL) / 1000);
416 }
417 
421 void dafPer::DbStorageImpl::setColumnToNull(std::string const& columnName) {
422  BoundVarMap::iterator bv = _inputVars.find(columnName);
423  if (bv == _inputVars.end()) {
424  bv = _inputVars.insert(
425  BoundVarMap::value_type(columnName,
426  BoundVar(allocateMemory(1)))).first;
427  }
428  bv->second._isNull = true;
429  bv->second._length = 1;
430 }
431 
436  if (_readonly) {
437  error("Attempt to insert into read-only database", false);
438  }
439  if (_insertTable.empty()) error("Insert table not initialized in DbStorage::insertRow()", false);
440  if (_inputVars.empty()) error("No values to insert", false);
441 
442  std::string query = "INSERT INTO " + quote(_insertTable) + " (";
443 
444  boost::scoped_array<MYSQL_BIND> binder(new MYSQL_BIND[_inputVars.size()]);
445  memset(binder.get(), 0, _inputVars.size() * sizeof(MYSQL_BIND));
446 
447  int i = 0;
448  for (BoundVarMap::iterator it = _inputVars.begin();
449  it != _inputVars.end(); ++it) {
450  if (it != _inputVars.begin()) {
451  query += ", ";
452  }
453  query += quote(it->first);
454 
455  // Bind variables
456  MYSQL_BIND& bind(binder[i]);
457  BoundVar& bv(it->second);
458  if (bv._isNull) {
459  bind.buffer_type = MYSQL_TYPE_NULL;
460  }
461  else {
462  bind.buffer_type = bv._type;
463  bind.buffer = bv._data;
464  bind.buffer_length = bv._length;
465  bind.length = &(bv._length);
466  bind.is_null = 0;
467  bind.is_unsigned = bv._isUnsigned;
468  bind.error = 0;
469  }
470  ++i;
471  }
472  query += ") VALUES (";
473  for (size_t i = 0; i < _inputVars.size(); ++i) {
474  if (i != 0) {
475  query += ", ";
476  }
477  query += "?";
478  }
479  query += ")";
480 
481  // Execute statement
482  // Guard statement with mysql_stmt_close()
483  _statement = mysql_stmt_init(_db);
484  if (_statement == 0) {
485  error("Unable to initialize statement: " + query);
486  }
487  if (mysql_stmt_prepare(_statement, query.c_str(), query.length()) != 0) {
488  stError("Unable to prepare statement: " + query);
489  }
490  if (mysql_stmt_bind_param(_statement, binder.get())) {
491  stError("Unable to bind variables in: " + query);
492  }
493  if (mysql_stmt_execute(_statement) != 0) {
494  stError("Unable to execute statement: " + query);
495  }
496  mysql_stmt_close(_statement);
497  _statement = 0;
498 }
499 
501 // RETRIEVAL
503 
508 void dafPer::DbStorageImpl::setTableForQuery(std::string const& tableName,
509  bool isExpr) {
510  if (_db == 0) error("Database session not initialized in DbStorage::setTableForQuery()", false);
511  _queryTables.clear();
512  _queryTables.push_back(isExpr ? tableName : quote(tableName));
513  _inputVars.clear();
514  _outputVars.clear();
515  _outColumns.clear();
516  _whereClause.clear();
517  _groupBy.clear();
518  _orderBy.clear();
519  _statement = 0;
520 }
521 
526  std::vector<std::string> const& tableNameList) {
527  if (_db == 0) error("Database session not initialized in DbStorage::setTableListForQuery()", false);
528  for (std::vector<std::string>::const_iterator it = tableNameList.begin();
529  it != tableNameList.end(); ++it) {
530  _queryTables.push_back(quote(*it));
531  }
532  _inputVars.clear();
533  _outputVars.clear();
534  _outColumns.clear();
535  _whereClause.clear();
536  _groupBy.clear();
537  _orderBy.clear();
538  _statement = 0;
539 }
540 
548 void dafPer::DbStorageImpl::outColumn(std::string const& columnName,
549  bool isExpr) {
550  std::string col = isExpr ? columnName : quote(columnName);
551  _outColumns.push_back(col);
552 }
553 
562 template <typename T>
563 void dafPer::DbStorageImpl::outParam(std::string const& columnName,
564  T* location, bool isExpr) {
565  std::string col = isExpr ? columnName : quote(columnName);
566  _outColumns.push_back(col);
567  size_t size = sizeof(T);
568  std::pair<BoundVarMap::iterator, bool> pair = _outputVars.insert(
569  BoundVarMap::value_type(col, BoundVar(location)));
570  if (!pair.second) {
571  error("Duplicate column name requested: " + columnName, false);
572  }
573  BoundVar& bv = pair.first->second;
575  bv._isNull = false;
577  bv._length = size;
578 }
579 
580 template <>
581 void dafPer::DbStorageImpl::outParam(std::string const& columnName,
582  std::string* location, bool isExpr) {
583  std::string col = isExpr ? columnName : quote(columnName);
584  _outColumns.push_back(col);
585  size_t size = 4096;
586  std::pair<BoundVarMap::iterator, bool> pair = _outputVars.insert(
587  BoundVarMap::value_type(
588  col, BoundVar(allocateMemory(size + sizeof(std::string*)))));
589  if (!pair.second) {
590  error("Duplicate column name requested: " + columnName, false);
591  }
592  BoundVar& bv = pair.first->second;
593  *reinterpret_cast<std::string**>(bv._data) = location;
595  bv._isNull = false;
597  bv._length = size;
598 }
599 
600 template <>
601 void dafPer::DbStorageImpl::outParam(std::string const& columnName,
602  dafBase::DateTime* location,
603  bool isExpr) {
604  std::string col = isExpr ? columnName : quote(columnName);
605  _outColumns.push_back(col);
606  size_t size = sizeof(MYSQL_TIME);
607  std::pair<BoundVarMap::iterator, bool> pair = _outputVars.insert(
608  BoundVarMap::value_type(
609  col, BoundVar(allocateMemory(size + sizeof(dafBase::DateTime*)))));
610  if (!pair.second) {
611  error("Duplicate column name requested: " + columnName, false);
612  }
613  BoundVar& bv = pair.first->second;
614  *reinterpret_cast<dafBase::DateTime**>(bv._data) = location;
616  bv._isNull = false;
618  bv._length = size;
619 }
620 
626 template <typename T>
627 void dafPer::DbStorageImpl::condParam(std::string const& paramName, T const& value) {
628  setColumn<T>(paramName, value);
629 }
630 
635 void dafPer::DbStorageImpl::orderBy(std::string const& expression) {
636  if (!_orderBy.empty()) {
637  _orderBy += ", ";
638  }
639  _orderBy += expression;
640 }
641 
645 void dafPer::DbStorageImpl::groupBy(std::string const& expression) {
646  if (!_groupBy.empty()) {
647  _groupBy += ", ";
648  }
649  _groupBy += expression;
650 }
651 
657 void dafPer::DbStorageImpl::setQueryWhere(std::string const& whereClause) {
658  _whereClause = whereClause;
659 }
660 
664  if (_outColumns.empty()) error("No output columns for query", false);
665 
666  // SELECT outVars FROM queryTables WHERE whereClause GROUP BY groupBy
667  // ORDER BY orderBy
668 
669  // SELECT clause
670  std::string query = "SELECT ";
671  for (std::vector<std::string>::const_iterator it = _outColumns.begin();
672  it != _outColumns.end(); ++it) {
673  if (it != _outColumns.begin()) {
674  query += ", ";
675  }
676  query += *it;
677  }
678 
679  // FROM clause
680  query += " FROM ";
681  for (std::vector<std::string>::const_iterator it = _queryTables.begin();
682  it != _queryTables.end(); ++it) {
683  if (it != _queryTables.begin()) {
684  query += ", ";
685  }
686  query += *it;
687  }
688 
689  // WHERE clause
690  std::vector<std::string> whereBindings;
691  if (!_whereClause.empty()) {
692  boost::regex re(":([A-Za-z_]+)");
693  std::string result;
694  std::back_insert_iterator<std::string> out(result);
695  boost::regex_iterator<std::string::iterator> m;
696  for (boost::regex_iterator<std::string::iterator> i(
697  _whereClause.begin(), _whereClause.end(), re);
698  i != boost::regex_iterator<std::string::iterator>(); ++i) {
699  m = i;
700  std::copy(m->prefix().first, m->prefix().second, out);
701  *out++ = '?';
702  assert(m->size() == 2);
703  whereBindings.push_back(m->str(1));
704  }
705  if (m != boost::regex_iterator<std::string::iterator>()) {
706  std::copy(m->suffix().first, m->suffix().second, out);
707  }
708  else {
709  std::copy(_whereClause.begin(), _whereClause.end(), out);
710  }
711  query += " WHERE " + result;
712  }
713 
714  // GROUP BY clause
715  if (!_groupBy.empty()) query += " GROUP BY " + _groupBy;
716 
717  // ORDER BY clause
718  if (!_orderBy.empty()) query += " ORDER BY " + _orderBy;
719 
720 
721  // Create bindings for input WHERE clause variables, if any
722 
723  boost::scoped_array<MYSQL_BIND> inBinder(
724  new MYSQL_BIND[whereBindings.size()]);
725  memset(inBinder.get(), 0, whereBindings.size() * sizeof(MYSQL_BIND));
726  for (size_t i = 0; i < whereBindings.size(); ++i) {
727  MYSQL_BIND& bind(inBinder[i]);
728  BoundVarMap::iterator it = _inputVars.find(whereBindings[i]);
729  if (it == _inputVars.end()) {
730  error("Unbound variable in WHERE clause: " + whereBindings[i],
731  false);
732  }
733  BoundVar& bv = it->second;
734  bind.buffer_type = bv._type;
735  bind.buffer = bv._data;
736  bind.buffer_length = bv._length;
737  bind.is_null = 0;
738  bind.is_unsigned = bv._isUnsigned;
739  bind.error = 0;
740  }
741 
742 
743  // Initialize and prepare statement
744 
745  _statement = mysql_stmt_init(_db);
746  if (!_statement) {
747  error("Unable to initialize prepared statement");
748  }
749 
750  if (mysql_stmt_prepare(_statement, query.c_str(), query.length()) != 0) {
751  stError("Unable to prepare statement: " + query);
752  }
753 
754 
755  // Check number of input parameters and bind them
756  unsigned int params = mysql_stmt_param_count(_statement);
757  if (_whereClause.empty()) {
758  if (params != 0) {
759  error("Unbound WHERE clause parameters: " + query, false);
760  }
761  }
762  else {
763  if (params != whereBindings.size()) {
764  error("Mismatch in number of WHERE clause parameters: " + query,
765  false);
766  }
767  if (mysql_stmt_bind_param(_statement, inBinder.get())) {
768  stError("Unable to bind WHERE parameters: " + query);
769  }
770  }
771 
772  // Check number of result columns
773  MYSQL_RES* queryMetadata = mysql_stmt_result_metadata(_statement);
774  if (!queryMetadata) {
775  stError("No query metadata: " + query);
776  }
777  _numResultFields = mysql_num_fields(queryMetadata);
778  if (static_cast<unsigned int>(_numResultFields) != _outColumns.size()) {
779  error("Mismatch in number of SELECT items: " + query, false);
780  }
781 
782 
783  // Execute query
784 
785  if (mysql_stmt_execute(_statement) != 0) {
786  stError("MySQL query failed: " + query);
787  }
788 
789 
790  // Create bindings for output variables
791 
792  _resultFields = mysql_fetch_fields(queryMetadata);
793 
794  boost::scoped_array<MYSQL_BIND> outBinder(new MYSQL_BIND[_numResultFields]);
795  memset(outBinder.get(), 0, _numResultFields * sizeof(MYSQL_BIND));
796  _fieldLengths.reset(new unsigned long[_numResultFields]);
797  _fieldNulls.reset(new my_bool[_numResultFields]);
798 
799  for (int i = 0; i < _numResultFields; ++i) {
800  MYSQL_BIND& bind(outBinder[i]);
801  if (_outputVars.empty()) {
802  bind.buffer_type = MYSQL_TYPE_STRING;
803  bind.buffer = 0;
804  bind.buffer_length = 0;
805  bind.length = &(_fieldLengths[i]);
806  bind.is_null = &(_fieldNulls[i]);
807  bind.is_unsigned = (_resultFields[i].flags & UNSIGNED_FLAG) != 0;
808  bind.error = 0;
809  }
810  else {
811  BoundVarMap::iterator it = _outputVars.find(_outColumns[i]);
812  if (it == _outputVars.end()) {
813  error("Unbound variable in SELECT clause: " + _outColumns[i],
814  false);
815  }
816  BoundVar& bv = it->second;
817 
818  bind.buffer_type = bv._type;
820  bind.buffer = reinterpret_cast<char*>(bv._data) +
821  sizeof(std::string*);
822  }
824  bind.buffer = reinterpret_cast<char*>(bv._data) +
825  sizeof(std::string*);
826  }
827  else {
828  bind.buffer = bv._data;
829  }
830  bind.buffer_length = bv._length;
831  bind.length = &(_fieldLengths[i]);
832  bind.is_null = &(_fieldNulls[i]);
833  bind.is_unsigned = bv._isUnsigned;
834  bind.error = 0;
835  }
836  }
837  if (mysql_stmt_bind_result(_statement, outBinder.get())) {
838  stError("Unable to bind results: " + query);
839  }
840 }
841 
846  if (_statement == 0) {
847  error("Statement not initialized in DbStorage::next()", false);
848  }
849  int ret = mysql_stmt_fetch(_statement);
850  if (ret == 0) {
851  // Fix up strings and DateTimes
852  if (!_outputVars.empty()) {
853  for (size_t i = 0; i < _outColumns.size(); ++i) {
854  BoundVarMap::iterator bvit = _outputVars.find(_outColumns[i]);
855  if (bvit == _outputVars.end()) {
856  error("Unbound variable in SELECT clause: " +
857  _outColumns[i], false);
858  }
859  BoundVar& bv = bvit->second;
861  **reinterpret_cast<std::string**>(bv._data) =
862  std::string(reinterpret_cast<char*>(bv._data) +
863  sizeof(std::string*), _fieldLengths[i]);
864  }
865  else if (bv._type ==
867  char* cp = reinterpret_cast<char*>(bv._data) +
868  sizeof(dafBase::DateTime*);
869  MYSQL_TIME* t = reinterpret_cast<MYSQL_TIME*>(cp);
870  **reinterpret_cast<dafBase::DateTime**>(bv._data) =
871  dafBase::DateTime(t->year, t->month, t->day,
872  t->hour, t->minute, t->second,
874  }
875  }
876  }
877  return true;
878  }
879  if (ret == MYSQL_NO_DATA) return false;
880  if (ret == MYSQL_DATA_TRUNCATED && _outputVars.empty()) return true;
881  stError("Error fetching next row");
882  return false;
883 }
884 
889 template <typename T>
891  if (pos > _numResultFields) {
892  std::ostringstream os;
893  os << "Nonexistent column: " << pos;
894  error(os.str(), false);
895  }
896  MYSQL_BIND bind;
897  memset(&bind, 0, sizeof(MYSQL_BIND));
898  static T t;
899  bind.buffer_type = BoundVarTraits<T>::mysqlType;
900  bind.is_unsigned = BoundVarTraits<T>::isUnsigned;
901  bind.buffer = &t;
902  bind.buffer_length = sizeof(T);
903  bind.length = &(_fieldLengths[pos]);
904  bind.is_null = &(_fieldNulls[pos]);
905  if (mysql_stmt_fetch_column(_statement, &bind, pos, 0)) {
906  std::ostringstream os;
907  os << "Error fetching column: " << pos;
908  error(os.str(), false);
909  }
910  return t;
911 }
912 
913 template <>
914 std::string const& dafPer::DbStorageImpl::getColumnByPos(int pos) {
915  if (pos > _numResultFields) {
916  std::ostringstream os;
917  os << "Nonexistent column: " << pos;
918  error(os.str(), false);
919  }
920  MYSQL_BIND bind;
921  memset(&bind, 0, sizeof(MYSQL_BIND));
922  if (_resultFields[pos].type == MYSQL_TYPE_BIT) {
923  error("Invalid type for string retrieval", false);
924  }
925  boost::scoped_array<char> t(new char[_fieldLengths[pos]]);
926  bind.buffer_type = BoundVarTraits<std::string>::mysqlType;
927  bind.is_unsigned = BoundVarTraits<std::string>::isUnsigned;
928  bind.buffer = t.get();
929  bind.buffer_length = _fieldLengths[pos];
930  bind.length = &(_fieldLengths[pos]);
931  bind.is_null = &(_fieldNulls[pos]);
932  if (mysql_stmt_fetch_column(_statement, &bind, pos, 0)) {
933  std::ostringstream os;
934  os << "Error fetching string column: " << pos;
935  stError(os.str());
936  }
937  static std::string s;
938  s = std::string(t.get(), _fieldLengths[pos]);
939  return s;
940 }
941 
942 template <>
944  if (pos > _numResultFields) {
945  std::ostringstream os;
946  os << "Nonexistent column: " << pos;
947  error(os.str(), false);
948  }
949  MYSQL_BIND bind;
950  memset(&bind, 0, sizeof(MYSQL_BIND));
951  if (_resultFields[pos].type != MYSQL_TYPE_TIME &&
952  _resultFields[pos].type != MYSQL_TYPE_DATE &&
953  _resultFields[pos].type != MYSQL_TYPE_DATETIME &&
954  _resultFields[pos].type != MYSQL_TYPE_TIMESTAMP) {
955  error("Invalid type for DateTime retrieval", false);
956  }
957  static MYSQL_TIME t;
960  bind.buffer = &t;
961  bind.buffer_length = sizeof(MYSQL_TIME);
962  bind.length = &(_fieldLengths[pos]);
963  bind.is_null = &(_fieldNulls[pos]);
964  if (mysql_stmt_fetch_column(_statement, &bind, pos, 0)) {
965  std::ostringstream os;
966  os << "Error fetching DateTime column: " << pos;
967  stError(os.str());
968  }
969  static dafBase::DateTime v;
970  v = dafBase::DateTime(t.year, t.month, t.day, t.hour, t.minute, t.second,
972  return v;
973 }
974 
980  if (pos > _numResultFields) {
981  std::ostringstream os;
982  os << "Nonexistent column: " << pos;
983  error(os.str(), false);
984  }
985  return _fieldNulls[pos];
986 }
987 
991  mysql_stmt_close(_statement);
992  _statement = 0;
993 }
994 
995 
996 // Explicit template member function instantiations
997 // Ignore for doxygen processing.
999 template void dafPer::DbStorageImpl::setColumn<>(std::string const& columnName, char const& value);
1000 template void dafPer::DbStorageImpl::setColumn<>(std::string const& columnName, short const& value);
1001 template void dafPer::DbStorageImpl::setColumn<>(std::string const& columnName, int const& value);
1002 template void dafPer::DbStorageImpl::setColumn<>(std::string const& columnName, long const& value);
1003 template void dafPer::DbStorageImpl::setColumn<>(std::string const& columnName, long long const& value);
1004 template void dafPer::DbStorageImpl::setColumn<>(std::string const& columnName, float const& value);
1005 template void dafPer::DbStorageImpl::setColumn<>(std::string const& columnName, double const& value);
1006 template void dafPer::DbStorageImpl::setColumn<>(std::string const& columnName, std::string const& value);
1007 template void dafPer::DbStorageImpl::setColumn<>(std::string const& columnName, bool const& value);
1008 template void dafPer::DbStorageImpl::setColumn<>(std::string const& columnName, dafBase::DateTime const& value);
1009 
1010 template void dafPer::DbStorageImpl::outParam<>(std::string const& columnName, char* location, bool isExpr);
1011 template void dafPer::DbStorageImpl::outParam<>(std::string const& columnName, short* location, bool isExpr);
1012 template void dafPer::DbStorageImpl::outParam<>(std::string const& columnName, int* location, bool isExpr);
1013 template void dafPer::DbStorageImpl::outParam<>(std::string const& columnName, long* location, bool isExpr);
1014 template void dafPer::DbStorageImpl::outParam<>(std::string const& columnName, long long* location, bool isExpr);
1015 template void dafPer::DbStorageImpl::outParam<>(std::string const& columnName, float* location, bool isExpr);
1016 template void dafPer::DbStorageImpl::outParam<>(std::string const& columnName, double* location, bool isExpr);
1017 template void dafPer::DbStorageImpl::outParam<>(std::string const& columnName, std::string* location, bool isExpr);
1018 template void dafPer::DbStorageImpl::outParam<>(std::string const& columnName, bool* location, bool isExpr);
1019 template void dafPer::DbStorageImpl::outParam<>(std::string const& columnName, dafBase::DateTime* location, bool isExpr);
1020 
1021 template void dafPer::DbStorageImpl::condParam<>(std::string const& paramName, char const& value);
1022 template void dafPer::DbStorageImpl::condParam<>(std::string const& paramName, short const& value);
1023 template void dafPer::DbStorageImpl::condParam<>(std::string const& paramName, int const& value);
1024 template void dafPer::DbStorageImpl::condParam<>(std::string const& paramName, long const& value);
1025 template void dafPer::DbStorageImpl::condParam<>(std::string const& paramName, long long const& value);
1026 template void dafPer::DbStorageImpl::condParam<>(std::string const& paramName, float const& value);
1027 template void dafPer::DbStorageImpl::condParam<>(std::string const& paramName, double const& value);
1028 template void dafPer::DbStorageImpl::condParam<>(std::string const& paramName, std::string const& value);
1029 template void dafPer::DbStorageImpl::condParam<>(std::string const& paramName, bool const& value);
1030 template void dafPer::DbStorageImpl::condParam<>(std::string const& paramName, dafBase::DateTime const& value);
1031 
1032 template char const& dafPer::DbStorageImpl::getColumnByPos<>(int pos);
1033 template short const& dafPer::DbStorageImpl::getColumnByPos<>(int pos);
1034 template int const& dafPer::DbStorageImpl::getColumnByPos<>(int pos);
1035 template long const& dafPer::DbStorageImpl::getColumnByPos<>(int pos);
1036 template long long const& dafPer::DbStorageImpl::getColumnByPos<>(int pos);
1037 template float const& dafPer::DbStorageImpl::getColumnByPos<>(int pos);
1038 template double const& dafPer::DbStorageImpl::getColumnByPos<>(int pos);
1039 template std::string const& dafPer::DbStorageImpl::getColumnByPos<>(int pos);
1040 template bool const& dafPer::DbStorageImpl::getColumnByPos<>(int pos);
1041 template dafBase::DateTime const& dafPer::DbStorageImpl::getColumnByPos<>(int pos);
virtual void setQueryWhere(std::string const &whereClause)
Class for handling dates/times, including MJD, UTC, and TAI.
Definition: DateTime.h:58
table::Key< std::string > name
Definition: ApCorrMap.cc:71
virtual void setTableForInsert(std::string const &tableName)
void outParam(std::string const &columnName, T *location, bool isExpr)
void setColumn(std::string const &columnName, T const &value)
virtual void executeSql(std::string const &sqlStatement)
Include files required for standard LSST Exception handling.
Class for logical location of a persisted Persistable instance.
virtual void setPolicy(pexPolicy::Policy::Ptr policy)
boost::shared_ptr< Policy > Ptr
Definition: Policy.h:172
virtual std::string const & getPort(void) const
definition of the Trace messaging facilities
SelectEigenView< T >::Type copy(Eigen::EigenBase< T > const &other)
Copy an arbitrary Eigen expression into a new EigenView.
Definition: eigen.h:390
virtual void outColumn(std::string const &columnName, bool isExpr)
virtual void groupBy(std::string const &expression)
virtual void startSession(std::string const &location)
long long nsecs(Timescale scale=TAI) const
Definition: DateTime.cc:441
def error
Definition: log.py:108
Location of a persisted Persistable instance in a database.
std::string const & locString(void) const
void error(std::string const &text, bool mysqlCaused=true)
virtual void setRetrieveLocation(LogicalLocation const &location)
virtual std::string const & getPassword(void) const
void condParam(std::string const &paramName, T const &value)
Interface for DateTime class.
virtual std::string const & getHostname(void) const
virtual void setTableListForQuery(std::vector< std::string > const &tableNameList)
virtual void orderBy(std::string const &expression)
virtual void truncateTable(std::string const &tableName)
#define LSST_EXCEPT(type,...)
Definition: Exception.h:46
virtual void setColumnToNull(std::string const &columnName)
tuple m
Definition: lsstimport.py:48
std::string quote(std::string const &name)
virtual void createTableFromTemplate(std::string const &tableName, std::string const &templateName, bool mayAlreadyExist)
struct tm gmtime(void) const
Definition: DateTime.cc:492
void stError(std::string const &text)
Interface for DbStorageImpl class.
virtual void setPersistLocation(LogicalLocation const &location)
void executeQuery(std::string const &query)
virtual void dropTable(std::string const &tableName)
Interface for LogicalLocation class.
#define __attribute__(x)
int col
Definition: CR.cc:152
virtual std::string const & getDbName(void) const
virtual std::string const & getUsername(void) const
Interface for DbStorageLocation class.
virtual void setTableForQuery(std::string const &tableName, bool isExpr)