Commit 63bcc894 authored by Vadim Zeitlin's avatar Vadim Zeitlin

Add workaround for empty strings being null in Oracle

Oracle historically treats empty VARCHAR[2] column values as nulls, so
we need to adjust the string length unit test to provide indicators when
retrieving the value of a possibly null string and use nvl() to compute
its length to make this test pass when using this backend.
parent 2d74f9aa
......@@ -352,10 +352,10 @@ public:
// whatever we do.
virtual bool enable_std_char_padding(session&) const { return true; }
// Return the name of the function for determining the length of a string,
// i.e. "char_length" in standard SQL but often "len" or "length" in
// practice.
virtual std::string get_length_function_name() const = 0;
// Return the SQL expression giving the length of the specified string,
// i.e. "char_length(s)" in standard SQL but often "len(s)" or "length(s)"
// in practice and sometimes even worse (thanks Oracle).
virtual std::string sql_length(std::string const& s) const = 0;
virtual ~test_context_base()
{
......@@ -4219,12 +4219,9 @@ TEST_CASE_METHOD(common_tests, "String length", "[core][string][length]")
std::string s("123");
sql << "insert into soci_test(str) values(:s)", use(s);
const std::string& len_func = tc_.get_length_function_name();
std::string sout;
size_t slen;
sql << "select str," + len_func + "(str)"
" from soci_test",
sql << "select str," + tc_.sql_length("str") + " from soci_test",
into(sout), into(slen);
CHECK(slen == 3);
CHECK(sout.length() == 3);
......@@ -4241,11 +4238,14 @@ TEST_CASE_METHOD(common_tests, "String length", "[core][string][length]")
CHECK_NOTHROW( (sql << "insert into soci_test(str) values(:s)", use(v)) );
std::vector<std::string> vout(10);
// Although none of the strings here is really null, Oracle handles the
// empty string as being null, so to avoid an error about not providing
// the indicator when retrieving a null value, we must provide it here.
std::vector<indicator> vind(10);
std::vector<unsigned int> vlen(10);
sql << "select str," + len_func + "(str)"
" from soci_test"
" order by " + len_func + "(str)",
into(vout), into(vlen);
sql << "select str," + tc_.sql_length("str") + " from soci_test"
" order by " + tc_.sql_length("str"),
into(vout, vind), into(vlen);
REQUIRE(vout.size() == 3);
REQUIRE(vlen.size() == 3);
......
......@@ -96,9 +96,9 @@ public:
return "to_date('" + pi_datdt_string + "', 'YYYY-MM-DD HH24:MI:SS')";
}
virtual std::string get_length_function_name() const
virtual std::string sql_length(std::string const& s) const
{
return "length";
return "length(" + s + ")";
}
};
......
......@@ -1312,9 +1312,9 @@ class test_context : public tests::test_context_base
sql.commit();
}
virtual std::string get_length_function_name() const
virtual std::string sql_length(std::string const& s) const
{
return "char_length";
return "char_length(" + s + ")";
}
};
......
......@@ -128,9 +128,9 @@ public:
}
}
virtual std::string get_length_function_name() const
virtual std::string sql_length(std::string const& s) const
{
return "char_length";
return "char_length(" + s + ")";
}
};
......
......@@ -108,9 +108,9 @@ test_context(backend_factory const &backEnd, std::string const &connectString)
return "#" + datdt_string + "#";
}
virtual std::string get_length_function_name() const
virtual std::string sql_length(std::string const& s) const
{
return "len";
return "len(" + s + ")";
}
};
......
......@@ -94,9 +94,9 @@ public:
return "\'" + datdt_string + "\'";
}
virtual std::string get_length_function_name() const
virtual std::string sql_length(std::string const& s) const
{
return "length";
return "length(" + s + ")";
}
};
......
......@@ -161,9 +161,9 @@ public:
return true;
}
virtual std::string get_length_function_name() const
virtual std::string sql_length(std::string const& s) const
{
return "len";
return "len(" + s + ")";
}
};
......
......@@ -179,9 +179,9 @@ public:
return !m_verDriver.is_initialized() || m_verDriver < odbc_version(9, 3, 400);
}
virtual std::string get_length_function_name() const
virtual std::string sql_length(std::string const& s) const
{
return "char_length";
return "char_length(" + s + ")";
}
private:
......
......@@ -1556,9 +1556,12 @@ public:
return "to_date('" + datdt_string + "', 'YYYY-MM-DD HH24:MI:SS')";
}
virtual std::string get_length_function_name() const
virtual std::string sql_length(std::string const& s) const
{
return "length";
// Oracle treats empty strings as NULLs, but we want to return the
// length of 0 for them for consistency with the other backends, so use
// nvl() explicitly to achieve this.
return "nvl(length(" + s + "), 0)";
}
};
......
......@@ -1173,9 +1173,9 @@ public:
return false;
}
virtual std::string get_length_function_name() const
virtual std::string sql_length(std::string const& s) const
{
return "char_length";
return "char_length(" + s + ")";
}
};
......
......@@ -380,9 +380,9 @@ public:
return false;
}
virtual std::string get_length_function_name() const
virtual std::string sql_length(std::string const& s) const
{
return "length";
return "length(" + s + ")";
}
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment