| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_connectivity.hxx" |
| |
| |
| #include "connectivity/dbconversion.hxx" |
| #include <connectivity/dbtools.hxx> |
| #include <com/sun/star/script/XTypeConverter.hpp> |
| #include <com/sun/star/sdbc/DataType.hpp> |
| #include <com/sun/star/util/NumberFormat.hpp> |
| #include <com/sun/star/util/XNumberFormatTypes.hpp> |
| #include <com/sun/star/sdb/XColumnUpdate.hpp> |
| #include <com/sun/star/sdb/XColumn.hpp> |
| #include <com/sun/star/beans/XPropertySet.hpp> |
| #include <comphelper/extract.hxx> |
| #include "TConnection.hxx" |
| #include "diagnose_ex.h" |
| #include <comphelper/numbers.hxx> |
| #include <rtl/ustrbuf.hxx> |
| #include <tools/diagnose_ex.h> |
| |
| |
| using namespace ::connectivity; |
| using namespace ::comphelper; |
| using namespace ::com::sun::star::script; |
| using namespace ::com::sun::star::sdb; |
| using namespace ::com::sun::star::sdbc; |
| using namespace ::dbtools; |
| using namespace ::com::sun::star::lang; |
| using namespace ::com::sun::star::beans; |
| using namespace ::com::sun::star::util; |
| using namespace ::com::sun::star::uno; |
| using namespace ::com::sun::star::util; |
| using namespace ::com::sun::star::beans; |
| // ----------------------------------------------------------------------------- |
| ::rtl::OUString DBTypeConversion::toSQLString(sal_Int32 eType, const Any& _rVal, sal_Bool bQuote, |
| const Reference< XTypeConverter >& _rxTypeConverter) |
| { |
| ::rtl::OUStringBuffer aRet; |
| if (_rVal.hasValue()) |
| { |
| try |
| { |
| switch (eType) |
| { |
| case DataType::INTEGER: |
| case DataType::BIT: |
| case DataType::BOOLEAN: |
| case DataType::TINYINT: |
| case DataType::SMALLINT: |
| if (_rVal.getValueType().getTypeClass() == ::com::sun::star::uno::TypeClass_BOOLEAN) |
| { |
| if (::cppu::any2bool(_rVal)) |
| aRet.appendAscii("1"); |
| else |
| aRet.appendAscii("0"); |
| } |
| else |
| { |
| ::rtl::OUString sTemp; |
| _rxTypeConverter->convertToSimpleType(_rVal, TypeClass_STRING) >>= sTemp; |
| aRet.append(sTemp); |
| } |
| break; |
| case DataType::CHAR: |
| case DataType::VARCHAR: |
| case DataType::LONGVARCHAR: |
| if (bQuote) |
| aRet.appendAscii("'"); |
| { |
| ::rtl::OUString aTemp; |
| _rxTypeConverter->convertToSimpleType(_rVal, TypeClass_STRING) >>= aTemp; |
| sal_Int32 nIndex = (sal_Int32)-1; |
| const ::rtl::OUString sQuot(RTL_CONSTASCII_USTRINGPARAM("\'")); |
| const ::rtl::OUString sQuotToReplace(RTL_CONSTASCII_USTRINGPARAM("\'\'")); |
| do |
| { |
| nIndex += 2; |
| nIndex = aTemp.indexOf(sQuot,nIndex); |
| if(nIndex != -1) |
| aTemp = aTemp.replaceAt(nIndex,sQuot.getLength(),sQuotToReplace); |
| } while (nIndex != -1); |
| |
| aRet.append(aTemp); |
| } |
| if (bQuote) |
| aRet.appendAscii("'"); |
| break; |
| case DataType::REAL: |
| case DataType::DOUBLE: |
| case DataType::DECIMAL: |
| case DataType::NUMERIC: |
| case DataType::BIGINT: |
| default: |
| { |
| ::rtl::OUString sTemp; |
| _rxTypeConverter->convertToSimpleType(_rVal, TypeClass_STRING) >>= sTemp; |
| aRet.append(sTemp); |
| } |
| break; |
| case DataType::TIMESTAMP: |
| { |
| DateTime aDateTime; |
| bool bOk = false; |
| if (_rVal.getValueType().getTypeClass() == ::com::sun::star::uno::TypeClass_DOUBLE) |
| { |
| double nValue = 0.0; |
| _rVal >>= nValue; |
| aDateTime = DBTypeConversion::toDateTime(nValue); |
| bOk = true; |
| } |
| else if (_rVal.getValueType().getTypeClass() == ::com::sun::star::uno::TypeClass_STRING) |
| { |
| ::rtl::OUString sValue; |
| _rVal >>= sValue; |
| aDateTime = DBTypeConversion::toDateTime(sValue); |
| bOk = true; |
| } |
| else |
| bOk = _rVal >>= aDateTime; |
| |
| OSL_VERIFY_RES( bOk, "DBTypeConversion::toSQLString: _rVal is not datetime!"); |
| // check if this is really a timestamp or only a date |
| if ( bOk ) |
| { |
| if (bQuote) |
| aRet.appendAscii("{TS '"); |
| aRet.append(DBTypeConversion::toDateTimeString(aDateTime)); |
| if (bQuote) |
| aRet.appendAscii("'}"); |
| break; |
| } |
| break; |
| } |
| case DataType::DATE: |
| { |
| Date aDate; |
| bool bOk = false; |
| if (_rVal.getValueType().getTypeClass() == ::com::sun::star::uno::TypeClass_DOUBLE) |
| { |
| double nValue = 0.0; |
| _rVal >>= nValue; |
| aDate = DBTypeConversion::toDate(nValue); |
| bOk = true; |
| } |
| else if (_rVal.getValueType().getTypeClass() == ::com::sun::star::uno::TypeClass_STRING) |
| { |
| ::rtl::OUString sValue; |
| _rVal >>= sValue; |
| aDate = DBTypeConversion::toDate(sValue); |
| bOk = true; |
| } |
| else |
| bOk = _rVal >>= aDate; |
| OSL_VERIFY_RES( bOk, "DBTypeConversion::toSQLString: _rVal is not date!"); |
| if (bQuote) |
| aRet.appendAscii("{D '"); |
| aRet.append(DBTypeConversion::toDateString(aDate)); |
| if (bQuote) |
| aRet.appendAscii("'}"); |
| } break; |
| case DataType::TIME: |
| { |
| Time aTime; |
| bool bOk = false; |
| if (_rVal.getValueType().getTypeClass() == ::com::sun::star::uno::TypeClass_DOUBLE) |
| { |
| double nValue = 0.0; |
| _rVal >>= nValue; |
| aTime = DBTypeConversion::toTime(nValue); |
| bOk = true; |
| } |
| else if (_rVal.getValueType().getTypeClass() == ::com::sun::star::uno::TypeClass_STRING) |
| { |
| ::rtl::OUString sValue; |
| _rVal >>= sValue; |
| aTime = DBTypeConversion::toTime(sValue); |
| bOk = true; |
| } |
| else |
| bOk = _rVal >>= aTime; |
| OSL_VERIFY_RES( bOk,"DBTypeConversion::toSQLString: _rVal is not time!"); |
| if (bQuote) |
| aRet.appendAscii("{T '"); |
| aRet.append(DBTypeConversion::toTimeString(aTime)); |
| if (bQuote) |
| aRet.appendAscii("'}"); |
| } break; |
| } |
| } |
| catch ( const Exception& ) |
| { |
| OSL_ENSURE(0,"TypeConversion Error"); |
| } |
| } |
| else |
| aRet.appendAscii(" NULL "); |
| return aRet.makeStringAndClear(); |
| } |
| // ----------------------------------------------------------------------------- |
| Date DBTypeConversion::getNULLDate(const Reference< XNumberFormatsSupplier > &xSupplier) |
| { |
| OSL_ENSURE(xSupplier.is(), "getNULLDate : the formatter doesn't implement a supplier !"); |
| if (xSupplier.is()) |
| { |
| try |
| { |
| // get the null date |
| Date aDate; |
| xSupplier->getNumberFormatSettings()->getPropertyValue(::rtl::OUString::createFromAscii("NullDate")) >>= aDate; |
| return aDate; |
| } |
| catch ( const Exception& ) |
| { |
| } |
| } |
| |
| return getStandardDate(); |
| } |
| // ----------------------------------------------------------------------------- |
| void DBTypeConversion::setValue(const Reference<XColumnUpdate>& xVariant, |
| const Reference<XNumberFormatter>& xFormatter, |
| const Date& rNullDate, |
| const ::rtl::OUString& rString, |
| sal_Int32 nKey, |
| sal_Int16 nFieldType, |
| sal_Int16 nKeyType) throw(::com::sun::star::lang::IllegalArgumentException) |
| { |
| double fValue = 0; |
| if (rString.getLength()) |
| { |
| // Muss der String formatiert werden? |
| sal_Int16 nTypeClass = nKeyType & ~NumberFormat::DEFINED; |
| sal_Bool bTextFormat = nTypeClass == NumberFormat::TEXT; |
| sal_Int32 nKeyToUse = bTextFormat ? 0 : nKey; |
| sal_Int16 nRealUsedTypeClass = nTypeClass; |
| // bei einem Text-Format muessen wir dem Formatter etwas mehr Freiheiten einraeumen, sonst |
| // wirft convertStringToNumber eine NotNumericException |
| try |
| { |
| fValue = xFormatter->convertStringToNumber(nKeyToUse, rString); |
| sal_Int32 nRealUsedKey = xFormatter->detectNumberFormat(0, rString); |
| if (nRealUsedKey != nKeyToUse) |
| nRealUsedTypeClass = getNumberFormatType(xFormatter, nRealUsedKey) & ~NumberFormat::DEFINED; |
| |
| // und noch eine Sonderbehandlung, diesmal fuer Prozent-Formate |
| if ((NumberFormat::NUMBER == nRealUsedTypeClass) && (NumberFormat::PERCENT == nTypeClass)) |
| { // die Formatierung soll eigentlich als Prozent erfolgen, aber der String stellt nur eine |
| // einfache Nummer dar -> anpassen |
| ::rtl::OUString sExpanded(rString); |
| static ::rtl::OUString s_sPercentSymbol = ::rtl::OUString::createFromAscii("%"); |
| // need a method to add a sal_Unicode to a string, 'til then we use a static string |
| sExpanded += s_sPercentSymbol; |
| fValue = xFormatter->convertStringToNumber(nKeyToUse, sExpanded); |
| } |
| |
| switch (nRealUsedTypeClass) |
| { |
| case NumberFormat::DATE: |
| case NumberFormat::DATETIME: |
| case NumberFormat::TIME: |
| DBTypeConversion::setValue(xVariant,rNullDate,fValue,nRealUsedTypeClass); |
| // xVariant->updateDouble(toStandardDbDate(rNullDate, fValue)); |
| break; |
| case NumberFormat::CURRENCY: |
| case NumberFormat::NUMBER: |
| case NumberFormat::SCIENTIFIC: |
| case NumberFormat::FRACTION: |
| case NumberFormat::PERCENT: |
| xVariant->updateDouble(fValue); |
| break; |
| default: |
| xVariant->updateString(rString); |
| } |
| } |
| catch(const Exception& ) |
| { |
| xVariant->updateString(rString); |
| } |
| } |
| else |
| { |
| switch (nFieldType) |
| { |
| case ::com::sun::star::sdbc::DataType::CHAR: |
| case ::com::sun::star::sdbc::DataType::VARCHAR: |
| case ::com::sun::star::sdbc::DataType::LONGVARCHAR: |
| xVariant->updateString(rString); |
| break; |
| default: |
| xVariant->updateNull(); |
| } |
| } |
| } |
| |
| //------------------------------------------------------------------------------ |
| void DBTypeConversion::setValue(const Reference<XColumnUpdate>& xVariant, |
| const Date& rNullDate, |
| const double& rValue, |
| sal_Int16 nKeyType) throw(::com::sun::star::lang::IllegalArgumentException) |
| { |
| switch (nKeyType & ~NumberFormat::DEFINED) |
| { |
| case NumberFormat::DATE: |
| xVariant->updateDate(toDate( rValue, rNullDate)); |
| break; |
| case NumberFormat::DATETIME: |
| xVariant->updateTimestamp(toDateTime(rValue,rNullDate)); |
| break; |
| case NumberFormat::TIME: |
| xVariant->updateTime(toTime(rValue)); |
| break; |
| default: |
| { |
| double nValue = rValue; |
| // Reference<XPropertySet> xProp(xVariant,UNO_QUERY); |
| // if ( xProp.is() |
| // && xProp->getPropertySetInfo()->hasPropertyByName(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISSIGNED)) |
| // && !::comphelper::getBOOL(xProp->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISSIGNED))) ) |
| // { |
| // switch (::comphelper::getINT32(xProp->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE)))) |
| // { |
| // case DataType::TINYINT: |
| // nValue = static_cast<sal_uInt8>(rValue); |
| // break; |
| // case DataType::SMALLINT: |
| // nValue = static_cast<sal_uInt16>(rValue); |
| // break; |
| // case DataType::INTEGER: |
| // nValue = static_cast<sal_uInt32>(rValue); |
| // break; |
| // case DataType::BIGINT: |
| // nValue = static_cast<sal_uInt64>(rValue); |
| // break; |
| // } |
| // } |
| xVariant->updateDouble(nValue); |
| } |
| } |
| } |
| |
| //------------------------------------------------------------------------------ |
| double DBTypeConversion::getValue( const Reference< XColumn >& i_column, const Date& i_relativeToNullDate ) |
| { |
| try |
| { |
| const Reference< XPropertySet > xProp( i_column, UNO_QUERY_THROW ); |
| |
| const sal_Int32 nColumnType = ::comphelper::getINT32( xProp->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_TYPE ) ) ); |
| switch ( nColumnType ) |
| { |
| case DataType::DATE: |
| return toDouble( i_column->getDate(), i_relativeToNullDate ); |
| |
| case DataType::TIME: |
| return toDouble( i_column->getTime() ); |
| |
| case DataType::TIMESTAMP: |
| return toDouble( i_column->getTimestamp(), i_relativeToNullDate ); |
| |
| default: |
| { |
| sal_Bool bIsSigned = sal_True; |
| OSL_VERIFY( xProp->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_ISSIGNED ) ) >>= bIsSigned ); |
| if ( !bIsSigned ) |
| { |
| switch ( nColumnType) |
| { |
| case DataType::TINYINT: |
| return static_cast<double>(static_cast<sal_uInt8>(i_column->getByte())); |
| case DataType::SMALLINT: |
| return static_cast<double>(static_cast<sal_uInt16>(i_column->getShort())); |
| case DataType::INTEGER: |
| return static_cast<double>(static_cast<sal_uInt32>(i_column->getInt())); |
| case DataType::BIGINT: |
| return static_cast<double>(static_cast<sal_uInt64>(i_column->getLong())); |
| } |
| } |
| } |
| return i_column->getDouble(); |
| } |
| } |
| catch( const Exception& ) |
| { |
| DBG_UNHANDLED_EXCEPTION(); |
| return 0.0; |
| } |
| } |
| //------------------------------------------------------------------------------ |
| ::rtl::OUString DBTypeConversion::getFormattedValue(const Reference< XPropertySet>& _xColumn, |
| const Reference<XNumberFormatter>& _xFormatter, |
| const ::com::sun::star::lang::Locale& _rLocale, |
| const Date& _rNullDate) |
| { |
| OSL_ENSURE(_xColumn.is() && _xFormatter.is(), "DBTypeConversion::getFormattedValue: invalid arg !"); |
| if (!_xColumn.is() || !_xFormatter.is()) |
| return ::rtl::OUString(); |
| |
| sal_Int32 nKey(0); |
| try |
| { |
| _xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FORMATKEY)) >>= nKey; |
| } |
| catch (const Exception& ) |
| { |
| OSL_ENSURE(false, "DBTypeConversion::getFormattedValue: caught an exception while asking for the format key!"); |
| } |
| |
| if (!nKey) |
| { |
| Reference<XNumberFormats> xFormats( _xFormatter->getNumberFormatsSupplier()->getNumberFormats() ); |
| Reference<XNumberFormatTypes> xTypeList(_xFormatter->getNumberFormatsSupplier()->getNumberFormats(), UNO_QUERY); |
| |
| nKey = ::dbtools::getDefaultNumberFormat(_xColumn, |
| Reference< XNumberFormatTypes > (xFormats, UNO_QUERY), |
| _rLocale); |
| |
| } |
| |
| sal_Int16 nKeyType = getNumberFormatType(_xFormatter, nKey) & ~NumberFormat::DEFINED; |
| |
| return DBTypeConversion::getFormattedValue(Reference< XColumn > (_xColumn, UNO_QUERY), _xFormatter, _rNullDate, nKey, nKeyType); |
| } |
| |
| //------------------------------------------------------------------------------ |
| ::rtl::OUString DBTypeConversion::getFormattedValue(const Reference<XColumn>& xVariant, |
| const Reference<XNumberFormatter>& xFormatter, |
| const Date& rNullDate, |
| sal_Int32 nKey, |
| sal_Int16 nKeyType) |
| { |
| ::rtl::OUString aString; |
| if (xVariant.is()) |
| { |
| try |
| { |
| switch (nKeyType & ~NumberFormat::DEFINED) |
| { |
| case NumberFormat::DATE: |
| case NumberFormat::DATETIME: |
| { |
| // get a value which represents the given date, relative to the given null date |
| double fValue = getValue( xVariant, rNullDate ); |
| if ( !xVariant->wasNull() ) |
| { |
| // get the null date of the formatter |
| Date aFormatterNullDate( rNullDate ); |
| try |
| { |
| Reference< XNumberFormatsSupplier > xSupplier( xFormatter->getNumberFormatsSupplier(), UNO_SET_THROW ); |
| Reference< XPropertySet > xFormatterSettings( xSupplier->getNumberFormatSettings(), UNO_SET_THROW ); |
| OSL_VERIFY( xFormatterSettings->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "NullDate" ) ) ) >>= aFormatterNullDate ); |
| } |
| catch( const Exception& ) |
| { |
| DBG_UNHANDLED_EXCEPTION(); |
| } |
| // get a value which represents the given date, relative to the null date of the formatter |
| fValue -= toDays( rNullDate, aFormatterNullDate ); |
| // format this value |
| aString = xFormatter->convertNumberToString( nKey, fValue ); |
| } |
| } |
| break; |
| case NumberFormat::TIME: |
| case NumberFormat::NUMBER: |
| case NumberFormat::SCIENTIFIC: |
| case NumberFormat::FRACTION: |
| case NumberFormat::PERCENT: |
| { |
| double fValue = xVariant->getDouble(); |
| if (!xVariant->wasNull()) |
| aString = xFormatter->convertNumberToString(nKey, fValue); |
| } break; |
| case NumberFormat::CURRENCY: |
| { |
| double fValue = xVariant->getDouble(); |
| if (!xVariant->wasNull()) |
| aString = xFormatter->getInputString(nKey, fValue); |
| } break; |
| case NumberFormat::TEXT: |
| aString = xFormatter->formatString(nKey, xVariant->getString()); |
| break; |
| default: |
| aString = xVariant->getString(); |
| } |
| } |
| catch(const Exception& ) |
| { |
| aString = xVariant->getString(); |
| } |
| } |
| return aString; |
| } |
| //------------------------------------------------------------------ |