// // Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef SOCI_VALUES_H_INCLUDED #define SOCI_VALUES_H_INCLUDED #include "statement.h" #include "into-type.h" #include "use-type.h" #include namespace soci { namespace details { class copy_base { public: virtual ~copy_base() {} }; template struct copy_holder : public copy_base { copy_holder(T const & v) : value_(v) {} T value_; }; } // namespace details class SOCI_DECL values { friend class details::statement_impl; friend class details::into_type; friend class details::use_type; public: values() : row_(NULL), currentPos_(0), uppercaseColumnNames_(false) {} indicator get_indicator(std::size_t pos) const; indicator get_indicator(std::string const & name) const; template T get(std::size_t pos) const { if (row_ != NULL) { return row_->get(pos); } else if (*indicators_[pos] != i_null) { return get_from_uses(pos); } else { std::ostringstream msg; msg << "Column at position " << static_cast(pos) << " contains NULL value and no default was provided"; throw soci_error(msg.str()); } } template T get(std::size_t pos, T const & nullValue) const { if (row_ != NULL) { return row_->get(pos, nullValue); } else if (*indicators_[pos] == i_null) { return nullValue; } else { return get_from_uses(pos); } } template T get(std::string const & name) const { return row_ != NULL ? row_->get(name) : get_from_uses(name); } template T get(std::string const & name, T const & nullValue) const { return row_ != NULL ? row_->get(name, nullValue) : get_from_uses(name, nullValue); } template values const & operator>>(T & value) const { if (row_ != NULL) { // row maintains its own position counter // which is automatically reset when needed *row_ >> value; } else if (*indicators_[currentPos_] != i_null) { // if there is no row object, then the data can be // extracted from the locally stored use elements, // but for this the position counter has to be maintained // as well value = get_from_uses(currentPos_); ++currentPos_; } else { std::ostringstream msg; msg << "Column at position " << static_cast(currentPos_) << " contains NULL value and no default was provided"; throw soci_error(msg.str()); } return *this; } void skip(std::size_t num = 1) const { if (row_ != NULL) { row_->skip(num); } else { currentPos_ += num; } } void reset_get_counter() const { if (row_ != NULL) { row_->reset_get_counter(); } else { currentPos_ = 0; } } template void set(std::string const & name, T const & value, indicator indic = i_ok) { index_.insert(std::make_pair(name, uses_.size())); indicator * pind = new indicator(indic); indicators_.push_back(pind); typedef typename type_conversion::base_type base_type; base_type baseValue; if (indic == i_ok) { type_conversion::to_base(value, baseValue, *pind); } details::copy_holder * pcopy = new details::copy_holder(baseValue); deepCopies_.push_back(pcopy); uses_.push_back(new details::use_type( pcopy->value_, *pind, name)); } template void set(const T & value, indicator indic = i_ok) { indicator * pind = new indicator(indic); indicators_.push_back(pind); typedef typename type_conversion::base_type base_type; base_type baseValue; type_conversion::to_base(value, baseValue, *pind); details::copy_holder * pcopy = new details::copy_holder(baseValue); deepCopies_.push_back(pcopy); uses_.push_back(new details::use_type( pcopy->value_, *pind)); } template values & operator<<(T const & value) { set(value); return *this; } void uppercase_column_names(bool forceToUpper) { uppercaseColumnNames_ = forceToUpper; } private: //TODO To make values generally usable outside of TypeConversionS, // these should be reference counted smart pointers row * row_; std::vector uses_; std::map unused_; std::vector indicators_; std::map index_; std::vector deepCopies_; mutable std::size_t currentPos_; bool uppercaseColumnNames_; // When TypeConversion::to() is called, a values object is created // without an underlying row object. In that case, get_from_uses() // returns the underlying field values template T get_from_uses(std::string const & name, T const & nullValue) const { std::map::const_iterator pos = index_.find(name); if (pos != index_.end()) { if (*indicators_[pos->second] == i_null) { return nullValue; } return get_from_uses(pos->second); } throw soci_error("Value named " + name + " not found."); } template T get_from_uses(std::string const & name) const { std::map::const_iterator pos = index_.find(name); if (pos != index_.end()) { return get_from_uses(pos->second); } throw soci_error("Value named " + name + " not found."); } template T get_from_uses(std::size_t pos) const { details::standard_use_type* u = uses_[pos]; typedef typename type_conversion::base_type base_type; if (dynamic_cast *>(u)) { base_type const & baseValue = *static_cast(u->get_data()); T val; indicator ind = *indicators_[pos]; type_conversion::from_base(baseValue, ind, val); return val; } else { std::ostringstream msg; msg << "Value at position " << static_cast(pos) << " was set using a different type" " than the one passed to get()"; throw soci_error(msg.str()); } } row& get_row() { row_ = new row(); row_->uppercase_column_names(uppercaseColumnNames_); return * row_; } // this is called by Statement::bind(values) void add_unused(details::use_type_base * u, indicator * i) { static_cast(u)->convert_to_base(); unused_.insert(std::make_pair(u, i)); } // this is called by details::into_type::clean_up() // and use_type::clean_up() void clean_up() { delete row_; row_ = NULL; // delete any uses and indicators which were created by set() but // were not bound by the Statement // (bound uses and indicators are deleted in Statement::clean_up()) for (std::map::iterator pos = unused_.begin(); pos != unused_.end(); ++pos) { delete pos->first; delete pos->second; } for (std::size_t i = 0; i != deepCopies_.size(); ++i) { delete deepCopies_[i]; } } }; } // namespace soci #endif // SOCI_VALUES_H_INCLUDED