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>
This commit is contained in:
Wastack 2016-10-31 16:32:54 +01:00 committed by Lionel Elie Mamane
parent 9357e99450
commit 21cc1826c7
9 changed files with 324 additions and 39 deletions

View File

@ -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),

View File

@ -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)
{

View File

@ -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);
}
}

View File

@ -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)

View File

@ -376,6 +376,58 @@ bool OResultSet::isNull(const sal_Int32 nColumnIndex)
return false;
}
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)
{
@ -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);

View File

@ -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);

View File

@ -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)

View File

@ -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: */

View File

@ -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