summaryrefslogtreecommitdiff
path: root/connectivity
diff options
context:
space:
mode:
authorWastack <btomi96@gmail.com>2016-10-31 16:32:54 +0100
committerLionel Elie Mamane <lionel@mamane.lu>2016-11-10 09:37:12 +0000
commit21cc1826c758bb71bb0cfa055b3bb51a38bc2acb (patch)
tree7142453461e05a9320d0f15de9dfb12dd336e8b3 /connectivity
parent9357e99450974a4bea5946129af126469199797b (diff)
WiP tdf#74172 use DECIMAL and NUMERIC data types
Change-Id: I917cdf6e8d3ebfa7c9e4a52ca61adc5b8707ecfc Reviewed-on: https://gerrit.libreoffice.org/30447 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Lionel Elie Mamane <lionel@mamane.lu>
Diffstat (limited to 'connectivity')
-rw-r--r--connectivity/source/drivers/firebird/Column.cxx1
-rw-r--r--connectivity/source/drivers/firebird/DatabaseMetaData.cxx74
-rw-r--r--connectivity/source/drivers/firebird/PreparedStatement.cxx103
-rw-r--r--connectivity/source/drivers/firebird/PreparedStatement.hxx7
-rw-r--r--connectivity/source/drivers/firebird/ResultSet.cxx82
-rw-r--r--connectivity/source/drivers/firebird/ResultSet.hxx3
-rw-r--r--connectivity/source/drivers/firebird/ResultSetMetaData.cxx42
-rw-r--r--connectivity/source/drivers/firebird/Util.cxx46
-rw-r--r--connectivity/source/drivers/firebird/Util.hxx5
9 files changed, 324 insertions, 39 deletions
diff --git a/connectivity/source/drivers/firebird/Column.cxx b/connectivity/source/drivers/firebird/Column.cxx
index 28ce9ac0edb8..38c367cfcc43 100644
--- a/connectivity/source/drivers/firebird/Column.cxx
+++ b/connectivity/source/drivers/firebird/Column.cxx
@@ -24,6 +24,7 @@ Column::Column()
void Column::construct()
{
+ OColumn::construct();
m_sAutoIncrement = "GENERATED BY DEFAULT AS IDENTITY";
registerProperty(OMetaConnection::getPropMap().getNameByIndex(
PROPERTY_ID_AUTOINCREMENTCREATION),
diff --git a/connectivity/source/drivers/firebird/DatabaseMetaData.cxx b/connectivity/source/drivers/firebird/DatabaseMetaData.cxx
index f5b1a7e977a5..bb26401b3f5d 100644
--- a/connectivity/source/drivers/firebird/DatabaseMetaData.cxx
+++ b/connectivity/source/drivers/firebird/DatabaseMetaData.cxx
@@ -34,6 +34,7 @@
#include <com/sun/star/sdbc/XRow.hpp>
#include <com/sun/star/sdbc/KeyRule.hpp>
#include <com/sun/star/sdbc/Deferrability.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
using namespace connectivity::firebird;
using namespace com::sun::star;
@@ -902,7 +903,7 @@ uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getTypeInfo()
// SQL_TEXT
aRow[1] = new ORowSetValueDecorator(OUString("CHAR"));
- aRow[2] = new ORowSetValueDecorator(getColumnTypeFromFBType(SQL_TEXT));
+ aRow[2] = new ORowSetValueDecorator(getColumnTypeFromFBType(SQL_TEXT, 0));
aRow[3] = new ORowSetValueDecorator(sal_Int16(32767)); // Prevision = max length
aRow[6] = new ORowSetValueDecorator(OUString("length")); // Create Params
aRow[9] = new ORowSetValueDecorator(
@@ -914,7 +915,7 @@ uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getTypeInfo()
// SQL_VARYING
aRow[1] = new ORowSetValueDecorator(OUString("VARCHAR"));
- aRow[2] = new ORowSetValueDecorator(getColumnTypeFromFBType(SQL_VARYING));
+ aRow[2] = new ORowSetValueDecorator(getColumnTypeFromFBType(SQL_VARYING, 0));
aRow[3] = new ORowSetValueDecorator(sal_Int16(32767)); // Prevision = max length
aRow[6] = new ORowSetValueDecorator(OUString("length")); // Create Params
aRow[9] = new ORowSetValueDecorator(
@@ -935,44 +936,62 @@ uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getTypeInfo()
}
// SQL_SHORT
aRow[1] = new ORowSetValueDecorator(OUString("SMALLINT"));
- aRow[2] = new ORowSetValueDecorator(getColumnTypeFromFBType(SQL_SHORT));
+ aRow[2] = new ORowSetValueDecorator(getColumnTypeFromFBType(SQL_SHORT, 0));
aRow[3] = new ORowSetValueDecorator(sal_Int16(5)); // Prevision
aResults.push_back(aRow);
// SQL_LONG
aRow[1] = new ORowSetValueDecorator(OUString("INTEGER"));
- aRow[2] = new ORowSetValueDecorator(getColumnTypeFromFBType(SQL_LONG));
+ aRow[2] = new ORowSetValueDecorator(getColumnTypeFromFBType(SQL_LONG, 0));
aRow[3] = new ORowSetValueDecorator(sal_Int16(10)); // Precision
aResults.push_back(aRow);
// SQL_INT64
aRow[1] = new ORowSetValueDecorator(OUString("BIGINT"));
- aRow[2] = new ORowSetValueDecorator(getColumnTypeFromFBType(SQL_INT64));
+ aRow[2] = new ORowSetValueDecorator(getColumnTypeFromFBType(SQL_INT64, 0));
aRow[3] = new ORowSetValueDecorator(sal_Int16(20)); // Precision
aResults.push_back(aRow);
// Decimal Types common
{
- aRow[6] = new ORowSetValueDecorator(); // Create Params
aRow[9] = new ORowSetValueDecorator(
sal_Int16(ColumnSearch::FULL)); // Searchable
aRow[12] = new ORowSetValueDecorator(true); // Autoincrement
}
+
+ aRow[6] = new ORowSetValueDecorator(OUString("PRECISION,SCALE")); // Create params
+ // NUMERIC
+ aRow[1] = new ORowSetValueDecorator(OUString("NUMERIC"));
+ aRow[2] = new ORowSetValueDecorator(DataType::NUMERIC);
+ aRow[3] = new ORowSetValueDecorator(sal_Int16(15)); // Precision
+ aRow[14] = new ORowSetValueDecorator(sal_Int16(1)); // Minimum scale
+ aRow[15] = new ORowSetValueDecorator(sal_Int16(15)); // Max scale
+ aResults.push_back(aRow);
+ // DECIMAL
+ aRow[1] = new ORowSetValueDecorator(OUString("DECIMAL"));
+ aRow[2] = new ORowSetValueDecorator(DataType::DECIMAL);
+ aRow[3] = new ORowSetValueDecorator(sal_Int16(15)); // Precision
+ aRow[14] = new ORowSetValueDecorator(sal_Int16(1)); // Minimum scale
+ aRow[15] = new ORowSetValueDecorator(sal_Int16(15)); // Max scale
+ aResults.push_back(aRow);
+
+ aRow[6] = new ORowSetValueDecorator(); // Create Params
// SQL_FLOAT
aRow[1] = new ORowSetValueDecorator(OUString("FLOAT"));
- aRow[2] = new ORowSetValueDecorator(getColumnTypeFromFBType(SQL_FLOAT));
+ aRow[2] = new ORowSetValueDecorator(getColumnTypeFromFBType(SQL_FLOAT, 0));
aRow[3] = new ORowSetValueDecorator(sal_Int16(7)); // Precision
aRow[14] = new ORowSetValueDecorator(sal_Int16(1)); // Minimum scale
aRow[15] = new ORowSetValueDecorator(sal_Int16(7)); // Max scale
aResults.push_back(aRow);
// SQL_DOUBLE
aRow[1] = new ORowSetValueDecorator(OUString("DOUBLE PRECISION"));
- aRow[2] = new ORowSetValueDecorator(getColumnTypeFromFBType(SQL_DOUBLE));
+ aRow[2] = new ORowSetValueDecorator(getColumnTypeFromFBType(SQL_DOUBLE, 0));
aRow[3] = new ORowSetValueDecorator(sal_Int16(15)); // Precision
aRow[14] = new ORowSetValueDecorator(sal_Int16(1)); // Minimum scale
aRow[15] = new ORowSetValueDecorator(sal_Int16(15)); // Max scale
aResults.push_back(aRow);
+
// // SQL_D_FLOAT
-// aRow[1] = new ORowSetValueDecorator(getColumnTypeNameFromFBType(SQL_D_FLOAT));
-// aRow[2] = new ORowSetValueDecorator(getColumnTypeFromFBType(SQL_D_FLOAT));
+// aRow[1] = new ORowSetValueDecorator(getColumnTypeNameFromFBType(SQL_D_FLOAT, 0));
+// aRow[2] = new ORowSetValueDecorator(getColumnTypeFromFBType(SQL_D_FLOAT, 0));
// aRow[3] = new ORowSetValueDecorator(sal_Int16(15)); // Precision
// aRow[14] = new ORowSetValueDecorator(sal_Int16(1)); // Minimum scale
// aRow[15] = new ORowSetValueDecorator(sal_Int16(15)); // Max scale
@@ -982,7 +1001,7 @@ uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getTypeInfo()
// SQL_TIMESTAMP
// TODO: precision?
aRow[1] = new ORowSetValueDecorator(OUString("TIMESTAMP"));
- aRow[2] = new ORowSetValueDecorator(getColumnTypeFromFBType(SQL_TIMESTAMP));
+ aRow[2] = new ORowSetValueDecorator(getColumnTypeFromFBType(SQL_TIMESTAMP, 0));
aRow[3] = new ORowSetValueDecorator(sal_Int32(8)); // Prevision = max length
aRow[6] = new ORowSetValueDecorator(); // Create Params
aRow[9] = new ORowSetValueDecorator(
@@ -995,7 +1014,7 @@ uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getTypeInfo()
// SQL_TYPE_TIME
// TODO: precision?
aRow[1] = new ORowSetValueDecorator(OUString("TIME"));
- aRow[2] = new ORowSetValueDecorator(getColumnTypeFromFBType(SQL_TYPE_TIME));
+ aRow[2] = new ORowSetValueDecorator(getColumnTypeFromFBType(SQL_TYPE_TIME, 0));
aRow[3] = new ORowSetValueDecorator(sal_Int32(8)); // Prevision = max length
aRow[6] = new ORowSetValueDecorator(); // Create Params
aRow[9] = new ORowSetValueDecorator(
@@ -1008,7 +1027,7 @@ uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getTypeInfo()
// SQL_TYPE_DATE
// TODO: precision?
aRow[1] = new ORowSetValueDecorator(OUString("DATE"));
- aRow[2] = new ORowSetValueDecorator(getColumnTypeFromFBType(SQL_TYPE_DATE));
+ aRow[2] = new ORowSetValueDecorator(getColumnTypeFromFBType(SQL_TYPE_DATE, 0));
aRow[3] = new ORowSetValueDecorator(sal_Int32(8)); // Prevision = max length
aRow[6] = new ORowSetValueDecorator(); // Create Params
aRow[9] = new ORowSetValueDecorator(
@@ -1021,7 +1040,7 @@ uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getTypeInfo()
// SQL_BLOB
// TODO: precision?
aRow[1] = new ORowSetValueDecorator(OUString("BLOB"));
- aRow[2] = new ORowSetValueDecorator(getColumnTypeFromFBType(SQL_BLOB));
+ aRow[2] = new ORowSetValueDecorator(getColumnTypeFromFBType(SQL_BLOB, 0));
aRow[3] = new ORowSetValueDecorator(sal_Int32(0)); // Prevision = max length
aRow[6] = new ORowSetValueDecorator(); // Create Params
aRow[9] = new ORowSetValueDecorator(
@@ -1133,13 +1152,15 @@ uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getColumns(
"relfields.RDB$DEFAULT_VALUE, " // 4
"relfields.RDB$FIELD_POSITION, "// 5
"fields.RDB$FIELD_TYPE, " // 6
- "fields.RDB$FIELD_LENGTH, " // 7
- "fields.RDB$FIELD_PRECISION, " // 8
+ "fields.RDB$FIELD_SUB_TYPE, " // 7
+ "fields.RDB$FIELD_LENGTH, " // 8
+ "fields.RDB$FIELD_PRECISION, " // 9
+ "fields.RDB$FIELD_SCALE, " // 10
// Specifically use relfields null flag -- the one in fields is used
// for domains, whether a specific field is nullable is set in relfields,
// this is also the one we manually fiddle when changin NULL/NOT NULL
// (see Table.cxx)
- "relfields.RDB$NULL_FLAG " // 9
+ "relfields.RDB$NULL_FLAG " // 11
"FROM RDB$RELATION_FIELDS relfields "
"JOIN RDB$FIELDS fields "
"on (fields.RDB$FIELD_NAME = relfields.RDB$FIELD_SOURCE) "
@@ -1192,9 +1213,10 @@ uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getColumns(
aCurrentRow[4] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(2)));
// 5. Datatype
short aType = getFBTypeFromBlrType(xRow->getShort(6));
- aCurrentRow[5] = new ORowSetValueDecorator(getColumnTypeFromFBType(aType));
+ short aSubType = xRow->getShort(7);
+ aCurrentRow[5] = new ORowSetValueDecorator(getColumnTypeFromFBType(aType, aSubType));
// 6. Typename (SQL_*)
- aCurrentRow[6] = new ORowSetValueDecorator(getColumnTypeNameFromFBType(aType));
+ aCurrentRow[6] = new ORowSetValueDecorator(getColumnTypeNameFromFBType(aType, aSubType));
// 7. Column Sizes
{
@@ -1203,7 +1225,7 @@ uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getColumns(
{
case SQL_TEXT:
case SQL_VARYING:
- aColumnSize = xRow->getShort(7);
+ aColumnSize = xRow->getShort(8);
break;
case SQL_SHORT:
case SQL_LONG:
@@ -1212,7 +1234,7 @@ uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getColumns(
case SQL_D_FLOAT:
case SQL_INT64:
case SQL_QUAD:
- aColumnSize = xRow->getShort(8);
+ aColumnSize = xRow->getShort(9);
break;
case SQL_TIMESTAMP:
case SQL_BLOB:
@@ -1226,12 +1248,12 @@ uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getColumns(
aCurrentRow[7] = new ORowSetValueDecorator(aColumnSize);
}
- // 9. Decimal Digits
- // TODO: implement
- aCurrentRow[9] = new ORowSetValueDecorator(sal_Int32(0));
+ // 9. Decimal digits (scale)
+ // fb stores a negative number
+ aCurrentRow[9] = new ORowSetValueDecorator( (sal_Int16) -(xRow->getShort(10)) );
// 11. Nullable
- if (xRow->getShort(9))
+ if (xRow->getShort(11))
{
aCurrentRow[11] = new ORowSetValueDecorator(ColumnValue::NO_NULLS);
}
@@ -1265,7 +1287,7 @@ uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getColumns(
// 16. Bytes in Column for char
if (aType == SQL_TEXT)
{
- aCurrentRow[16] = new ORowSetValueDecorator(xRow->getShort(7));
+ aCurrentRow[16] = new ORowSetValueDecorator(xRow->getShort(8));
}
else if (aType == SQL_VARYING)
{
diff --git a/connectivity/source/drivers/firebird/PreparedStatement.cxx b/connectivity/source/drivers/firebird/PreparedStatement.cxx
index 13402b86d1dd..f9adc0bdb0fc 100644
--- a/connectivity/source/drivers/firebird/PreparedStatement.cxx
+++ b/connectivity/source/drivers/firebird/PreparedStatement.cxx
@@ -29,6 +29,7 @@
#include <osl/diagnose.h>
#include <propertyids.hxx>
#include <time.h>
+#include <connectivity/dbtools.hxx>
#include <com/sun/star/sdbc/DataType.hpp>
#include <com/sun/star/lang/DisposedException.hpp>
@@ -317,6 +318,32 @@ Reference< XResultSet > SAL_CALL OPreparedStatement::executeQuery()
return m_xResultSet;
}
+sal_Int64 OPreparedStatement::toNumericWithoutDecimalPlace(const OUString& sSource)
+{
+ OUString sNumber(sSource);
+
+ // cut off leading 0 eventually ( eg. 0.567 -> .567)
+ sSource.startsWith(OUString("0"), &sNumber);
+
+ sal_Int32 nDotIndex = sNumber.indexOf((sal_Unicode)'.');
+
+ if( nDotIndex < 0)
+ {
+ return sNumber.toInt64(); // no dot -> it's an integer
+ }
+ else
+ {
+ // remove dot
+ OUStringBuffer sBuffer(15);
+ if(nDotIndex > 0)
+ {
+ sBuffer.append(sNumber.copy(0, nDotIndex));
+ }
+ sBuffer.append(sNumber.copy(nDotIndex + 1));
+ return sBuffer.makeStringAndClear().toInt64();
+ }
+}
+
//----- XParameters -----------------------------------------------------------
void SAL_CALL OPreparedStatement::setNull(sal_Int32 nIndex, sal_Int32 /*nSqlType*/)
throw(SQLException, RuntimeException, std::exception)
@@ -561,13 +588,81 @@ void SAL_CALL OPreparedStatement::setRef( sal_Int32 parameterIndex, const Refere
void SAL_CALL OPreparedStatement::setObjectWithInfo( sal_Int32 parameterIndex, const Any& x, sal_Int32 sqlType, sal_Int32 scale ) throw(SQLException, RuntimeException, std::exception)
{
- (void) parameterIndex;
- (void) x;
- (void) sqlType;
- (void) scale;
checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed);
::osl::MutexGuard aGuard( m_aMutex );
+ XSQLVAR* pVar = m_pInSqlda->sqlvar + (parameterIndex - 1);
+ int dType = (pVar->sqltype & ~1); // drop null flag
+
+ if(sqlType == DataType::DECIMAL || sqlType == DataType::NUMERIC)
+ {
+ double myDouble=0.0;
+ OUString myString;
+ if( x >>= myDouble )
+ {
+ myString = OUString::number( myDouble );
+ }
+ else
+ {
+ x >>= myString;
+ }
+
+ // 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(myString);
+ if(myString.indexOf('.') != -1) // there is a dot
+ {
+ for(sal_Int32 i=myString.copy(myString.indexOf('.')+1).getLength(); i<scale;i++)
+ {
+ sBuffer.append('0');
+ }
+ }
+ else
+ {
+ for (sal_Int32 i=0; i<scale; i++)
+ {
+ sBuffer.append('0');
+ }
+ }
+ myString = sBuffer.makeStringAndClear();
+ // set value depending on type
+ sal_Int16 n16Value = 0;
+ sal_Int32 n32Value = 0;
+ sal_Int64 n64Value = 0;
+ switch(dType)
+ {
+ case SQL_SHORT:
+ n16Value = (sal_Int16) toNumericWithoutDecimalPlace(myString);
+ setValue< sal_Int16 >(parameterIndex,
+ n16Value,
+ dType);
+ break;
+ case SQL_LONG:
+ case SQL_DOUBLE: // TODO FIXME 32 bits
+ n32Value = (sal_Int32) toNumericWithoutDecimalPlace(myString);
+ setValue< sal_Int32 >(parameterIndex,
+ n32Value,
+ dType);
+ break;
+ case SQL_INT64:
+ n64Value = (sal_Int64) toNumericWithoutDecimalPlace(myString);
+ setValue< sal_Int64 >(parameterIndex,
+ n64Value,
+ dType);
+ break;
+ default:
+ SAL_WARN("connectivity.firebird",
+ "No Firebird sql type found for numeric or decimal types");
+ ::dbtools::setObjectWithInfo(this,parameterIndex,x,sqlType,scale);
+ }
+ }
+ else
+ {
+ ::dbtools::setObjectWithInfo(this,parameterIndex,x,sqlType,scale);
+ }
+
}
diff --git a/connectivity/source/drivers/firebird/PreparedStatement.hxx b/connectivity/source/drivers/firebird/PreparedStatement.hxx
index d98e46d2950c..04ba79227b90 100644
--- a/connectivity/source/drivers/firebird/PreparedStatement.hxx
+++ b/connectivity/source/drivers/firebird/PreparedStatement.hxx
@@ -79,6 +79,13 @@ namespace connectivity
*/
void closeBlobAfterWriting(isc_blob_handle& rBlobHandle);
+ /**
+ * Take out the number part of a fix point decimal without
+ * the information of where is the fracional part from a
+ * string representation of a number. (e.g. 54.654 -> 54654)
+ */
+ sal_Int64 toNumericWithoutDecimalPlace(const OUString& sSource);
+
protected:
virtual void SAL_CALL setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,
const css::uno::Any& rValue)
diff --git a/connectivity/source/drivers/firebird/ResultSet.cxx b/connectivity/source/drivers/firebird/ResultSet.cxx
index 916f7df49f69..71744187c8b0 100644
--- a/connectivity/source/drivers/firebird/ResultSet.cxx
+++ b/connectivity/source/drivers/firebird/ResultSet.cxx
@@ -377,6 +377,58 @@ bool OResultSet::isNull(const sal_Int32 nColumnIndex)
}
template <typename T>
+OUString OResultSet::makeNumericString(const sal_Int32 nColumnIndex)
+{
+ // minus because firebird stores scale as a negative number
+ int nDecimalCount = -(m_pSqlda->sqlvar[nColumnIndex-1].sqlscale);
+ if(nDecimalCount < 0)
+ {
+ // scale should be always positive
+ assert(false);
+ return OUString();
+ }
+
+ OUStringBuffer sRetBuffer;
+ T nAllDigits = *reinterpret_cast<T*>(m_pSqlda->sqlvar[nColumnIndex-1].sqldata);
+ sal_Int64 nDecimalCountExp = pow10Integer(nDecimalCount);
+
+ if(nAllDigits < 0)
+ {
+ sRetBuffer.append('-');
+ nAllDigits = -nAllDigits; // abs
+ }
+
+ sRetBuffer.append((sal_Int64) (nAllDigits / nDecimalCountExp) );
+ if( nDecimalCount > 0)
+ {
+ sRetBuffer.append('.');
+
+ sal_Int64 nFractionalPart = nAllDigits % nDecimalCountExp;
+
+ int iCount = 0; // digit count
+ sal_Int64 nFracTemp = nFractionalPart;
+ while(nFracTemp>0)
+ {
+ nFracTemp /= 10;
+ iCount++;
+ }
+
+ int nMissingNulls = nDecimalCount - iCount;
+
+ // append nulls after dot and before nFractionalPart
+ for(int i=0; i<nMissingNulls; i++)
+ {
+ sRetBuffer.append('0');
+ }
+
+ // the rest
+ sRetBuffer.append(nFractionalPart);
+ }
+
+ return sRetBuffer.makeStringAndClear();
+}
+
+template <typename T>
T OResultSet::retrieveValue(const sal_Int32 nColumnIndex, const ISC_SHORT nType)
{
if ((m_bWasNull = isNull(nColumnIndex)))
@@ -398,18 +450,25 @@ ORowSetValue OResultSet::retrieveValue(const sal_Int32 nColumnIndex, const ISC_S
//
// Basically we just have to map to the correct direct request and
// ORowSetValue does the rest for us here.
+ int nSqlSubType = m_pSqlda->sqlvar[nColumnIndex-1].sqlsubtype;
switch (m_pSqlda->sqlvar[nColumnIndex-1].sqltype & ~1)
{
case SQL_TEXT:
case SQL_VARYING:
return getString(nColumnIndex);
case SQL_SHORT:
+ if(nSqlSubType == 0 || nSqlSubType == 1) //numeric or decimal
+ return getString(nColumnIndex);
return getShort(nColumnIndex);
case SQL_LONG:
+ if(nSqlSubType == 0 || nSqlSubType == 1) //numeric or decimal
+ return getString(nColumnIndex);
return getInt(nColumnIndex);
case SQL_FLOAT:
return getFloat(nColumnIndex);
case SQL_DOUBLE:
+ if(nSqlSubType == 0 || nSqlSubType == 1) //numeric or decimal
+ return getString(nColumnIndex);
return getDouble(nColumnIndex);
case SQL_D_FLOAT:
return getFloat(nColumnIndex);
@@ -420,6 +479,8 @@ ORowSetValue OResultSet::retrieveValue(const sal_Int32 nColumnIndex, const ISC_S
case SQL_TYPE_DATE:
return getDate(nColumnIndex);
case SQL_INT64:
+ if(nSqlSubType == 0 || nSqlSubType == 1) //numeric or decimal
+ return getString(nColumnIndex);
return getLong(nColumnIndex);
case SQL_BLOB:
case SQL_NULL:
@@ -502,6 +563,7 @@ OUString OResultSet::retrieveValue(const sal_Int32 nColumnIndex, const ISC_SHORT
{
// &~1 to remove the "can contain NULL" indicator
int aSqlType = m_pSqlda->sqlvar[nColumnIndex-1].sqltype & ~1;
+ int aSqlSubType = m_pSqlda->sqlvar[nColumnIndex-1].sqlsubtype;
if (aSqlType == SQL_TEXT )
{
return OUString(m_pSqlda->sqlvar[nColumnIndex-1].sqldata,
@@ -517,6 +579,26 @@ OUString OResultSet::retrieveValue(const sal_Int32 nColumnIndex, const ISC_SHORT
aLength,
RTL_TEXTENCODING_UTF8);
}
+ else if ((aSqlType == SQL_SHORT || aSqlType == SQL_LONG
+ || aSqlType == SQL_DOUBLE || aSqlType == SQL_INT64)
+ && (aSqlSubType == 1 || aSqlSubType == 2))
+ {
+ // decimal and numeric types
+ switch(aSqlType)
+ {
+ case SQL_SHORT:
+ return makeNumericString<sal_Int16>(nColumnIndex);
+ case SQL_LONG:
+ return makeNumericString<sal_Int32>(nColumnIndex);
+ case SQL_DOUBLE:
+ // TODO FIXME 64 bits?
+ case SQL_INT64:
+ return makeNumericString<sal_Int64>(nColumnIndex);
+ default:
+ assert(false);
+ return OUString(); // never reached
+ }
+ }
else
{
return retrieveValue< ORowSetValue >(nColumnIndex, 0);
diff --git a/connectivity/source/drivers/firebird/ResultSet.hxx b/connectivity/source/drivers/firebird/ResultSet.hxx
index fb4d929a8cb7..347c7ea80f71 100644
--- a/connectivity/source/drivers/firebird/ResultSet.hxx
+++ b/connectivity/source/drivers/firebird/ResultSet.hxx
@@ -101,6 +101,9 @@ namespace connectivity
bool isNull(const sal_Int32 nColumnIndex);
+ template <typename T> OUString makeNumericString(
+ const sal_Int32 nColumnIndex);
+
template <typename T> T retrieveValue(const sal_Int32 nColumnIndex,
const ISC_SHORT nType);
diff --git a/connectivity/source/drivers/firebird/ResultSetMetaData.cxx b/connectivity/source/drivers/firebird/ResultSetMetaData.cxx
index 9baadab8fcce..c36148c6c2fa 100644
--- a/connectivity/source/drivers/firebird/ResultSetMetaData.cxx
+++ b/connectivity/source/drivers/firebird/ResultSetMetaData.cxx
@@ -23,6 +23,7 @@
#include <com/sun/star/sdbc/ColumnValue.hpp>
#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
using namespace connectivity::firebird;
@@ -62,8 +63,9 @@ sal_Int32 SAL_CALL OResultSetMetaData::getColumnType(sal_Int32 column)
verifyValidColumn(column);
short aType = m_pSqlda->sqlvar[column-1].sqltype;
+ short aSubType = m_pSqlda->sqlvar[column-1].sqlsubtype;
- return getColumnTypeFromFBType(aType);
+ return getColumnTypeFromFBType(aType, aSubType);
}
sal_Bool SAL_CALL OResultSetMetaData::isCaseSensitive(sal_Int32 column)
@@ -118,8 +120,9 @@ OUString SAL_CALL OResultSetMetaData::getColumnTypeName(sal_Int32 column)
verifyValidColumn(column);
short aType = m_pSqlda->sqlvar[column-1].sqltype;
+ short aSubType = m_pSqlda->sqlvar[column-1].sqlsubtype;
- return getColumnTypeNameFromFBType(aType);
+ return getColumnTypeNameFromFBType(aType, aSubType);
}
OUString SAL_CALL OResultSetMetaData::getColumnLabel(sal_Int32 column)
@@ -191,15 +194,44 @@ sal_Bool SAL_CALL OResultSetMetaData::isSigned(sal_Int32 column)
sal_Int32 SAL_CALL OResultSetMetaData::getPrecision(sal_Int32 column)
throw(SQLException, RuntimeException, std::exception)
{
- // TODO: implement
- (void) column;
+ sal_Int32 nType = getColumnType(column);
+ if( (nType == DataType::NUMERIC || nType == DataType::DECIMAL)
+ && !m_sTableName.isEmpty() )
+ {
+ OUString sColumnName = getColumnName( column );
+
+ // RDB$FIELD_SOURCE is a unique name of column per database
+ OUString sSql = "SELECT RDB$FIELD_PRECISION FROM RDB$FIELDS "
+ " INNER JOIN RDB$RELATION_FIELDS "
+ " ON RDB$RELATION_FIELDS.RDB$FIELD_SOURCE = RDB$FIELDS.RDB$FIELD_NAME "
+ "WHERE RDB$RELATION_FIELDS.RDB$RELATION_NAME = '"
+ + escapeWith(getTableName(column), '\'', '\'') + "' AND "
+ "RDB$RELATION_FIELDS.RDB$FIELD_NAME = '"
+ + escapeWith(sColumnName, '\'', '\'') +"'";
+ Reference<XStatement> xStmt= m_pConnection->createStatement();
+
+ Reference<XResultSet> xRes =
+ xStmt->executeQuery(sSql);
+ Reference<XRow> xRow ( xRes, UNO_QUERY);
+ if(xRes->next())
+ {
+ return (sal_Int32) xRow->getShort(1);
+ }
+ else
+ {
+ SAL_WARN("connectivity.firebird","Column '"
+ << sColumnName
+ << "' not found in database");
+ return 0;
+ }
+ }
return 0;
}
sal_Int32 SAL_CALL OResultSetMetaData::getScale(sal_Int32 column)
throw(css::sdbc::SQLException, css::uno::RuntimeException, std::exception)
{
- return m_pSqlda->sqlvar[column-1].sqlscale;
+ return -(m_pSqlda->sqlvar[column-1].sqlscale); // fb stores negative number
}
sal_Int32 SAL_CALL OResultSetMetaData::isNullable(sal_Int32 column)
diff --git a/connectivity/source/drivers/firebird/Util.cxx b/connectivity/source/drivers/firebird/Util.cxx
index ee5a9bd32481..318aa6d839b0 100644
--- a/connectivity/source/drivers/firebird/Util.cxx
+++ b/connectivity/source/drivers/firebird/Util.cxx
@@ -65,7 +65,7 @@ void firebird::evaluateStatusVector(const ISC_STATUS_ARRAY& rStatusVector,
}
}
-sal_Int32 firebird::getColumnTypeFromFBType(short aType)
+sal_Int32 firebird::getColumnTypeFromFBType(short aType, short aSubType)
{
aType &= ~1; // Remove last bit -- it is used to denote whether column
// can store Null, not needed for type determination
@@ -76,12 +76,24 @@ sal_Int32 firebird::getColumnTypeFromFBType(short aType)
case SQL_VARYING:
return DataType::VARCHAR;
case SQL_SHORT:
+ if(aSubType == 1)
+ return DataType::NUMERIC;
+ if(aSubType == 2)
+ return DataType::DECIMAL;
return DataType::SMALLINT;
case SQL_LONG:
+ if(aSubType == 1)
+ return DataType::NUMERIC;
+ if(aSubType == 2)
+ return DataType::DECIMAL;
return DataType::INTEGER;
case SQL_FLOAT:
return DataType::FLOAT;
case SQL_DOUBLE:
+ if(aSubType == 1)
+ return DataType::NUMERIC;
+ if(aSubType == 2)
+ return DataType::DECIMAL;
return DataType::DOUBLE;
case SQL_D_FLOAT:
return DataType::DOUBLE;
@@ -96,6 +108,10 @@ sal_Int32 firebird::getColumnTypeFromFBType(short aType)
case SQL_TYPE_DATE:
return DataType::DATE;
case SQL_INT64:
+ if(aSubType == 1)
+ return DataType::NUMERIC;
+ if(aSubType == 2)
+ return DataType::DECIMAL;
return DataType::BIGINT;
case SQL_NULL:
return DataType::SQLNULL;
@@ -107,7 +123,7 @@ sal_Int32 firebird::getColumnTypeFromFBType(short aType)
}
}
-OUString firebird::getColumnTypeNameFromFBType(short aType)
+OUString firebird::getColumnTypeNameFromFBType(short aType, short aSubType)
{
aType &= ~1; // Remove last bit -- it is used to denote whether column
// can store Null, not needed for type determination
@@ -118,12 +134,24 @@ OUString firebird::getColumnTypeNameFromFBType(short aType)
case SQL_VARYING:
return OUString("SQL_VARYING");
case SQL_SHORT:
+ if(aSubType == 1)
+ return OUString("SQL_NUMERIC");
+ if(aSubType == 2)
+ return OUString("SQL_DECIMAL");
return OUString("SQL_SHORT");
case SQL_LONG:
+ if(aSubType == 1)
+ return OUString("SQL_NUMERIC");
+ if(aSubType == 2)
+ return OUString("SQL_DECIMAL");
return OUString("SQL_LONG");
case SQL_FLOAT:
return OUString("SQL_FLOAT");
case SQL_DOUBLE:
+ if(aSubType == 1)
+ return OUString("SQL_NUMERIC");
+ if(aSubType == 2)
+ return OUString("SQL_DECIMAL");
return OUString("SQL_DOUBLE");
case SQL_D_FLOAT:
return OUString("SQL_D_FLOAT");
@@ -138,6 +166,10 @@ OUString firebird::getColumnTypeNameFromFBType(short aType)
case SQL_TYPE_DATE:
return OUString("SQL_TYPE_DATE");
case SQL_INT64:
+ if(aSubType == 1)
+ return OUString("SQL_NUMERIC");
+ if(aSubType == 2)
+ return OUString("SQL_DECIMAL");
return OUString("SQL_INT64");
case SQL_NULL:
return OUString("SQL_NULL");
@@ -540,4 +572,14 @@ OUString firebird::escapeWith( const OUString& sText, const char aKey, const cha
return sRet;
}
+
+sal_Int64 firebird::pow10Integer(int nDecimalCount)
+{
+ sal_Int64 nRet = 1;
+ for(int i=0; i< nDecimalCount; i++)
+ {
+ nRet *= 10;
+ }
+ return nRet;
+}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/firebird/Util.hxx b/connectivity/source/drivers/firebird/Util.hxx
index b957c808b37f..fa9af07c0b27 100644
--- a/connectivity/source/drivers/firebird/Util.hxx
+++ b/connectivity/source/drivers/firebird/Util.hxx
@@ -53,8 +53,8 @@ namespace connectivity
const css::uno::Reference< css::uno::XInterface >& _rxContext)
throw (css::sdbc::SQLException);
- sal_Int32 getColumnTypeFromFBType(short aType);
- ::rtl::OUString getColumnTypeNameFromFBType(short aType);
+ sal_Int32 getColumnTypeFromFBType(short aType, short aSubType);
+ ::rtl::OUString getColumnTypeNameFromFBType(short aType, short aSubType);
/**
* Internally (i.e. in RDB$FIELD_TYPE) firebird stores the data type
@@ -73,6 +73,7 @@ namespace connectivity
OString extractSingleTableFromSelect( const OStringVector &vec );
OUString escapeWith( const OUString& sText, const char aKey, const char aEscapeChar);
+ sal_Int64 pow10Integer( int nDecimalCount );
}
}
#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_UTIL_HXX