Permalink
Browse files

Add support for odbc_option_driver_complete connection parameter.

Allow passing arbitrary options via connection_parameters and add support for
an option allowing to specify the "driver completion" mode, i.e. the degree of
interactivity of the driver, in the ODBC backend.

By default now do ask the user if the DSN doesn't include the user name and/or
password for the connection but the old behaviour is still available if
ODBC_OPTION_DRIVER_COMPLETE option is set to SQL_DRIVER_NOPROMPT before
opening the session.
  • Loading branch information...
vadz committed Feb 10, 2013
1 parent 104e3f3 commit 4081c575bdcd93aa515cd5cad1a6a46e240a6160
Showing with 74 additions and 4 deletions.
  1. +7 −1 doc/backends/odbc.html
  2. +32 −3 src/backends/odbc/session.cpp
  3. +6 −0 src/backends/odbc/soci-odbc.h
  4. +29 −0 src/core/connection-parameters.h
View
@@ -274,7 +274,13 @@ <h4 id="get_connection_string">get_connection_string()</h4>
<h3 id="options">Configuration options</h3>
<p>None</p>
<p>This backend supports <code>ODBC_OPTION_DRIVER_COMPLETE</code> option which can be passed to it via <code>connection_parameters</code> class. The value of this option is passed to <code>SQLDriverConnect()</code> function as "driver completion" parameter and so must be one of <code>SQL_DRIVER_XXX</code> values, in the string form. The default value of this option is <code>SQL_DRIVER_PROMPT</code> meaning that the driver will query the user for the user name and/or the password if they are not stored together with the connection. If this is undesirable for some reason, you can use <code>SQL_DRIVER_NOPROMPT</code> value for this option to suppress showing the message box:</p>
<pre class="example">
connection_parameters parameters("odbc", "DSN=mydb");
parameters.set_option(ODBC_OPTION_DRIVER_COMPLETE, "0" /* SQL_DRIVER_NOPROMPT */);
session sql(parameters);
</pre>
<p class="copyright">Copyright &copy; 2013 Mateusz Loskot</p>
<p class="copyright">Copyright &copy; 2004-2006 Maciej Sobczak, Stephen Hutton, David Courtney</p>
@@ -9,9 +9,13 @@
#include "soci-odbc.h"
#include "session.h"
#include <cstdio>
using namespace soci;
using namespace soci::details;
char const * soci::odbc_option_driver_complete = "odbc.driver_complete";
odbc_session_backend::odbc_session_backend(
connection_parameters const & parameters)
: henv_(0), hdbc_(0), product_(prod_uninitialized)
@@ -44,11 +48,36 @@ odbc_session_backend::odbc_session_backend(
SQLCHAR outConnString[1024];
SQLSMALLINT strLength;
rc = SQLDriverConnect(hdbc_, NULL, // windows handle
// Prompt the user for any missing information (typically UID/PWD) in the
// connection string by default but allow overriding this using "prompt"
// option.
SQLHWND hwnd_for_prompt = NULL;
unsigned completion = SQL_DRIVER_COMPLETE;
std::string completionString;
if (parameters.get_option(odbc_option_driver_complete, completionString))
{
// The value of the option is supposed to be just the integer value of
// one of SQL_DRIVER_XXX constants but don't check for the exact value in
// case more of them are added in the future, the ODBC driver will return
// an error if we pass it an invalid value anyhow.
if (std::sscanf(completionString.c_str(), "%u", &completion) != 1)
{
throw soci_error("Invalid non-numeric driver completion option value \"" +
completionString + "\".");
}
}
#ifdef _WIN32
if (completion != SQL_DRIVER_NOPROMPT)
hwnd_for_prompt = ::GetDesktopWindow();
#endif // _WIN32
std::string const & connectString = parameters.get_connect_string();
rc = SQLDriverConnect(hdbc_, hwnd_for_prompt,
(SQLCHAR *)connectString.c_str(),
(SQLSMALLINT)connectString.size(),
outConnString, 1024,
&strLength, SQL_DRIVER_NOPROMPT);
outConnString, 1024, &strLength,
static_cast<SQLUSMALLINT>(completion));
if (is_odbc_error(rc))
{
@@ -40,6 +40,12 @@ namespace details
std::size_t const odbc_max_buffer_length = 100 * 1024 * 1024;
}
// Option allowing to specify the "driver completion" parameter of
// SQLDriverConnect(). Its possible values are the same as the allowed values
// for this parameter in the official ODBC, i.e. one of SQL_DRIVER_XXX (in
// string form as all options are strings currently).
extern SOCI_ODBC_DECL char const * odbc_option_driver_complete;
struct odbc_statement_backend;
// Helper of into and use backends.
@@ -10,6 +10,7 @@
#include "soci-config.h"
#include <map>
#include <string>
namespace soci
@@ -28,10 +29,38 @@ class SOCI_DECL connection_parameters
// Default copy ctor, assignment operator and dtor are all OK for us.
// Retrieve the backend and the connection strings specified in the ctor.
backend_factory const * get_factory() const { return factory_; }
std::string const & get_connect_string() const { return connectString_; }
// Set the value of the given option, overwriting any previous value.
void set_option(const char * name, std::string const & value)
{
options_[name] = value;
}
// Return true if the option with the given name was found and fill the
// provided parameter with its value.
bool get_option(const char * name, std::string & value) const
{
Options::const_iterator const it = options_.find(name);
if (it == options_.end())
return false;
value = it->second;
return true;
}
private:
// The backend and connection string specified in our ctor.
backend_factory const * factory_;
std::string connectString_;
// We store all the values as strings for simplicity.
typedef std::map<const char*, std::string> Options;
Options options_;
};
} // namespace soci

0 comments on commit 4081c57

Please sign in to comment.