backends/firebird/session.cpp
Go to the documentation of this file.
1 //
2 // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton, Rafal Bobrowski
3 // Distributed under the Boost Software License, Version 1.0.
4 // (See accompanying file LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
6 //
7 
8 #define SOCI_FIREBIRD_SOURCE
9 #include "soci-firebird.h"
10 #include "error-firebird.h"
11 #include "session.h"
12 #include <locale>
13 #include <map>
14 #include <sstream>
15 #include <string>
16 
17 using namespace soci;
18 using namespace soci::details::firebird;
19 
20 namespace
21 {
22 
23 // Helpers of explodeISCConnectString() for reading words from a string. "Word"
24 // here is defined very loosely as just a sequence of non-space characters.
25 //
26 // All these helper functions update the input iterator to point to the first
27 // character not consumed by them.
28 
29 // Advance the input iterator until the first non-space character or end of the
30 // string.
31 void skipWhiteSpace(std::string::const_iterator& i, std::string::const_iterator const &end)
32 {
33  std::locale const loc;
34  for (; i != end; ++i)
35  {
36  if (!std::isspace(*i, loc))
37  break;
38  }
39 }
40 
41 // Return the string of all characters until the first space or the specified
42 // delimiter.
43 //
44 // Throws if the first non-space character after the end of the word is not the
45 // delimiter. However just returns en empty string, without throwing, if
46 // nothing is left at all in the string except for white space.
47 std::string
48 getWordUntil(std::string const &s, std::string::const_iterator &i, char delim)
49 {
50  std::string::const_iterator const end = s.end();
51  skipWhiteSpace(i, end);
52 
53  // We need to handle this case specially because it's not an error if
54  // nothing at all remains in the string. But if anything does remain, then
55  // we must have the delimiter.
56  if (i == end)
57  return std::string();
58 
59  // Simply put anything until the delimiter into the word, stopping at the
60  // first white space character.
61  std::string word;
62  std::locale const loc;
63  for (; i != end; ++i)
64  {
65  if (*i == delim)
66  break;
67 
68  if (std::isspace(*i, loc))
69  {
70  skipWhiteSpace(i, end);
71  if (i == end || *i != delim)
72  {
73  std::ostringstream os;
74  os << "Expected '" << delim << "' at position "
75  << (i - s.begin() + 1)
76  << " in Firebird connection string \""
77  << s << "\".";
78 
79  throw soci_error(os.str());
80  }
81 
82  break;
83  }
84 
85  word += *i;
86  }
87 
88  if (i == end)
89  {
90  std::ostringstream os;
91  os << "Expected '" << delim
92  << "' not found before the end of the string "
93  << "in Firebird connection string \""
94  << s << "\".";
95 
96  throw soci_error(os.str());
97  }
98 
99  ++i; // Skip the delimiter itself.
100 
101  return word;
102 }
103 
104 // Return a possibly quoted word, i.e. either just a sequence of non-space
105 // characters or everything inside a double-quoted string.
106 //
107 // Throws if the word is quoted and the closing quote is not found. However
108 // doesn't throw, just returns an empty string if there is nothing left.
109 std::string
110 getPossiblyQuotedWord(std::string const &s, std::string::const_iterator &i)
111 {
112  std::string::const_iterator const end = s.end();
113  skipWhiteSpace(i, end);
114 
115  std::string word;
116 
117  if (i != end && *i == '"')
118  {
119  for (;;)
120  {
121  if (++i == end)
122  {
123  std::ostringstream os;
124  os << "Expected '\"' not found before the end of the string "
125  "in Firebird connection string \""
126  << s << "\".";
127 
128  throw soci_error(os.str());
129  }
130 
131  if (*i == '"')
132  {
133  ++i;
134  break;
135  }
136 
137  word += *i;
138  }
139  }
140  else // Not quoted.
141  {
142  std::locale const loc;
143  for (; i != end; ++i)
144  {
145  if (std::isspace(*i, loc))
146  break;
147 
148  word += *i;
149  }
150  }
151 
152  return word;
153 }
154 
155 // retrieves parameters from the uniform connect string which is supposed to be
156 // in the form "key=value[ key2=value2 ...]" and the values may be quoted to
157 // allow including spaces into them. Notice that currently there is no way to
158 // include both a space and a double quote in a value.
159 std::map<std::string, std::string>
160 explodeISCConnectString(std::string const &connectString)
161 {
162  std::map<std::string, std::string> parameters;
163 
164  std::string key, value;
165  for (std::string::const_iterator i = connectString.begin(); ; )
166  {
167  key = getWordUntil(connectString, i, '=');
168  if (key.empty())
169  break;
170 
171  value = getPossiblyQuotedWord(connectString, i);
172 
173  parameters.insert(std::pair<std::string, std::string>(key, value));
174  }
175 
176  return parameters;
177 }
178 
179 // extracts given parameter from map previusly build with explodeISCConnectString
180 bool getISCConnectParameter(std::map<std::string, std::string> const & m, std::string const & key,
181  std::string & value)
182 {
183  std::map <std::string, std::string> :: const_iterator i;
184  value.clear();
185 
186  i = m.find(key);
187 
188  if (i != m.end())
189  {
190  value = i->second;
191  return true;
192  }
193  else
194  {
195  return false;
196  }
197 }
198 
199 } // namespace anonymous
200 
202  connection_parameters const & parameters) : dbhp_(0), trhp_(0)
203  , decimals_as_strings_(false)
204 {
205  // extract connection parameters
206  std::map<std::string, std::string>
207  params(explodeISCConnectString(parameters.get_connect_string()));
208 
209  ISC_STATUS stat[stat_size];
210  std::string param;
211 
212  // preparing connection options
213  if (getISCConnectParameter(params, "user", param))
214  {
215  setDPBOption(isc_dpb_user_name, param);
216  }
217 
218  if (getISCConnectParameter(params, "password", param))
219  {
220  setDPBOption(isc_dpb_password, param);
221  }
222 
223  if (getISCConnectParameter(params, "role", param))
224  {
225  setDPBOption(isc_dpb_sql_role_name, param);
226  }
227 
228  if (getISCConnectParameter(params, "charset", param))
229  {
230  setDPBOption(isc_dpb_lc_ctype, param);
231  }
232 
233  if (getISCConnectParameter(params, "service", param) == false)
234  {
235  throw soci_error("Service name not specified.");
236  }
237 
238  // connecting data base
239  if (isc_attach_database(stat, static_cast<short>(param.size()),
240  const_cast<char*>(param.c_str()), &dbhp_,
241  static_cast<short>(dpb_.size()), const_cast<char*>(dpb_.c_str())))
242  {
243  throw_iscerror(stat);
244  }
245 
246  if (getISCConnectParameter(params, "decimals_as_strings", param))
247  {
248  decimals_as_strings_ = param == "1" || param == "Y" || param == "y";
249  }
250  // starting transaction
251  begin();
252 }
253 
254 
256 {
257  // Transaction is always started in ctor, because Firebird can't work
258  // without active transaction.
259  // Transaction will be automatically commited in cleanUp method.
260  if (trhp_ == 0)
261  {
262  ISC_STATUS stat[stat_size];
263  if (isc_start_transaction(stat, &trhp_, 1, &dbhp_, 0, NULL))
264  {
265  throw_iscerror(stat);
266  }
267  }
268 }
269 
271 {
272  cleanUp();
273 }
274 
275 void firebird_session_backend::setDPBOption(int const option, std::string const & value)
276 {
277 
278  if (dpb_.size() == 0)
279  {
280  dpb_.append(1, static_cast<char>(isc_dpb_version1));
281  }
282 
283  // now we are adding new option
284  dpb_.append(1, static_cast<char>(option));
285  dpb_.append(1, static_cast<char>(value.size()));
286  dpb_.append(value);
287 }
288 
290 {
291  ISC_STATUS stat[stat_size];
292 
293  if (trhp_ != 0)
294  {
295  if (isc_commit_transaction(stat, &trhp_))
296  {
297  throw_iscerror(stat);
298  }
299 
300  trhp_ = 0;
301  }
302 
303 #ifndef SOCI_FIREBIRD_NORESTARTTRANSACTION
304  begin();
305 #endif
306 
307 }
308 
310 {
311  ISC_STATUS stat[stat_size];
312 
313  if (trhp_ != 0)
314  {
315  if (isc_rollback_transaction(stat, &trhp_))
316  {
317  throw_iscerror(stat);
318  }
319 
320  trhp_ = 0;
321  }
322 
323 #ifndef SOCI_FIREBIRD_NORESTARTTRANSACTION
324  begin();
325 #endif
326 
327 }
328 
330 {
331  ISC_STATUS stat[stat_size];
332 
333  // at the end of session our transaction is finally commited.
334  if (trhp_ != 0)
335  {
336  if (isc_commit_transaction(stat, &trhp_))
337  {
338  throw_iscerror(stat);
339  }
340 
341  trhp_ = 0;
342  }
343 
344  if (isc_detach_database(stat, &dbhp_))
345  {
346  throw_iscerror(stat);
347  }
348 
349  dbhp_ = 0L;
350 }
351 
353  session & s, std::string const & sequence, long & value)
354 {
355  // We could use isq_execute2() directly but this is even simpler.
356  s << "select next value for " + sequence + " from rdb$database",
357  into(value);
358 
359  return true;
360 }
361 
363 {
364  return new firebird_statement_backend(*this);
365 }
366 
368 {
369  return new firebird_rowid_backend(*this);
370 }
371 
373 {
374  return new firebird_blob_backend(*this);
375 }
details::into_container< T, details::no_indicator > into(T &t)
Definition: into.h:51
virtual firebird_statement_backend * make_statement_backend()
firebird_session_backend(connection_parameters const &parameters)
std::string const & get_connect_string() const
std::size_t const stat_size
Definition: soci-firebird.h:40
virtual bool get_next_sequence_value(session &s, std::string const &sequence, long &value)
void throw_iscerror(ISC_STATUS *status_vector)
std::string connectString
Definition: test-db2.cpp:21
virtual firebird_rowid_backend * make_rowid_backend()
std::vector< ISM::CombinatorialTrainerParameters > parameters
virtual firebird_blob_backend * make_blob_backend()
virtual void setDPBOption(int const option, std::string const &value)


asr_lib_ism
Author(s): Hanselmann Fabian, Heller Florian, Heizmann Heinrich, Kübler Marcel, Mehlhaus Jonas, Meißner Pascal, Qattan Mohamad, Reckling Reno, Stroh Daniel
autogenerated on Wed Jan 8 2020 04:02:41