Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master'
Browse files Browse the repository at this point in the history
  • Loading branch information
pbondo committed Feb 21, 2013
2 parents 39c10a6 + d121e93 commit 14e2a75
Show file tree
Hide file tree
Showing 23 changed files with 631 additions and 130 deletions.
6 changes: 3 additions & 3 deletions .travis.yml
Expand Up @@ -21,7 +21,7 @@ before_install:
# http://tech.groups.yahoo.com/group/firebird-support/message/120883
#- sudo dpkg-reconfigure -f noninteractive firebird2.5-super
- sudo sed /ENABLE_FIREBIRD_SERVER=/s/no/yes/ -i /etc/default/firebird2.5
- cat /etc/default/firebird2.5
- cat /etc/default/firebird2.5 | grep ENABLE_FIREBIRD_SERVER
- sudo service firebird2.5-super start

before_script:
Expand All @@ -32,12 +32,12 @@ before_script:
- isql-fb -z -q -i /dev/null # --version
- echo 'CREATE DATABASE "LOCALHOST:/tmp/soci_test.fdb" PAGE_SIZE = 16384;' > /tmp/create_soci_test.sql
- isql-fb -u SYSDBA -p masterkey -i /tmp/create_soci_test.sql -q
- ls -l /tmp/
- cat /tmp/create_soci_test.sql

script:
- mkdir -p src/_build
- cd src/_build
- cmake -DSOCI_TESTS=ON -DSOCI_EMPTY_TEST_CONNSTR:STRING="dummy connection" -DSOCI_FIREBIRD_TEST_CONNSTR:STRING="service=LOCALHOST:/tmp/soci_test.fdb user=SYSDBA password=masterkey -DSOCI_MYSQL_TEST_CONNSTR:STRING="db=soci_test" -DSOCI_POSTGRESQL_TEST_CONNSTR:STRING="dbname=soci_test user=postgres" -DSOCI_SQLITE3_TEST_CONNSTR:STRING="soci_test.db" -DSOCI_ODBC_TEST_POSTGRESQL_CONNSTR="FILEDSN=${PWD}/../backends/odbc/test/test-postgresql.dsn;" -DSOCI_ODBC_TEST_MYSQL_CONNSTR="FILEDSN=${PWD}/../backends/odbc/test/test-mysql.dsn;" ..
- cmake -DSOCI_TESTS=ON -DSOCI_EMPTY_TEST_CONNSTR:STRING="dummy connection" -DSOCI_FIREBIRD_TEST_CONNSTR:STRING="service=LOCALHOST:/tmp/soci_test.fdb user=SYSDBA password=masterkey" -DSOCI_MYSQL_TEST_CONNSTR:STRING="db=soci_test" -DSOCI_POSTGRESQL_TEST_CONNSTR:STRING="dbname=soci_test user=postgres" -DSOCI_SQLITE3_TEST_CONNSTR:STRING="soci_test.db" -DSOCI_ODBC_TEST_POSTGRESQL_CONNSTR="FILEDSN=${PWD}/../backends/odbc/test/test-postgresql.dsn;" -DSOCI_ODBC_TEST_MYSQL_CONNSTR="FILEDSN=${PWD}/../backends/odbc/test/test-mysql.dsn;" ..
- cmake --build .
- ctest -V --output-on-failure .

Expand Down
1 change: 1 addition & 0 deletions README.md
Expand Up @@ -40,6 +40,7 @@ Requirements

Core:
* C++ compiler
* Boost C++ Libraries (optional, headers only)

Backend specific:
* Firebird client library X.Y
Expand Down
20 changes: 1 addition & 19 deletions src/CMakeLists.txt
Expand Up @@ -67,25 +67,7 @@ include(SociDependencies)
# Installation
#################################################################################

if(EXISTS /etc/os-release)
file(READ /etc/os-release OS_RELEASE)
string(REGEX MATCH "ID(_LIKE)?=debian" DEBIAN ${OS_RELEASE})
string(REGEX MATCH "ID(_LIKE)?=fedora" FEDORA ${OS_RELEASE})
string(REGEX MATCH "ID(_LIKE)?=ubuntu" UBUNTU ${OS_RELEASE})
elseif(EXISTS /etc/lsb-release)
file(READ /etc/lsb-release OS_RELEASE)
string(REGEX MATCH "DISTRIB_ID=[Uu]buntu" UBUNTU ${OS_RELEASE})
string(REGEX MATCH "DISTRIB_ID=[Db]ebian" DEBIAN ${OS_RELEASE})
endif()

