Skip to content

Commit

Permalink
Several changes:
Browse files Browse the repository at this point in the history
    - Dbo: fix firebird backend regressions
    - Dbo postgres: support timezone columns (from Bruce Toll) #2840
  • Loading branch information
Koen Deforche committed Apr 3, 2014
1 parent 39825b1 commit 2d5ecd8
Show file tree
Hide file tree
Showing 10 changed files with 193 additions and 37 deletions.
2 changes: 1 addition & 1 deletion src/Wt/Dbo/Query.C
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ std::string createWrappedQueryCountSql(const std::string& query,
bool requireSubqueryAlias)
{
if (requireSubqueryAlias)
return "select count(1) from (" + query + ") as dbocount";
return "select count(1) from (" + query + ") dbocount";
else
return "select count(1) from (" + query + ")";
}
Expand Down
2 changes: 1 addition & 1 deletion src/Wt/Dbo/Query_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -527,7 +527,7 @@ void Query<Result, DynamicBinding>::bindParameters(SqlStatement *statement)
int to = (limit_ == -1) ? (1 << 30) : (from + limit_ - 1);
field(binder, to, "to");
}
} else {//this->session_->limitQueryMethod_ == Rownum
} else if (this->session_->limitQueryMethod_ == Rownum){
if (limit_ != -1){
int v = limit_;
field(binder, v, "rownum");
Expand Down
3 changes: 2 additions & 1 deletion src/Wt/Dbo/SqlConnection
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ enum SqlDateTimeType {
enum LimitQuery{
Limit,
RowsFromTo,
Rownum
Rownum,
NotSupported
};

class SqlStatement;
Expand Down
5 changes: 3 additions & 2 deletions src/Wt/Dbo/backend/Firebird
Original file line number Diff line number Diff line change
Expand Up @@ -110,10 +110,11 @@ namespace Wt {
virtual std::string autoincrementInsertSuffix(const std::string& id) const;
virtual const char *dateTimeType(SqlDateTimeType type) const;
virtual const char *blobType() const;
virtual const char *textType() const;
virtual const char *booleanType() const;
virtual std::string textType(int size) const;
virtual const char *booleanType() const;
virtual LimitQuery limitQueryMethod() const;
virtual bool supportAlterTable() const;
virtual bool usesRowsFromTo() const {return false;}
//@}

virtual void prepareForDropTables();
Expand Down
6 changes: 3 additions & 3 deletions src/Wt/Dbo/backend/Firebird.C
Original file line number Diff line number Diff line change
Expand Up @@ -638,9 +638,9 @@ namespace Wt
impl_->m_tra->Rollback();
}

const char *Firebird::textType() const
std::string Firebird::textType(int size) const
{
return "blob sub_type text";
return std::string("blob sub_type text");
}

const char *Firebird::booleanType() const
Expand All @@ -655,7 +655,7 @@ namespace Wt

LimitQuery Firebird::limitQueryMethod() const
{
return RowsFromTo;
return RowsFromTo;
}

bool Firebird::supportAlterTable() const
Expand Down
1 change: 1 addition & 0 deletions src/Wt/Dbo/backend/Postgres
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ public:
virtual const char *blobType() const;
virtual bool supportAlterTable() const;
virtual bool supportDeferrableFKConstraint() const;
virtual bool requireSubqueryAlias() const;
//@}

private:
Expand Down
61 changes: 46 additions & 15 deletions src/Wt/Dbo/backend/Postgres.C
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,10 @@ class PostgresStatement : public SqlStatement
public:
PostgresStatement(Postgres& conn, const std::string& sql)
: conn_(conn),
sql_(convertToNumberedPlaceholders(sql))
sql_(sql)
{
convertToNumberedPlaceholders();

lastId_ = -1;
row_ = affectedRows_ = 0;
result_ = 0;
Expand Down Expand Up @@ -140,6 +142,12 @@ public:
else {
v = boost::posix_time::to_iso_extended_string(value);
v[v.find('T')] = ' ';
/*
* Add explicit timezone offset. Postgres will ignore this for a TIMESTAMP
* column, but will treat the timestamp as UTC in a TIMESTAMP WITH TIME
* ZONE column -- possibly in a legacy table.
*/
v.append("+00");
}

setValue(column, v);
Expand Down Expand Up @@ -386,8 +394,21 @@ public:
if (type == SqlDate)
*value = boost::posix_time::ptime(boost::gregorian::from_string(v),
boost::posix_time::hours(0));
else
*value = boost::posix_time::time_from_string(v);
else {
/*
* Handle timezone offset. Postgres will append a timezone offset [+-]dd
* if a column is defined as TIMESTAMP WITH TIME ZONE -- possibly
* in a legacy table. If offset is present, subtract it for UTC output.
*/
if (v.size() >= 3 && std::strchr("+-", v[v.size() - 3])) {
int hours = boost::lexical_cast<int>(v.substr(v.size() - 3));
boost::posix_time::time_duration offset
= boost::posix_time::hours(hours);
*value = boost::posix_time::time_from_string(v.substr(0, v.size() - 3))
- offset;
} else
*value = boost::posix_time::time_from_string(v);
}

DEBUG(std::cerr << this
<< " result time_duration " << column << " " << *value << std::endl);
Expand Down Expand Up @@ -449,6 +470,7 @@ private:
enum { NoFirstRow, FirstRow, NextRow, Done } state_;
std::vector<Param> params_;

int paramCount_;
char **paramValues_;
int *paramTypes_, *paramLengths_, *paramFormats_;

Expand All @@ -470,52 +492,56 @@ private:
}

void setValue(int column, const std::string& value) {
if (column >= paramCount_)
throw PostgresException("Binding too much parameters");

for (int i = (int)params_.size(); i <= column; ++i)
params_.push_back(Param());

params_[column].value = value;
params_[column].isnull = false;
}

std::string convertToNumberedPlaceholders(const std::string& sql)
void convertToNumberedPlaceholders()
{
std::stringstream result;

enum { Statement, SQuote, DQuote } state = Statement;
int placeholder = 1;

for (unsigned i = 0; i < sql.length(); ++i) {
for (unsigned i = 0; i < sql_.length(); ++i) {
switch (state) {
case Statement:
if (sql[i] == '\'')
if (sql_[i] == '\'')
state = SQuote;
else if (sql[i] == '"')
else if (sql_[i] == '"')
state = DQuote;
else if (sql[i] == '?') {
else if (sql_[i] == '?') {
result << '$' << placeholder++;
continue;
}
break;
case SQuote:
if (sql[i] == '\'') {
if (i + 1 == sql.length())
if (sql_[i] == '\'') {
if (i + 1 == sql_.length())
state = Statement;
else if (sql[i + 1] == '\'') {
result << sql[i];
else if (sql_[i + 1] == '\'') {
result << sql_[i];
++i; // skip to next
} else
state = Statement;
}
break;
case DQuote:
if (sql[i] == '"')
if (sql_[i] == '"')
state = Statement;
break;
}
result << sql[i];
result << sql_[i];
}

return result.str();
paramCount_ = placeholder - 1;
sql_ = result.str();
}
};

Expand Down Expand Up @@ -648,6 +674,11 @@ bool Postgres::supportDeferrableFKConstraint() const
return true;
}

bool Postgres::requireSubqueryAlias() const
{
return true;
}

void Postgres::startTransaction()
{
PGresult *result = PQexec(conn_, "start transaction");
Expand Down
8 changes: 6 additions & 2 deletions test/dbo/DboFixture.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ struct DboFixtureBase
logged = true;
}

connection = new dbo::backend::Firebird ("localhost",
connection = new dbo::backend::Firebird ("vendetta",
file,
"test_user", "test_pwd",
"", "", "");
Expand All @@ -94,7 +94,11 @@ struct DboFixtureBase

~DboFixtureBase()
{
session_->dropTables();
try {
session_->dropTables();
} catch (...) {

}

delete session_;
delete connectionPool_;
Expand Down
122 changes: 120 additions & 2 deletions test/dbo/DboTest.C
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,6 @@ struct DboFixture : DboFixtureBase
} catch (...) {
}

std::cout << " -------------end of droping ---------------*****--------- --- ----- ---**" << std::endl;

std::cerr << session_->tableCreationSql() << std::endl;

//session_->dropTables();
Expand Down Expand Up @@ -1835,3 +1833,123 @@ BOOST_AUTO_TEST_CASE( dbo_test21 )
delete model;
}
}

BOOST_AUTO_TEST_CASE( dbo_test22a )
{
#ifdef POSTGRES
DboFixture f;
dbo::Session *session_ = f.session_;
Wt::WDateTime datetime1 = Wt::WDateTime(Wt::WDate(2009, 10, 1),
Wt::WTime(12, 11, 31));

{
dbo::Transaction t(*session_);
session_->execute("SET TIME ZONE \"America/New_York\"");

dbo::ptr<A> a1(new A());
a1.modify()->datetime = datetime1;

session_->add(a1);
t.commit();
}

{
dbo::Transaction t(*session_);

dbo::ptr<A> a2 = session_->find<A>();

BOOST_REQUIRE(a2->datetime == datetime1);
}
#endif //POSTGRES
}

BOOST_AUTO_TEST_CASE( dbo_test22b )
{
#ifdef POSTGRES
DboFixture f;
dbo::Session *session_ = f.session_;
Wt::WDateTime datetime1 = Wt::WDateTime(Wt::WDate(2009, 10, 1),
Wt::WTime(12, 11, 31));

{
dbo::Transaction t(*session_);
session_->execute("SET TIME ZONE \"Europe/Brussels\"");

dbo::ptr<A> a1(new A());
a1.modify()->datetime = datetime1;

session_->add(a1);
t.commit();
}

{
dbo::Transaction t(*session_);

dbo::ptr<A> a2 = session_->find<A>();

BOOST_REQUIRE(a2->datetime == datetime1);
}
#endif //POSTGRES
}

BOOST_AUTO_TEST_CASE( dbo_test22c )
{
#ifdef POSTGRES
DboFixture f;
dbo::Session *session_ = f.session_;
Wt::WDateTime datetime1 = Wt::WDateTime(Wt::WDate(2009, 10, 1),
Wt::WTime(12, 11, 31));

{
dbo::Transaction t(*session_);
session_->execute("ALTER TABLE table_a ALTER COLUMN datetime "
"TYPE TIMESTAMP WITH TIME ZONE" );
session_->execute("SET TIME ZONE \"America/New_York\"");

dbo::ptr<A> a1(new A());
a1.modify()->datetime = datetime1;

session_->add(a1);
t.commit();
}

{
dbo::Transaction t(*session_);

dbo::ptr<A> a2 = session_->find<A>();

BOOST_REQUIRE(a2->datetime == datetime1);
}
#endif //POSTGRES
}

BOOST_AUTO_TEST_CASE( dbo_test22d )
{
#ifdef POSTGRES
DboFixture f;
dbo::Session *session_ = f.session_;
Wt::WDateTime datetime1 = Wt::WDateTime(Wt::WDate(2009, 10, 1),
Wt::WTime(12, 11, 31));

{
dbo::Transaction t(*session_);
session_->execute("ALTER TABLE table_a ALTER COLUMN datetime "
"TYPE TIMESTAMP WITH TIME ZONE" );
session_->execute("SET TIME ZONE \"Europe/Brussels\"");

dbo::ptr<A> a1(new A());
a1.modify()->datetime = datetime1;

session_->add(a1);
t.commit();
}

{
dbo::Transaction t(*session_);

dbo::ptr<A> a2 = session_->find<A>();

BOOST_REQUIRE(a2->datetime == datetime1);
}
#endif //POSTGRES
}
Loading

0 comments on commit 2d5ecd8

Please sign in to comment.