Skip to content

Commit

Permalink
Merge branch 'conn-params-improve'
Browse files Browse the repository at this point in the history
Improvements to connection string handling: don't duplicate parsing code
in Firebird, Oracle, PostgreSQL and SQLite backends.

Also allow using connection_parameters::set_option() to set some option
instead of having to specify it in the connection string itself.

See SOCI#1176.
  • Loading branch information
vadz committed Nov 10, 2024
2 parents ee5ce98 + 1a6607b commit 7fb2e51
Show file tree
Hide file tree
Showing 19 changed files with 642 additions and 514 deletions.
5 changes: 0 additions & 5 deletions docs/backends/postgresql.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,6 @@ Note that in the single-row operation:
* bulk queries are not supported, and
* in order to fulfill the expectations of the underlying client library, the complete rowset has to be exhausted before executing further queries on the same session.

Also please note that single rows mode requires PostgreSQL 9 or later, both at
compile- and run-time. If you need to support earlier versions of PostgreSQL,
you can define `SOCI_POSTGRESQL_NOSINGLEROWMODE` when building the library to
disable it.

Once you have created a `session` object as shown above, you can use it to access the database, for example:

```cpp
Expand Down
13 changes: 10 additions & 3 deletions docs/backends/sqlite3.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,21 @@ session sql("sqlite3", "db=db.sqlite timeout=2 shared_cache=true");
The set of parameters used in the connection string for SQLite is:
* `dbname` or `db`
* `dbname` or `db` - this parameter is required unless the entire connection
string is just the database name, in which case it must not contain any `=`
signs.
* `timeout` - set sqlite busy timeout (in seconds) ([link](http://www.sqlite.org/c3ref/busy_timeout.html))
* `readonly` - open database in read-only mode instead of the default read-write (note that the database file must already exist in this case, see [the documentation](https://www.sqlite.org/c3ref/open.html))
* `nocreate` - open an existing database without creating a new one if it doesn't already exist (by default, a new database file is created).
* `synchronous` - set the pragma synchronous flag ([link](http://www.sqlite.org/pragma.html#pragma_synchronous))
* `shared_cache` - should be `true` ([link](http://www.sqlite.org/c3ref/enable_shared_cache.html))
* `shared_cache` - enable or disabled shared pager cache ([link](http://www.sqlite.org/c3ref/enable_shared_cache.html))
* `vfs` - set the SQLite VFS used to as OS interface. The VFS should be registered before opening the connection, see [the documenation](https://www.sqlite.org/vfs.html)
* `foreign_keys` - set the pragma foreign_keys flag ([link](https://www.sqlite.org/pragma.html#pragma_foreign_keys)).
* `foreign_keys` - set the pragma `foreign_keys` flag ([link](https://www.sqlite.org/pragma.html#pragma_foreign_keys)).
Boolean options `readonly`, `nocreate`, and `shared_cache` can be either
specified without any value, which is equivalent to setting them to `1`, or set
to one of `1`, `yes`, `true` or `on` to enable the option or `0`, `no`, `false`
or `off` to disable it. Specifying any other value results in an error.
Once you have created a `session` object as shown above, you can use it to access the database, for example:
Expand Down
58 changes: 58 additions & 0 deletions include/private/soci-case.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
//
// Copyright (C) 2024 Vadim Zeitlin.
// 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_PRIVATE_SOCI_CASE_H_INCLUDED
#define SOCI_PRIVATE_SOCI_CASE_H_INCLUDED

#include <cctype>
#include <string>

namespace soci
{

namespace details
{

// Simplistic conversions of strings to upper/lower case.
//
// This doesn't work correctly for arbitrary Unicode strings for well-known
// reasons (such conversions can't be done correctly on char by char basis),
// but they do work for ASCII strings that we deal with and for anything else
// we'd need ICU -- which we could start using later, if necessary, by just
// replacing these functions with the versions using ICU functions instead.

inline std::string string_toupper(std::string const& s)
{
std::string res;
res.reserve(s.size());

for (char c : s)
{
res += static_cast<char>(std::toupper(static_cast<unsigned char>(c)));
}

return res;
}

inline std::string string_tolower(std::string const& s)
{
std::string res;
res.reserve(s.size());

for (char c : s)
{
res += static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
}

return res;
}

} // namespace details

} // namespace soci

#endif // SOCI_PRIVATE_SOCI_CASE_H_INCLUDED
45 changes: 42 additions & 3 deletions include/soci/connection-parameters.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,22 @@ class SOCI_DECL connection_parameters
void set_connect_string(const std::string & connectString) { connectString_ = connectString; }
std::string const & get_connect_string() const { return connectString_; }


// For some (but not all) backends the connection string consists of
// space-separated name=value pairs. This function parses the string
// assuming it uses this syntax and sets the options accordingly.
//
// If it detects invalid syntax, e.g. a name without a corresponding value,
// it throws an exception.
//
// Note that currently unknown options are simply ignored.
void extract_options_from_space_separated_string();

// Build a space-separated string from the options, quoting the options
// values using the provided quote character.
std::string build_string_from_options(char quote) const;


// Set the value of the given option, overwriting any previous value.
void set_option(const char * name, std::string const & value)
{
Expand All @@ -70,12 +86,35 @@ class SOCI_DECL connection_parameters
return true;
}

// Return true if the option with the given name was found with option_true
// value.
// Same as get_option(), but also removes the option from the connection
// string if it was present in it.
bool extract_option(const char * name, std::string & value)
{
Options::iterator const it = options_.find(name);
if (it == options_.end())
return false;

value = it->second;
options_.erase(it);

return true;
}

// Return true if the option with the given name has one of the values
// considered to be true, i.e. "1", "yes", "true" or "on" or is empty.
// Return false if the value is one of "0", "no", "false" or "off" or the
// option was not specified at all.
//
// Throw an exception if the option was given but the value is none of
// the above, comparing case-insensitively.
static bool is_true_value(const char * name, std::string const & value);

// Return true if the option with the given name was found with a "true"
// value in the sense of is_true_value() above.
bool is_option_on(const char * name) const
{
std::string value;
return get_option(name, value) && value == option_true;
return get_option(name, value) && is_true_value(name, value);
}

private:
Expand Down
3 changes: 1 addition & 2 deletions include/soci/postgresql/soci-postgresql.h
Original file line number Diff line number Diff line change
Expand Up @@ -384,8 +384,7 @@ class SOCI_POSTGRESQL_DECL postgresql_blob_backend : public details::blob_backen

struct SOCI_POSTGRESQL_DECL postgresql_session_backend : details::session_backend
{
postgresql_session_backend(connection_parameters const & parameters,
bool single_row_mode);
explicit postgresql_session_backend(connection_parameters const & parameters);

~postgresql_session_backend() override;

Expand Down
Loading

0 comments on commit 7fb2e51

Please sign in to comment.