if(UBUNTU)
set(SOCI_LIBDIR "lib")
elseif(DEBIAN)
execute_process(COMMAND uname -m
OUTPUT_VARIABLE SOCI_ARCH
OUTPUT_STRIP_TRAILING_WHITESPACE)
set(SOCI_LIBDIR "lib/${SOCI_ARCH}-linux-gnu")
elseif(APPLE OR CMAKE_SIZEOF_VOID_P EQUAL 4)
if(APPLE OR CMAKE_SIZEOF_VOID_P EQUAL 4)
set(SOCI_LIBDIR "lib")
else()
set(SOCI_LIBDIR "lib64")
Expand Down
15 changes: 14 additions & 1 deletion src/backends/firebird/common.cpp
Expand Up @@ -190,7 +190,20 @@ std::string getTextParam(XSQLVAR const *var)
{
size = var->sqllen;
}
else throw soci_error("Unexpected string type");
else if ((var->sqltype & ~1) == SQL_SHORT)
{
return format_decimal<short>(var->sqldata, var->sqlscale);
}
else if ((var->sqltype & ~1) == SQL_LONG)
{
return format_decimal<int>(var->sqldata, var->sqlscale);
}
else if ((var->sqltype & ~1) == SQL_INT64)
{
return format_decimal<long long>(var->sqldata, var->sqlscale);
}
else
throw soci_error("Unexpected string type");

return std::string(var->sqldata + offset, size);
}
Expand Down
22 changes: 22 additions & 0 deletions src/backends/firebird/common.h
Expand Up @@ -14,6 +14,7 @@
#include <ctime>
#include <limits>
#include <sstream>
#include <iomanip>
#include <string>
#include <vector>

Expand Down Expand Up @@ -151,6 +152,27 @@ void parse_decimal(void * val, XSQLVAR * var, const char * s)
to_isc<IntType>(val, var, scale);
}

template<typename IntType>
std::string format_decimal(const void *sqldata, int sqlscale)
{
IntType x = *reinterpret_cast<const IntType *>(sqldata);
std::stringstream out;
out << x;
std::string r = out.str();
if (sqlscale < 0)
{
if (r.size() - (x < 0) <= -sqlscale)
{
r = std::string(size_t(x < 0), '-') +
std::string(-sqlscale - (r.size() - (x < 0)) + 1, '0') +
r.substr(size_t(x < 0), std::string::npos);
}
return r.substr(0, r.size() + sqlscale) + '.' +
r.substr(r.size() + sqlscale, std::string::npos);
}
return r + std::string(sqlscale, '0');
}

