/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * 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 .
*/
sal_Int32 nFormat = 0;
sal_Int32 nNumberType = _bIsCurrency ? NumberFormat::CURRENCY : NumberFormat::NUMBER; switch (_nDataType)
{ case DataType::BIT: case DataType::BOOLEAN:
nFormat = _xTypes->getStandardFormat(NumberFormat::LOGICAL, _rLocale); break; case DataType::TINYINT: case DataType::SMALLINT: case DataType::INTEGER: case DataType::BIGINT: case DataType::FLOAT: case DataType::REAL: case DataType::DOUBLE: case DataType::NUMERIC: case DataType::DECIMAL:
{ try
{
nFormat = _xTypes->getStandardFormat(static_cast<sal_Int16>(nNumberType), _rLocale); if(_nScale > 0)
{ // generate a new format if necessary
Reference< XNumberFormats > xFormats(_xTypes, UNO_QUERY);
OUString sNewFormat = xFormats->generateFormat( 0, _rLocale, false, false, static_cast<sal_Int16>(_nScale), 1);
// and add it to the formatter if necessary
nFormat = xFormats->queryKey(sNewFormat, _rLocale, false); if (nFormat == sal_Int32(-1))
nFormat = xFormats->addNew(sNewFormat, _rLocale);
}
} catch (Exception&)
{
nFormat = _xTypes->getStandardFormat(static_cast<sal_Int16>(nNumberType), _rLocale);
}
} break; case DataType::CHAR: case DataType::VARCHAR: case DataType::LONGVARCHAR: case DataType::CLOB:
nFormat = _xTypes->getStandardFormat(NumberFormat::TEXT, _rLocale); break; case DataType::DATE:
nFormat = _xTypes->getStandardFormat(NumberFormat::DATE, _rLocale); break; case DataType::TIME:
nFormat = _xTypes->getStandardFormat(NumberFormat::TIME, _rLocale); break; case DataType::TIMESTAMP:
nFormat = _xTypes->getStandardFormat(NumberFormat::DATETIME, _rLocale); break; case DataType::BINARY: case DataType::VARBINARY: case DataType::LONGVARBINARY: case DataType::SQLNULL: case DataType::OTHER: case DataType::OBJECT: case DataType::DISTINCT: case DataType::STRUCT: case DataType::ARRAY: case DataType::BLOB: case DataType::REF: default:
nFormat = _xTypes->getStandardFormat(NumberFormat::UNDEFINED, _rLocale);
} return nFormat;
}
//set ParentWindow for dialog, but just for the duration of this //call, undo at end of scope
Reference<XInitialization> xIni(xDataSource, UNO_QUERY); if (xIni.is())
{
Sequence< Any > aArgs{ Any(NamedValue( u"ParentWindow"_ustr, Any(_rxParent) )) };
xIni->initialize(aArgs);
}
// do it with interaction handler if(_rsUser.isEmpty() || _rsPwd.isEmpty())
{
Reference<XPropertySet> xProp(xDataSource,UNO_QUERY);
OUString sPwd, sUser; bool bPwdReq = false; try
{
xProp->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PASSWORD)) >>= sPwd;
bPwdReq = ::cppu::any2bool(xProp->getPropertyValue(u"IsPasswordRequired"_ustr));
xProp->getPropertyValue(u"User"_ustr) >>= sUser;
} catch(Exception&)
{
OSL_FAIL("dbtools::getConnection: error while retrieving data source properties!");
} if(bPwdReq && sPwd.isEmpty())
{ // password required, but empty -> connect using an interaction handler
Reference<XCompletedConnection> xConnectionCompletion(xProp, UNO_QUERY); if (xConnectionCompletion.is())
{ // instantiate the default SDB interaction handler
Reference< XInteractionHandler > xHandler =
InteractionHandler::createWithParent(_rxContext, _rxParent);
xConnection = xConnectionCompletion->connectWithCompletion(xHandler);
}
} else
xConnection = xDataSource->getConnection(sUser, sPwd);
} if(!xConnection.is()) // try to get one if not already have one, just to make sure
xConnection = xDataSource->getConnection(_rsUser, _rsPwd);
if (xIni.is())
{
Sequence< Any > aArgs{ Any(NamedValue( u"ParentWindow"_ustr, Any(Reference<XWindow>()) )) };
xIni->initialize(aArgs);
}
// helper function which allows to implement both the connectRowset and the ensureRowSetConnection semantics // if connectRowset (which is deprecated) is removed, this function and one of its parameters are // not needed anymore, the whole implementation can be moved into ensureRowSetConnection then) static SharedConnection lcl_connectRowSet(const Reference< XRowSet>& _rxRowSet, const Reference< XComponentContext >& _rxContext, bool _bAttachAutoDisposer, const Reference< XWindow >& _rxParent)
{
SharedConnection xConnection;
do
{
Reference< XPropertySet> xRowSetProps(_rxRowSet, UNO_QUERY); if ( !xRowSetProps.is() ) break;
if ( xExistingConn.is() // 2. embedded in a database?
|| isEmbeddedInDatabase( _rxRowSet, xExistingConn ) // 3. is there a connection in the parent hierarchy?
|| ( xExistingConn = findConnection( _rxRowSet ) ).is()
)
{
xRowSetProps->setPropertyValue(u"ActiveConnection"_ustr, Any( xExistingConn ) ); // no auto disposer needed, since we did not create the connection
Reference< XConnection > xPureConnection; if (!sDataSourceName.isEmpty())
{ // the row set's data source property is set // -> try to connect, get user and pwd setting for that
OUString sUser, sPwd;
if (hasProperty(sUserProp, xRowSetProps))
xRowSetProps->getPropertyValue(sUserProp) >>= sUser; if (hasProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PASSWORD), xRowSetProps))
xRowSetProps->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PASSWORD)) >>= sPwd;
xPureConnection = getConnection_allowException( sDataSourceName, sUser, sPwd, _rxContext, _rxParent );
} elseif (!sURL.isEmpty())
{ // the row set has no data source, but a connection url set // -> try to connection with that url
Reference< XConnectionPool > xDriverManager; try {
xDriverManager = ConnectionPool::create( _rxContext );
} catch( const Exception& ) { } if (xDriverManager.is())
{
OUString sUser, sPwd; if (hasProperty(sUserProp, xRowSetProps))
xRowSetProps->getPropertyValue(sUserProp) >>= sUser; if (hasProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PASSWORD), xRowSetProps))
xRowSetProps->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PASSWORD)) >>= sPwd; if (!sUser.isEmpty())
{ // use user and pwd together with the url auto aInfo(::comphelper::InitPropertySequence({
{ "user", Any(sUser) },
{ "password", Any(sPwd) }
}));
xPureConnection = xDriverManager->getConnectionWithInfo( sURL, aInfo );
} else // just use the url
xPureConnection = xDriverManager->getConnection( sURL );
}
}
xConnection.reset(
xPureConnection,
_bAttachAutoDisposer ? SharedConnection::NoTakeOwnership : SharedConnection::TakeOwnership /* take ownership if and only if we're *not* going to auto-dispose the connection */
);
// now if we created a connection, forward it to the row set if ( xConnection.is() )
{ try
{ if ( _bAttachAutoDisposer )
{ new OAutoConnectionDisposer( _rxRowSet, xConnection );
} else
xRowSetProps->setPropertyValue(
u"ActiveConnection"_ustr,
Any( xConnection.getTyped() )
);
} catch(Exception&)
{
TOOLS_WARN_EXCEPTION( "connectivity.commontools", "EXception when we set the new active connection!");
}
}
} while ( false );
// reset the error if ( _pErrorInfo )
*_pErrorInfo = SQLExceptionInfo(); // reset the ownership holder
_rxKeepFieldsAlive.clear();
// go for the fields try
{ // some kind of state machine to ease the sharing of code
FieldLookupState eState = FAILED; switch ( _nCommandType )
{ case CommandType::TABLE:
eState = HANDLE_TABLE; break; case CommandType::QUERY:
eState = HANDLE_QUERY; break; case CommandType::COMMAND:
eState = HANDLE_SQL; break;
}
// needed in various states:
Reference< XNameAccess > xObjectCollection;
Reference< XColumnsSupplier > xSupplyColumns;
// go! while ( ( DONE != eState ) && ( FAILED != eState ) )
{ switch ( eState )
{ case HANDLE_TABLE:
{ // initial state for handling the tables
// get the table objects
Reference< XTablesSupplier > xSupplyTables( _rxConnection, UNO_QUERY ); if ( xSupplyTables.is() )
xObjectCollection = xSupplyTables->getTables(); // if something went wrong 'til here, then this will be handled in the next state
// next state: get the object
eState = RETRIEVE_OBJECT;
} break;
case HANDLE_QUERY:
{ // initial state for handling the tables
// get the table objects
Reference< XQueriesSupplier > xSupplyQueries( _rxConnection, UNO_QUERY ); if ( xSupplyQueries.is() )
xObjectCollection = xSupplyQueries->getQueries(); // if something went wrong 'til here, then this will be handled in the next state
// next state: get the object
eState = RETRIEVE_OBJECT;
} break;
case RETRIEVE_OBJECT: // here we should have an object (aka query or table) collection, and are going // to retrieve the desired object
// next state: default to FAILED
eState = FAILED;
OSL_ENSURE( xObjectCollection.is(), "::dbtools::getFieldsByCommandDescriptor: invalid connection (no sdb.Connection, or no Tables-/QueriesSupplier)!"); if ( xObjectCollection.is() && xObjectCollection->hasByName( _rCommand ) )
{
xObjectCollection->getByName( _rCommand ) >>= xSupplyColumns; // (xSupplyColumns being NULL will be handled in the next state)
// next: go for the columns
eState = RETRIEVE_COLUMNS;
} break;
case RETRIEVE_COLUMNS:
OSL_ENSURE( xSupplyColumns.is(), "::dbtools::getFieldsByCommandDescriptor: could not retrieve the columns supplier!" );
// next state: default to FAILED
eState = FAILED;
if ( xSupplyColumns.is() )
{
xFields = xSupplyColumns->getColumns(); // that's it
eState = DONE;
} break;
case HANDLE_SQL:
{
OUString sStatementToExecute( _rCommand );
// well, the main problem here is to handle statements which contain a parameter // If we would simply execute a parametrized statement, then this will fail because // we cannot supply any parameter values. // Thus, we try to analyze the statement, and to append a WHERE 0=1 filter criterion // This should cause every driver to not really execute the statement, but to return // an empty result set with the proper structure. We then can use this result set // to retrieve the columns.
if ( xComposerFac.is() )
{
Reference< XSingleSelectQueryComposer > xComposer(xComposerFac->createInstance(u"com.sun.star.sdb.SingleSelectQueryComposer"_ustr),UNO_QUERY); if ( xComposer.is() )
{
xComposer->setQuery( sStatementToExecute );
// Now set the filter to a dummy restriction which will result in an empty // result set.
xComposer->setFilter( u"0=1"_ustr );
sStatementToExecute = xComposer->getQuery( );
}
}
} catch( const Exception& )
{ // silent this error, this was just a try. If we're here, we did not change sStatementToExecute, // so it will still be _rCommand, which then will be executed without being touched
}
// now execute
Reference< XPreparedStatement > xStatement = _rxConnection->prepareStatement( sStatementToExecute ); // transfer ownership of this temporary object to the caller
_rxKeepFieldsAlive.set(xStatement, css::uno::UNO_QUERY);
// set the "MaxRows" to 0. This is just in case our attempt to append a 0=1 filter // failed - in this case, the MaxRows restriction should at least ensure that there // is no data returned (which would be potentially expensive)
Reference< XPropertySet > xStatementProps( xStatement,UNO_QUERY ); try
{ if ( xStatementProps.is() )
xStatementProps->setPropertyValue( u"MaxRows"_ustr, Any( sal_Int32( 0 ) ) );
} catch( const Exception& )
{
OSL_FAIL( "::dbtools::getFieldsByCommandDescriptor: could not set the MaxRows!" ); // oh damn. Not much of a chance to recover, we will no retrieve the complete // full blown result set
}
xSupplyColumns.set(xStatement->executeQuery(), css::uno::UNO_QUERY); // this should have given us a result set which does not contain any data, but // the structural information we need
// so the next state is to get the columns
eState = RETRIEVE_COLUMNS;
} break;
default:
OSL_FAIL( "::dbtools::getFieldsByCommandDescriptor: oops! unhandled state here!" );
eState = FAILED;
}
}
} catch( const SQLContext& e ) { if ( _pErrorInfo ) *_pErrorInfo = SQLExceptionInfo( e ); } catch( const SQLWarning& e ) { if ( _pErrorInfo ) *_pErrorInfo = SQLExceptionInfo( e ); } catch( const SQLException& e ) { if ( _pErrorInfo ) *_pErrorInfo = SQLExceptionInfo( e ); } catch( const Exception& )
{
TOOLS_WARN_EXCEPTION( "connectivity.commontools", "::dbtools::getFieldsByCommandDescriptor: caught an exception while retrieving the fields!" );
}
OUString sName(_rQualifiedName); // do we have catalogs? if ( aNameComps.bCatalogs )
{ if (_rxConnMetaData->isCatalogAtStart())
{ // search for the catalog name at the beginning
sal_Int32 nIndex = sName.indexOf(sSeparator); if (-1 != nIndex)
{
_rCatalog = sName.copy(0, nIndex);
sName = sName.copy(nIndex + 1);
}
} else
{ // Catalog name at the end
sal_Int32 nIndex = sName.lastIndexOf(sSeparator); if (-1 != nIndex)
{
_rCatalog = sName.copy(nIndex + 1);
sName = sName.copy(0, nIndex);
}
}
}
// First we copy all the Props, that are available in source and target and have the same description
Reference< XPropertySetInfo> xOldInfo( xOldProps->getPropertySetInfo());
Reference< XPropertySetInfo> xNewInfo( xNewProps->getPropertySetInfo());
if ( ( pResult != aNewProperties.end() )
&& ( pResult->Name == rOldProp.Name )
&& ( (pResult->Attributes & PropertyAttribute::READONLY) == 0 )
&& ( pResult->Type.equals(rOldProp.Type)) )
{ // Attributes match and the property is not read-only try
{
xNewProps->setPropertyValue(pResult->Name, xOldProps->getPropertyValue(pResult->Name));
} catch(IllegalArgumentException const &)
{
TOOLS_WARN_EXCEPTION( "connectivity.commontools", "TransferFormComponentProperties : could not transfer the value for property \""
<< pResult->Name << "\"");
}
}
}
}
// for formatted fields (either old or new) we have some special treatments
Reference< XServiceInfo > xSI( xOldProps, UNO_QUERY ); bool bOldIsFormatted = xSI.is() && xSI->supportsService( sFormattedServiceName );
xSI.set( xNewProps, UNO_QUERY ); bool bNewIsFormatted = xSI.is() && xSI->supportsService( sFormattedServiceName );
if (!bOldIsFormatted && !bNewIsFormatted) return; // nothing to do
if (bOldIsFormatted && bNewIsFormatted) // if both fields are formatted we do no conversions return;
if (bOldIsFormatted)
{ // get some properties from the selected format and put them in the new Set
Any aFormatKey( xOldProps->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FORMATKEY)) ); if (aFormatKey.hasValue())
{
Reference< XNumberFormatsSupplier> xSupplier;
xOldProps->getPropertyValue(sPropFormatsSupplier) >>= xSupplier; if (xSupplier.is())
{
Reference< XNumberFormats> xFormats(xSupplier->getNumberFormats());
Reference< XPropertySet> xFormat(xFormats->getByKey(getINT32(aFormatKey))); if (hasProperty(sPropCurrencySymbol, xFormat))
{
Any aVal( xFormat->getPropertyValue(sPropCurrencySymbol) ); if (aVal.hasValue() && hasProperty(sPropCurrencySymbol, xNewProps)) // If the source value hasn't been set then don't copy it // so we don't overwrite the default value
xNewProps->setPropertyValue(sPropCurrencySymbol, aVal);
} if (hasProperty(sPropDecimals, xFormat) && hasProperty(sPropDecimals, xNewProps))
xNewProps->setPropertyValue(sPropDecimals, xFormat->getPropertyValue(sPropDecimals));
}
}
// a potential Min-Max-Conversion
Any aEffectiveMin( xOldProps->getPropertyValue(sPropEffectiveMin) ); if (aEffectiveMin.hasValue())
{ // Unlike the ValueMin the EffectiveMin can be void if (hasProperty(sPropValueMin, xNewProps))
{
OSL_ENSURE(aEffectiveMin.getValueTypeClass() == TypeClass_DOUBLE, "TransferFormComponentProperties : invalid property type !");
xNewProps->setPropertyValue(sPropValueMin, aEffectiveMin);
}
}
Any aEffectiveMax( xOldProps->getPropertyValue(sPropEffectiveMax) ); if (aEffectiveMax.hasValue())
{ // analog if (hasProperty(sPropValueMax, xNewProps))
{
OSL_ENSURE(aEffectiveMax.getValueTypeClass() == TypeClass_DOUBLE, "TransferFormComponentProperties : invalid property type !");
xNewProps->setPropertyValue(sPropValueMax, aEffectiveMax);
}
}
// then we can still convert and copy the default values
Any aEffectiveDefault( xOldProps->getPropertyValue(sPropEffectiveDefault) ); if (aEffectiveDefault.hasValue())
{ bool bIsString = aEffectiveDefault.getValueTypeClass() == TypeClass_STRING;
OSL_ENSURE(bIsString || aEffectiveDefault.getValueTypeClass() == TypeClass_DOUBLE, "TransferFormComponentProperties : invalid property type !"); // The Effective-Properties should always be void or string or double...
if (hasProperty(sPropDefaultDate, xNewProps) && !bIsString)
{ // (to convert an OUString into a date will not always succeed, because it might be bound to a text-column, // but we can work with a double)
Date aDate = DBTypeConversion::toDate(getDouble(aEffectiveDefault));
xNewProps->setPropertyValue(sPropDefaultDate, Any(aDate));
}
if (hasProperty(sPropDefaultTime, xNewProps) && !bIsString)
{ // Completely analogous to time
css::util::Time aTime = DBTypeConversion::toTime(getDouble(aEffectiveDefault));
xNewProps->setPropertyValue(sPropDefaultTime, Any(aTime));
}
if (hasProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DEFAULTVALUE), xNewProps) && !bIsString)
{ // Here we can simply pass the double
xNewProps->setPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DEFAULTVALUE), aEffectiveDefault);
}
if (hasProperty(sPropDefaultText, xNewProps) && bIsString)
{ // and here the OUString
xNewProps->setPropertyValue(sPropDefaultText, aEffectiveDefault);
}
// nyi: The translation between doubles and OUString would offer more alternatives
}
}
// The other direction: the new Control shall be formatted if (bNewIsFormatted)
{ // first the formatting // we can't set a Supplier, so the new Set must bring one in
Reference< XNumberFormatsSupplier> xSupplier;
xNewProps->getPropertyValue(sPropFormatsSupplier) >>= xSupplier; if (xSupplier.is())
{
Reference< XNumberFormats> xFormats(xSupplier->getNumberFormats());
// Set number of decimals
sal_Int16 nDecimals = 2; if (hasProperty(sPropDecimalAccuracy, xOldProps))
xOldProps->getPropertyValue(sPropDecimalAccuracy) >>= nDecimals;
// base format (depending on the ClassId of the old Set)
sal_Int32 nBaseKey = 0; if (hasProperty(sPropClassId, xOldProps))
{
Reference< XNumberFormatTypes> xTypeList(xFormats, UNO_QUERY); if (xTypeList.is())
{
sal_Int16 nClassId = 0;
xOldProps->getPropertyValue(sPropClassId) >>= nClassId; switch (nClassId)
{ case FormComponentType::DATEFIELD :
nBaseKey = xTypeList->getStandardFormat(NumberFormat::DATE, _rLocale); break;
case FormComponentType::TIMEFIELD :
nBaseKey = xTypeList->getStandardFormat(NumberFormat::TIME, _rLocale); break;
// With this we can generate a new format ...
OUString sNewFormat = xFormats->generateFormat(nBaseKey, _rLocale, false, false, nDecimals, 0); // No thousands separator, negative numbers are not in red, no leading zeros
// ... and add at FormatsSupplier (if needed)
sal_Int32 nKey = xFormats->queryKey(sNewFormat, _rLocale, false); if (nKey == sal_Int32(-1))
{ // not added yet in my formatter ...
nKey = xFormats->addNew(sNewFormat, _rLocale);
}
// min-/max-Value
Any aNewMin, aNewMax; if (hasProperty(sPropValueMin, xOldProps))
aNewMin = xOldProps->getPropertyValue(sPropValueMin); if (hasProperty(sPropValueMax, xOldProps))
aNewMax = xOldProps->getPropertyValue(sPropValueMax);
xNewProps->setPropertyValue(sPropEffectiveMin, aNewMin);
xNewProps->setPropertyValue(sPropEffectiveMax, aNewMax);
// Default-Value
Any aNewDefault; if (hasProperty(sPropDefaultDate, xOldProps))
{
Any aDate( xOldProps->getPropertyValue(sPropDefaultDate) ); if (aDate.hasValue())
aNewDefault <<= DBTypeConversion::toDouble(*o3tl::doAccess<Date>(aDate));
}
if (hasProperty(sPropDefaultTime, xOldProps))
{
Any aTime( xOldProps->getPropertyValue(sPropDefaultTime) ); if (aTime.hasValue())
aNewDefault <<= DBTypeConversion::toDouble(*o3tl::doAccess<Time>(aTime));
}
// double or OUString will be copied directly if (hasProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DEFAULTVALUE), xOldProps))
aNewDefault = xOldProps->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DEFAULTVALUE)); if (hasProperty(sPropDefaultText, xOldProps))
aNewDefault = xOldProps->getPropertyValue(sPropDefaultText);
static Reference< XSingleSelectQueryComposer > getComposedRowSetStatement( const Reference< XPropertySet >& _rxRowSet, const Reference< XComponentContext >& _rxContext, constReference< XWindow >& _rxParent )
{
Reference< XSingleSelectQueryComposer > xComposer; try
{
Reference< XConnection> xConn = connectRowset( Reference< XRowSet >( _rxRowSet, UNO_QUERY ), _rxContext, _rxParent ); if ( xConn.is() ) // implies _rxRowSet.is()
{ // build the statement the row set is based on (can't use the ActiveCommand property of the set // as this reflects the status after the last execute, not the currently set properties)
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.