summaryrefslogtreecommitdiff
path: root/connectivity/source/drivers/firebird/PreparedStatement.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'connectivity/source/drivers/firebird/PreparedStatement.cxx')
-rw-r--r--connectivity/source/drivers/firebird/PreparedStatement.cxx174
1 files changed, 83 insertions, 91 deletions
diff --git a/connectivity/source/drivers/firebird/PreparedStatement.cxx b/connectivity/source/drivers/firebird/PreparedStatement.cxx
index ce951d639bae..f761365fb5bb 100644
--- a/connectivity/source/drivers/firebird/PreparedStatement.cxx
+++ b/connectivity/source/drivers/firebird/PreparedStatement.cxx
@@ -193,41 +193,36 @@ void SAL_CALL OPreparedStatement::setString(sal_Int32 nParameterIndex,
checkParameterIndex(nParameterIndex);
setParameterNull(nParameterIndex, false);
- OString str = OUStringToOString(sInput , RTL_TEXTENCODING_UTF8 );
-
XSQLVAR* pVar = m_pInSqlda->sqlvar + (nParameterIndex - 1);
+ ColumnTypeInfo columnType(*pVar);
- int dtype = (pVar->sqltype & ~1); // drop flag bit for now
-
- if (str.getLength() > pVar->sqllen)
- str = str.copy(0, pVar->sqllen);
-
- switch (dtype) {
- case SQL_VARYING:
+ switch (auto sdbcType = columnType.getSdbcType()) {
+ case DataType::VARCHAR:
+ case DataType::CHAR:
{
- const sal_Int32 max_varchar_len = 0xFFFF;
- // First 2 bytes indicate string size
- if (str.getLength() > max_varchar_len)
+ OString str = OUStringToOString(sInput, RTL_TEXTENCODING_UTF8);
+ const ISC_SHORT nLength = std::min(str.getLength(), static_cast<sal_Int32>(pVar->sqllen));
+ int offset = 0;
+ if (sdbcType == DataType::VARCHAR)
{
- str = str.copy(0, max_varchar_len);
+ // First 2 bytes indicate string size
+ static_assert(sizeof(nLength) == 2, "must match dest memcpy len");
+ memcpy(pVar->sqldata, &nLength, 2);
+ offset = 2;
}
- const sal_uInt16 nLength = str.getLength();
- static_assert(sizeof(nLength) == 2, "must match dest memcpy len");
- memcpy(pVar->sqldata, &nLength, 2);
// Actual data
- memcpy(pVar->sqldata + 2, str.getStr(), str.getLength());
+ memcpy(pVar->sqldata + offset, str.getStr(), nLength);
+ if (sdbcType == DataType::CHAR)
+ {
+ // Fill remainder with spaces
+ memset(pVar->sqldata + offset + nLength, ' ', pVar->sqllen - nLength);
+ }
break;
}
- case SQL_TEXT:
- memcpy(pVar->sqldata, str.getStr(), str.getLength());
- // Fill remainder with spaces
- memset(pVar->sqldata + str.getLength(), ' ', pVar->sqllen - str.getLength());
- break;
- case SQL_BLOB: // Clob
- assert( pVar->sqlsubtype == static_cast<short>(BlobSubtype::Clob) );
+ case DataType::CLOB:
setClob(nParameterIndex, sInput );
break;
- case SQL_SHORT:
+ case DataType::SMALLINT:
{
sal_Int32 int32Value = sInput.toInt32();
if ( (int32Value < std::numeric_limits<sal_Int16>::min()) ||
@@ -241,31 +236,38 @@ void SAL_CALL OPreparedStatement::setString(sal_Int32 nParameterIndex,
setShort(nParameterIndex, int32Value);
break;
}
- case SQL_LONG:
+ case DataType::INTEGER:
{
sal_Int32 int32Value = sInput.toInt32();
setInt(nParameterIndex, int32Value);
break;
}
- case SQL_INT64:
+ case DataType::BIGINT:
{
sal_Int64 int64Value = sInput.toInt64();
setLong(nParameterIndex, int64Value);
break;
}
- case SQL_FLOAT:
+ case DataType::FLOAT:
{
float floatValue = sInput.toFloat();
setFloat(nParameterIndex, floatValue);
break;
}
- case SQL_BOOLEAN:
+ case DataType::DOUBLE:
+ setDouble(nParameterIndex, sInput.toDouble());
+ break;
+ case DataType::NUMERIC:
+ case DataType::DECIMAL:
+ return setObjectWithInfo(nParameterIndex, Any{ sInput }, sdbcType, columnType.getScale());
+ break;
+ case DataType::BOOLEAN:
{
bool boolValue = sInput.toBoolean();
setBoolean(nParameterIndex, boolValue);
break;
}
- case SQL_NULL:
+ case DataType::SQLNULL:
{
// See https://www.firebirdsql.org/file/documentation/html/en/refdocs/fblangref25/firebird-25-language-reference.html#fblangref25-datatypes-special-sqlnull
pVar->sqldata = nullptr;
@@ -359,32 +361,59 @@ namespace {
* the information of where is the fractional part from a
* string representation of a number. (e.g. 54.654 -> 54654)
*/
-sal_Int64 toNumericWithoutDecimalPlace(const OUString& sSource)
+sal_Int64 toNumericWithoutDecimalPlace(const Any& x, sal_Int32 scale)
{
- OUString sNumber(sSource);
-
- // cut off leading 0 eventually ( eg. 0.567 -> .567)
- (void)sSource.startsWith("0", &sNumber);
+ if (double value = 0; x >>= value)
+ return static_cast<sal_Int64>(value * pow10Integer(scale) + 0.5);
- sal_Int32 nDotIndex = sNumber.indexOf('.');
+ // Can't use conversion of string to double, because it could be not representable in double
- if( nDotIndex < 0)
+ OUString s;
+ x >>= s;
+ std::u16string_view num(o3tl::trim(s));
+ size_t end = num.starts_with('-') ? 1 : 0;
+ for (bool seenDot = false; end < num.size(); ++end)
{
- return sNumber.toInt64(); // no dot -> it's an integer
+ if (num[end] == '.')
+ {
+ if (seenDot)
+ break;
+ seenDot = true;
+ }
+ else if (!rtl::isAsciiDigit(num[end]))
+ break;
}
- else
+ num = num.substr(0, end);
+
+ // fill in the number with nulls in fractional part.
+ // We need this because e.g. 0.450 != 0.045 despite
+ // their scale is equal
+ OUStringBuffer buffer(num);
+ if (auto dotPos = num.find('.'); dotPos != std::u16string_view::npos) // there is a dot
{
- // remove dot
- OUStringBuffer sBuffer(15);
- if(nDotIndex > 0)
+ scale -= num.substr(dotPos + 1).size();
+ buffer.remove(dotPos, 1);
+ if (scale < 0)
{
- sBuffer.append(sNumber.subView(0, nDotIndex));
+ assert(buffer.getLength() >= -scale);
+ buffer.truncate(buffer.getLength() + scale);
+ scale = 0;
}
- sBuffer.append(sNumber.subView(nDotIndex + 1));
- return o3tl::toInt64(sBuffer);
}
+ for (sal_Int32 i = 0; i < scale; ++i)
+ buffer.append('0');
+
+ return OUString::unacquired(buffer).toInt64();
}
+double toDouble(const Any& x)
+{
+ if (double value = 0; x >>= value)
+ return value;
+ OUString s;
+ x >>= s;
+ return s.toDouble();
+}
}
//----- XParameters -----------------------------------------------------------
@@ -806,57 +835,20 @@ void SAL_CALL OPreparedStatement::setObjectWithInfo( sal_Int32 parameterIndex, c
if(sqlType == DataType::DECIMAL || sqlType == DataType::NUMERIC)
{
- double dbValue =0.0;
- OUString sValue;
- if( x >>= dbValue )
- {
- // truncate and round to 'scale' number of decimal places
- sValue = OUString::number( std::floor((dbValue * pow10Integer(scale)) + .5) / pow10Integer(scale) );
- }
- else
- {
- x >>= sValue;
- }
-
- // fill in the number with nulls in fractional part.
- // We need this because e.g. 0.450 != 0.045 despite
- // their scale is equal
- OUStringBuffer sBuffer(15);
- sBuffer.append(sValue);
- if(sValue.indexOf('.') != -1) // there is a dot
- {
- for(sal_Int32 i=sValue.subView(sValue.indexOf('.')+1).size(); i<scale;i++)
- {
- sBuffer.append('0');
- }
- }
- else
- {
- for (sal_Int32 i=0; i<scale; i++)
- {
- sBuffer.append('0');
- }
- }
-
- sValue = sBuffer.makeStringAndClear();
switch(dType)
{
case SQL_SHORT:
- setValue< sal_Int16 >(parameterIndex,
- static_cast<sal_Int16>( toNumericWithoutDecimalPlace(sValue) ),
- dType);
- break;
+ return setValue(parameterIndex,
+ static_cast<sal_Int16>(toNumericWithoutDecimalPlace(x, scale)),
+ dType);
case SQL_LONG:
- case SQL_DOUBLE:
- setValue< sal_Int32 >(parameterIndex,
- static_cast<sal_Int32>( toNumericWithoutDecimalPlace(sValue) ),
- dType);
- break;
+ return setValue(parameterIndex,
+ static_cast<sal_Int32>(toNumericWithoutDecimalPlace(x, scale)),
+ dType);
case SQL_INT64:
- setValue< sal_Int64 >(parameterIndex,
- toNumericWithoutDecimalPlace(sValue),
- dType);
- break;
+ return setValue(parameterIndex, toNumericWithoutDecimalPlace(x, scale), dType);
+ case SQL_DOUBLE:
+ return setValue(parameterIndex, toDouble(x), dType);
default:
SAL_WARN("connectivity.firebird",
"No Firebird sql type found for numeric or decimal types");