template<typename T1>
T1 from_isc(XSQLVAR * var)
{
Expand Down
164 changes: 149 additions & 15 deletions src/backends/firebird/session.cpp
Expand Up @@ -9,6 +9,7 @@
#include "soci-firebird.h"
#include "error-firebird.h"
#include "session.h"
#include <locale>
#include <map>
#include <sstream>
#include <string>
Expand All @@ -19,32 +20,160 @@ using namespace soci::details::firebird;
namespace
{

// retrieves parameters from the uniform connect string
void explodeISCConnectString(std::string const &connectString,
std::map<std::string, std::string> &parameters)
// Helpers of explodeISCConnectString() for reading words from a string. "Word"
// here is defined very loosely as just a sequence of non-space characters.
//
// All these helper functions update the input iterator to point to the first
// character not consumed by them.

// Advance the input iterator until the first non-space character or end of the
// string.
void skipWhiteSpace(std::string::const_iterator& i, std::string::const_iterator const &end)
{
std::locale const loc;
for (; i != end; ++i)
{
if (!std::isspace(*i, loc))
break;
}
}

// Return the string of all characters until the first space or the specified
// delimiter.
//
// Throws if the first non-space character after the end of the word is not the
// delimiter. However just returns en empty string, without throwing, if
// nothing is left at all in the string except for white space.
std::string
getWordUntil(std::string const &s, std::string::const_iterator &i, char delim)
{
std::string tmp;
for (std::string::const_iterator i = connectString.begin(),
end = connectString.end(); i != end; ++i)
std::string::const_iterator const end = s.end();
skipWhiteSpace(i, end);

// We need to handle this case specially because it's not an error if
// nothing at all remains in the string. But if anything does remain, then
// we must have the delimiter.
if (i == end)
return std::string();

// Simply put anything until the delimiter into the word, stopping at the
// first white space character.
std::string word;
std::locale const loc;
for (; i != end; ++i)
{
if (*i == '=')
if (*i == delim)
break;

if (std::isspace(*i, loc))
{
tmp += ' ';
skipWhiteSpace(i, end);
if (i == end || *i != delim)
{
std::ostringstream os;
os << "Expected '" << delim << "' at position "
<< (i - s.begin() + 1)
<< " in Firebird connection string \""
<< s << "\".";

throw soci_error(os.str());
}

break;
}
else

word += *i;
}

if (i == end)
{
std::ostringstream os;
os << "Expected '" << delim
<< "' not found before the end of the string "
<< "in Firebird connection string \""
<< s << "\".";

throw soci_error(os.str());
}

++i; // Skip the delimiter itself.

return word;
}

// Return a possibly quoted word, i.e. either just a sequence of non-space
// characters or everything inside a double-quoted string.
//
// Throws if the word is quoted and the closing quote is not found. However
// doesn't throw, just returns an empty string if there is nothing left.
std::string
getPossiblyQuotedWord(std::string const &s, std::string::const_iterator &i)
{
std::string::const_iterator const end = s.end();
skipWhiteSpace(i, end);

std::string word;

if (i != end && *i == '"')
{
for (;;)
{
if (++i == end)
{
std::ostringstream os;
os << "Expected '\"' not found before the end of the string "
"in Firebird connection string \""
<< s << "\".";

throw soci_error(os.str());
}

if (*i == '"')
{
++i;
break;
}

word += *i;
}
}
else // Not quoted.
{
std::locale const loc;
for (; i != end; ++i)
{
tmp += *i;
if (std::isspace(*i, loc))
break;

word += *i;
}
}

parameters.clear();
return word;
}

// retrieves parameters from the uniform connect string which is supposed to be
// in the form "key=value[ key2=value2 ...]" and the values may be quoted to
// allow including spaces into them. Notice that currently there is no way to
// include both a space and a double quote in a value.
std::map<std::string, std::string>
explodeISCConnectString(std::string const &connectString)
{
std::map<std::string, std::string> parameters;

std::istringstream iss(tmp);
std::string key, value;
while (iss >> key >> value)
for (std::string::const_iterator i = connectString.begin(); ; )
{
key = getWordUntil(connectString, i, '=');
if (key.empty())
break;

value = getPossiblyQuotedWord(connectString, i);

parameters.insert(std::pair<std::string, std::string>(key, value));
}

return parameters;
}

// extracts given parameter from map previusly build with explodeISCConnectString
Expand All @@ -71,10 +200,11 @@ bool getISCConnectParameter(std::map<std::string, std::string> const & m, std::s

firebird_session_backend::firebird_session_backend(
std::string const & connectString) : dbhp_(0), trhp_(0)
, decimals_as_strings_(false)
{
// extract connection parameters
std::map<std::string, std::string> params;
explodeISCConnectString(connectString, params);
std::map<std::string, std::string>
params(explodeISCConnectString(connectString));

ISC_STATUS stat[stat_size];
std::string param;
Expand Down Expand Up @@ -113,6 +243,10 @@ firebird_session_backend::firebird_session_backend(
throw_iscerror(stat);
}

if (getISCConnectParameter(params, "decimals_as_strings", param))
{
decimals_as_strings_ = param == "1" or param == "Y" or param == "y";
}
// starting transaction
begin();
}
Expand Down
3 changes: 3 additions & 0 deletions src/backends/firebird/soci-firebird.h
Expand Up @@ -312,9 +312,12 @@ struct firebird_session_backend : details::session_backend

virtual void setDPBOption(int const option, std::string const & value);

bool get_option_decimals_as_strings() { return decimals_as_strings_; }

isc_db_handle dbhp_;
isc_tr_handle trhp_;
std::string dpb_;
bool decimals_as_strings_;
};

struct firebird_backend_factory : backend_factory
Expand Down
12 changes: 9 additions & 3 deletions src/backends/firebird/statement.cpp
Expand Up @@ -579,7 +579,7 @@ long long firebird_statement_backend::get_affected_rows()
// type, its value length in bytes and the value itself.
long long row_count = 0;

for ( char* p = sql_rec_buf; p < sql_rec_buf + length; )
for ( char* p = sql_rec_buf; !row_count && p < sql_rec_buf + length; )
{
switch (*p++)
{
Expand Down Expand Up @@ -650,7 +650,10 @@ void firebird_statement_backend::describe_column(int colNum,
case SQL_LONG:
if (var->sqlscale < 0)
{
type = dt_double;
if (session_.get_option_decimals_as_strings())
type = dt_string;
else
type = dt_double;
}
else
{
Expand All @@ -660,7 +663,10 @@ void firebird_statement_backend::describe_column(int colNum,
case SQL_INT64:
if (var->sqlscale < 0)
{
type = dt_double;
if (session_.get_option_decimals_as_strings())
type = dt_string;
else
type = dt_double;
}
else
{
Expand Down

0 comments on commit 14e2a75

Please sign in to comment.