aGrUM  0.21.0
a C++ library for (probabilistic) graphical models
nanodbcParser_tpl.h
Go to the documentation of this file.
1 /***************************************************************************
2  * Copyright (c) 2005-2020 by Christophe GONZALES(@AMU) and Pierre-Henri WUILLEMIN(@LIP6) *
3  * info_at_agrum_dot_org *
4  * *
5  * This program is free software; you can redistribute it and/or modify *
6  * it under the terms of the GNU General Public License as published by *
7  * the Free Software Foundation; either version 2 of the License, or *
8  * (at your option) any later version. *
9  * *
10  * This program is distributed in the hope that it will be useful, *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13  * GNU General Public License for more details. *
14  * *
15  * You should have received a copy of the GNU General Public License *
16  * along with this program; if not, write to the *
17  * Free Software Foundation, Inc., *
18  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19  ***************************************************************************/
20 /**
21  * @file
22  * @brief Class for parsing SQL results using Nanodbc.
23  *
24  * @author Lionel TORTI, Christophe GONZALES(@AMU) and Pierre-Henri WUILLEMIN(@LIP6)
25  */
26 
27 #ifdef ODBC_
28 
29 #ifndef DOXYGEN_SHOULD_SKIP_THIS
30 
31 #include <agrum/tools/database/nanodbcParser.h>
32 
33 namespace gum {
34 
35  namespace learning {
36 
37 
38  /// Default constructor
39  template <template<typename> class ALLOC>
40  NanodbcParser<ALLOC>::NanodbcParser( const ALLOC<std::string>& alloc )
41  : _data_( alloc ) {
42  GUM_CONSTRUCTOR( NanodbcParser );
43  }
44 
45 
46  /// constructor that executes an SQL query if the connection is active
47  template <template<typename> class ALLOC>
48  NanodbcParser<ALLOC>::NanodbcParser( nanodbc::connection& connexion,
49  const std::string& query,
50  const ALLOC<std::string>& alloc )
51  : _data_( alloc ) {
52  // check if there is a connection. If so, execute the query
53  if ( connexion.connected () ) {
54  _result_ = nanodbc::execute( connexion, query );
55  _data_.resize ( std::size_t ( _result_.columns() ) );
56  }
57  GUM_CONSTRUCTOR( NanodbcParser );
58  }
59 
60 
61  /// destructor
62  template <template<typename> class ALLOC>
63  NanodbcParser<ALLOC>::~NanodbcParser() {
64  GUM_DESTRUCTOR( NanodbcParser );
65  }
66 
67 
68  /// Gets the next line of the SQL stream and parses it.
69  template <template<typename> class ALLOC>
70  bool NanodbcParser<ALLOC>::next() {
71  /* Extract from sql.h:
72  SQL data type codes
73  #define SQL_UNKNOWN_TYPE 0
74  #define SQL_CHAR 1
75  #define SQL_NUMERIC 2
76  #define SQL_DECIMAL 3
77  #define SQL_INTEGER 4
78  #define SQL_SMALLINT 5
79  #define SQL_FLOAT 6
80  #define SQL_REAL 7
81  #define SQL_DOUBLE 8
82  #if (ODBCVER >= 0x0300)
83  #define SQL_DATETIME 9
84  #endif
85  #define SQL_VARCHAR 12 */
86  try {
87  if ( _result_.next() ) {
88  const std::size_t nb_cols = std::size_t ( _result_.columns() );
89  char str[100]; // buffer for retrieving floats
90  for ( std::size_t i = 0; i < nb_cols; ++i ) {
91  const short pos ( i );
92  try {
93  const int type = _result_.column_datatype ( pos );
94 
95  // if the column contains a numeric field, we should use
96  // method get<float>, otherwise a get<string> should be ok
97  // WARNING: using a get<string> to get the content of a
98  // real-valued field will provide incorrect results
99  if ( ( type >= SQL_NUMERIC ) && ( type <= SQL_DOUBLE ) ) {
100  sprintf ( str, "%g", _result_.get<float>( pos ) );
101  _data_[i] = str;
102  }
103  else {
104  _data_[i] = _result_.get<std::string>( pos );
105  }
106  } catch ( nanodbc::null_access_error& e ) {
107  _data_[i] = "NULL";
108  }
109  }
110  ++ _nb_line_;
111  return true;
112  }
113  } catch ( std::runtime_error& e ) {
114  GUM_ERROR( DatabaseError, std::string( e.what() ) )
115  }
116  _data_.clear();
117  return false;
118  }
119 
120 
121  // return the current number line
122  template <template<typename> class ALLOC>
123  INLINE std::size_t NanodbcParser<ALLOC>::nbLine() const {
124  return _nb_line_ >= 1 ? _nb_line_ - 1 : std::size_t(0);
125  }
126 
127 
128  // returns the current parsed line.
129  template <template<typename> class ALLOC>
130  INLINE
131  const std::vector<std::string,ALLOC<std::string>>&
132  NanodbcParser<ALLOC>::current() const {
133  if ( ! _data_.empty () ) {
134  return _data_;
135  }
136 
137  GUM_ERROR( NullElement, "No parsed data" )
138  }
139 
140 
141  /// start a new query
142  template <template<typename> class ALLOC>
143  void NanodbcParser<ALLOC>::useNewQuery ( nanodbc::connection& connexion,
144  const std::string& query ) {
145  _result_ = nanodbc::execute( connexion, query );
146  _data_.resize ( std::size_t ( _result_.columns() ) );
147  _nb_line_ = std::size_t(0);
148  }
149 
150 
151  /// returns the number of columns in the query result
152  template <template<typename> class ALLOC>
153  INLINE std::size_t NanodbcParser<ALLOC>::nbColumns () const {
154  return std::size_t ( _result_.columns () );
155  }
156 
157 
158  /// returns the name of the ith column
159  template <template<typename> class ALLOC>
160  INLINE std::string
161  NanodbcParser<ALLOC>::columnName ( const std::size_t i ) const {
162  return _result_.column_name( i );
163  }
164 
165 
166  } // namespace learning
167 
168 } // namespace gum
169 
170 #endif /* DOXYGEN_SHOULD_SKIP_THIS */
171 
172 #endif // ODBC_