1386 lines
53 KiB
C++
1386 lines
53 KiB
C++
/* -*- 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 .
|
|
*/
|
|
|
|
#include <UITools.hxx>
|
|
#include <sfx2/docfilt.hxx>
|
|
#include <core_resource.hxx>
|
|
#include <dlgsave.hxx>
|
|
#include <defaultobjectnamecheck.hxx>
|
|
#include <strings.hxx>
|
|
#include <comphelper/extract.hxx>
|
|
#include <com/sun/star/sdb/DatabaseContext.hpp>
|
|
#include <com/sun/star/sdb/XSingleSelectQueryAnalyzer.hpp>
|
|
#include <com/sun/star/sdb/XCompletedConnection.hpp>
|
|
#include <com/sun/star/sdbc/XDataSource.hpp>
|
|
#include <com/sun/star/sdb/SQLContext.hpp>
|
|
#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
|
|
#include <com/sun/star/sdbcx/XViewsSupplier.hpp>
|
|
#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
|
|
#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp>
|
|
#include <com/sun/star/sdbcx/XAppend.hpp>
|
|
#include <com/sun/star/sdbc/XRow.hpp>
|
|
#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
|
|
#include <com/sun/star/sdbc/XResultSetMetaData.hpp>
|
|
#include <com/sun/star/sdbc/ColumnValue.hpp>
|
|
#include <com/sun/star/task/InteractionHandler.hpp>
|
|
#include <com/sun/star/ucb/XContent.hpp>
|
|
#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
|
|
#include <com/sun/star/beans/PropertyValue.hpp>
|
|
#include <com/sun/star/container/XNameContainer.hpp>
|
|
#include <com/sun/star/ucb/InteractiveIOException.hpp>
|
|
#include <com/sun/star/sdb/XDocumentDataSource.hpp>
|
|
#include <com/sun/star/ucb/IOErrorCode.hpp>
|
|
#include <vcl/syswin.hxx>
|
|
#include <vcl/settings.hxx>
|
|
#include <vcl/svapp.hxx>
|
|
#include <com/sun/star/beans/XPropertySetInfo.hpp>
|
|
#include <com/sun/star/beans/XPropertySet.hpp>
|
|
#include <com/sun/star/container/XNameAccess.hpp>
|
|
#include <com/sun/star/container/XHierarchicalNameContainer.hpp>
|
|
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
|
|
#include <com/sun/star/awt/TextAlign.hpp>
|
|
#include <TypeInfo.hxx>
|
|
#include <FieldDescriptions.hxx>
|
|
#include <comphelper/stl_types.hxx>
|
|
#include <comphelper/types.hxx>
|
|
#include <comphelper/propertysequence.hxx>
|
|
|
|
#include <svx/svxids.hrc>
|
|
|
|
#include <sal/log.hxx>
|
|
#include <svl/numformat.hxx>
|
|
#include <svl/itempool.hxx>
|
|
#include <helpids.h>
|
|
#include <svl/itemset.hxx>
|
|
#include <sbagrid.hrc>
|
|
#include <svl/rngitem.hxx>
|
|
#include <svl/intitem.hxx>
|
|
#include <svx/numinf.hxx>
|
|
#include <svl/zforlist.hxx>
|
|
#include <dlgattr.hxx>
|
|
#include <com/sun/star/container/XChild.hpp>
|
|
#include <com/sun/star/util/NumberFormatter.hpp>
|
|
#include <com/sun/star/util/XNumberFormatsSupplier.hpp>
|
|
#include <com/sun/star/util/XNumberFormatter.hpp>
|
|
#include <strings.hrc>
|
|
#include <sqlmessage.hxx>
|
|
#include <dlgsize.hxx>
|
|
#include <svtools/editbrowsebox.hxx>
|
|
#include <tools/urlobj.hxx>
|
|
#include <comphelper/diagnose_ex.hxx>
|
|
#include <svl/numuno.hxx>
|
|
#include <svl/filenotation.hxx>
|
|
#include <connectivity/FValue.hxx>
|
|
|
|
#include <editeng/justifyitem.hxx>
|
|
#include <memory>
|
|
|
|
namespace dbaui
|
|
{
|
|
using namespace ::dbtools;
|
|
using namespace ::comphelper;
|
|
using namespace ::com::sun::star;
|
|
using namespace ::com::sun::star::uno;
|
|
using namespace ::com::sun::star::task;
|
|
using namespace ::com::sun::star::sdbcx;
|
|
using namespace ::com::sun::star::sdbc;
|
|
using namespace ::com::sun::star::sdb;
|
|
using namespace ::com::sun::star::util;
|
|
using namespace ::com::sun::star::ucb;
|
|
using namespace ::com::sun::star::beans;
|
|
using namespace ::com::sun::star::container;
|
|
using namespace ::com::sun::star::lang;
|
|
using namespace ::svt;
|
|
using ::com::sun::star::ucb::InteractiveIOException;
|
|
using ::com::sun::star::ucb::IOErrorCode_NO_FILE;
|
|
using ::com::sun::star::ucb::IOErrorCode_NOT_EXISTING;
|
|
|
|
SQLExceptionInfo createConnection( const OUString& _rsDataSourceName,
|
|
const Reference< css::container::XNameAccess >& _xDatabaseContext,
|
|
const Reference< css::uno::XComponentContext >& _rxContext,
|
|
Reference< css::lang::XEventListener> const & _rEvtLst,
|
|
Reference< css::sdbc::XConnection>& _rOUTConnection )
|
|
{
|
|
Reference<XPropertySet> xProp;
|
|
try
|
|
{
|
|
xProp.set(_xDatabaseContext->getByName(_rsDataSourceName),UNO_QUERY);
|
|
}
|
|
catch(const Exception&)
|
|
{
|
|
}
|
|
|
|
return createConnection(xProp,_rxContext,_rEvtLst,_rOUTConnection);
|
|
}
|
|
|
|
SQLExceptionInfo createConnection( const Reference< css::beans::XPropertySet>& _xDataSource,
|
|
const Reference< css::uno::XComponentContext >& _rxContext,
|
|
Reference< css::lang::XEventListener> const & _rEvtLst,
|
|
Reference< css::sdbc::XConnection>& _rOUTConnection )
|
|
{
|
|
SQLExceptionInfo aInfo;
|
|
if ( !_xDataSource.is() )
|
|
{
|
|
SAL_WARN("dbaccess.ui", "createConnection: could not retrieve the data source!");
|
|
return aInfo;
|
|
}
|
|
|
|
OUString sPwd, sUser;
|
|
bool bPwdReq = false;
|
|
try
|
|
{
|
|
_xDataSource->getPropertyValue(PROPERTY_PASSWORD) >>= sPwd;
|
|
bPwdReq = ::cppu::any2bool(_xDataSource->getPropertyValue(PROPERTY_ISPASSWORDREQUIRED));
|
|
_xDataSource->getPropertyValue(PROPERTY_USER) >>= sUser;
|
|
}
|
|
catch(const Exception&)
|
|
{
|
|
SAL_WARN("dbaccess.ui", "createConnection: error while retrieving data source properties!");
|
|
}
|
|
|
|
try
|
|
{
|
|
if(bPwdReq && sPwd.isEmpty())
|
|
{ // password required, but empty -> connect using an interaction handler
|
|
Reference<XCompletedConnection> xConnectionCompletion(_xDataSource, UNO_QUERY);
|
|
if (!xConnectionCompletion.is())
|
|
{
|
|
SAL_WARN("dbaccess.ui", "createConnection: missing an interface ... need an error message here!");
|
|
}
|
|
else
|
|
{ // instantiate the default SDB interaction handler
|
|
Reference< XInteractionHandler > xHandler = InteractionHandler::createWithParent(_rxContext, nullptr);
|
|
_rOUTConnection = xConnectionCompletion->connectWithCompletion(xHandler);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Reference<XDataSource> xDataSource(_xDataSource,UNO_QUERY);
|
|
_rOUTConnection = xDataSource->getConnection(sUser, sPwd);
|
|
}
|
|
// be notified when connection is in disposing
|
|
Reference< XComponent > xComponent(_rOUTConnection, UNO_QUERY);
|
|
if (xComponent.is() && _rEvtLst.is())
|
|
xComponent->addEventListener(_rEvtLst);
|
|
}
|
|
catch(const SQLContext& e) { aInfo = SQLExceptionInfo(e); }
|
|
catch(const SQLWarning& e) { aInfo = SQLExceptionInfo(e); }
|
|
catch(const SQLException& e) { aInfo = SQLExceptionInfo(e); }
|
|
catch(const Exception&) {
|
|
TOOLS_WARN_EXCEPTION("dbaccess.ui", "SbaTableQueryBrowser::OnExpandEntry: could not connect - unknown exception");
|
|
}
|
|
|
|
return aInfo;
|
|
}
|
|
|
|
Reference< XDataSource > getDataSourceByName( const OUString& _rDataSourceName,
|
|
weld::Window* _pErrorMessageParent, const Reference< XComponentContext >& _rxContext, ::dbtools::SQLExceptionInfo* _pErrorInfo )
|
|
{
|
|
Reference< XDatabaseContext > xDatabaseContext = DatabaseContext::create(_rxContext);
|
|
|
|
Reference< XDataSource > xDatasource;
|
|
SQLExceptionInfo aSQLError;
|
|
try
|
|
{
|
|
xDatabaseContext->getByName( _rDataSourceName ) >>= xDatasource;
|
|
}
|
|
catch(const WrappedTargetException& e)
|
|
{
|
|
InteractiveIOException aIOException;
|
|
if ( ( e.TargetException >>= aIOException )
|
|
&& ( ( aIOException.Code == IOErrorCode_NO_FILE )
|
|
|| ( aIOException.Code == IOErrorCode_NOT_EXISTING )
|
|
)
|
|
)
|
|
{
|
|
OUString sErrorMessage( DBA_RES( STR_FILE_DOES_NOT_EXIST ) );
|
|
OFileNotation aTransformer( e.Message );
|
|
sErrorMessage = sErrorMessage.replaceFirst( "$file$", aTransformer.get( OFileNotation::N_SYSTEM ) );
|
|
aSQLError = SQLExceptionInfo( sErrorMessage ).get();
|
|
}
|
|
else
|
|
{
|
|
aSQLError = SQLExceptionInfo( e.TargetException );
|
|
}
|
|
}
|
|
catch( const Exception& )
|
|
{
|
|
DBG_UNHANDLED_EXCEPTION("dbaccess");
|
|
}
|
|
|
|
if ( xDatasource.is() )
|
|
return xDatasource;
|
|
|
|
if ( aSQLError.isValid() )
|
|
{
|
|
if ( _pErrorInfo )
|
|
{
|
|
*_pErrorInfo = std::move(aSQLError);
|
|
}
|
|
else
|
|
{
|
|
showError( aSQLError, _pErrorMessageParent ? _pErrorMessageParent->GetXWindow() : nullptr, _rxContext );
|
|
}
|
|
}
|
|
|
|
return Reference<XDataSource>();
|
|
}
|
|
|
|
Reference< XInterface > getDataSourceOrModel(const Reference< XInterface >& _xObject)
|
|
{
|
|
Reference< XInterface > xRet;
|
|
Reference<XDocumentDataSource> xDocumentDataSource(_xObject,UNO_QUERY);
|
|
if ( xDocumentDataSource.is() )
|
|
xRet = xDocumentDataSource->getDatabaseDocument();
|
|
|
|
if ( !xRet.is() )
|
|
{
|
|
Reference<XOfficeDatabaseDocument> xOfficeDoc(_xObject,UNO_QUERY);
|
|
if ( xOfficeDoc.is() )
|
|
xRet = xOfficeDoc->getDataSource();
|
|
}
|
|
|
|
return xRet;
|
|
}
|
|
|
|
TOTypeInfoSP getTypeInfoFromType(const OTypeInfoMap& _rTypeInfo,
|
|
sal_Int32 _nType,
|
|
const OUString& _sTypeName,
|
|
const OUString& _sCreateParams,
|
|
sal_Int32 _nPrecision,
|
|
sal_Int32 _nScale,
|
|
bool _bAutoIncrement,
|
|
bool& _brForceToType)
|
|
{
|
|
TOTypeInfoSP pTypeInfo;
|
|
_brForceToType = false;
|
|
// search for type
|
|
std::pair<OTypeInfoMap::const_iterator, OTypeInfoMap::const_iterator> aPair = _rTypeInfo.equal_range(_nType);
|
|
OTypeInfoMap::const_iterator aIter = aPair.first;
|
|
if(aIter != _rTypeInfo.end()) // compare with end is correct here
|
|
{
|
|
for(;aIter != aPair.second;++aIter)
|
|
{
|
|
// search the best matching type
|
|
#ifdef DBG_UTIL
|
|
OUString sDBTypeName = aIter->second->aTypeName; (void)sDBTypeName;
|
|
#endif
|
|
if ( (
|
|
_sTypeName.isEmpty()
|
|
|| (aIter->second->aTypeName.equalsIgnoreAsciiCase(_sTypeName))
|
|
)
|
|
&& (
|
|
(
|
|
!aIter->second->aCreateParams.getLength()
|
|
&& _sCreateParams.isEmpty()
|
|
)
|
|
|| (
|
|
(aIter->second->nPrecision >= _nPrecision)
|
|
&& (aIter->second->nMaximumScale >= _nScale)
|
|
&& ( (_bAutoIncrement && aIter->second->bAutoIncrement) || !_bAutoIncrement )
|
|
)
|
|
)
|
|
)
|
|
break;
|
|
}
|
|
|
|
if (aIter == aPair.second)
|
|
{
|
|
for(aIter = aPair.first; aIter != aPair.second; ++aIter)
|
|
{
|
|
sal_Int32 nPrec = aIter->second->nPrecision;
|
|
sal_Int32 nScale = aIter->second->nMaximumScale;
|
|
// search the best matching type (now comparing the local names)
|
|
if ( (aIter->second->aLocalTypeName.equalsIgnoreAsciiCase(_sTypeName))
|
|
&& (nPrec >= _nPrecision)
|
|
&& (nScale >= _nScale)
|
|
&& ( (_bAutoIncrement && aIter->second->bAutoIncrement) || !_bAutoIncrement )
|
|
)
|
|
{
|
|
SAL_WARN("dbaccess.ui", "getTypeInfoFromType: assuming column type " <<
|
|
aIter->second->aTypeName << "\" (expected type name " <<
|
|
_sTypeName << " matches the type's local name).");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (aIter == aPair.second)
|
|
{ // no match for the names, no match for the local names
|
|
// -> drop the precision and the scale restriction, accept any type with the property
|
|
// type id (nType)
|
|
|
|
for(aIter = aPair.first; aIter != aPair.second; ++aIter)
|
|
{
|
|
// search the best matching type (now comparing the local names)
|
|
sal_Int32 nPrec = aIter->second->nPrecision;
|
|
sal_Int32 nScale = aIter->second->nMaximumScale;
|
|
if ( (nPrec >= _nPrecision)
|
|
&& (nScale >= _nScale)
|
|
&& ( (_bAutoIncrement && aIter->second->bAutoIncrement) || !_bAutoIncrement )
|
|
)
|
|
break;
|
|
}
|
|
}
|
|
if (aIter == aPair.second)
|
|
{
|
|
if ( _bAutoIncrement )
|
|
{
|
|
for(aIter = aPair.first; aIter != aPair.second; ++aIter)
|
|
{
|
|
// search the best matching type (now comparing the local names)
|
|
sal_Int32 nScale = aIter->second->nMaximumScale;
|
|
if ( (nScale >= _nScale)
|
|
&& (aIter->second->bAutoIncrement == _bAutoIncrement)
|
|
)
|
|
break;
|
|
}
|
|
if ( aIter == aPair.second )
|
|
{
|
|
// try it without the auto increment flag
|
|
pTypeInfo = getTypeInfoFromType(_rTypeInfo,
|
|
_nType,
|
|
_sTypeName,
|
|
_sCreateParams,
|
|
_nPrecision,
|
|
_nScale,
|
|
false,
|
|
_brForceToType);
|
|
}
|
|
else
|
|
pTypeInfo = aIter->second;
|
|
}
|
|
else
|
|
{
|
|
pTypeInfo = aPair.first->second;
|
|
_brForceToType = true;
|
|
}
|
|
}
|
|
else
|
|
pTypeInfo = aIter->second;
|
|
}
|
|
else
|
|
{
|
|
::comphelper::UStringMixEqual aCase(false);
|
|
// search for typeinfo where the typename is equal _sTypeName
|
|
for (auto const& elem : _rTypeInfo)
|
|
{
|
|
if ( aCase( elem.second->getDBName() , _sTypeName ) )
|
|
{
|
|
pTypeInfo = elem.second;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
OSL_ENSURE(pTypeInfo, "getTypeInfoFromType: no type info found for this type!");
|
|
return pTypeInfo;
|
|
}
|
|
|
|
void fillTypeInfo( const Reference< css::sdbc::XConnection>& _rxConnection,
|
|
std::u16string_view _rsTypeNames,
|
|
OTypeInfoMap& _rTypeInfoMap,
|
|
std::vector<OTypeInfoMap::iterator>& _rTypeInfoIters)
|
|
{
|
|
if(!_rxConnection.is())
|
|
return;
|
|
Reference< XResultSet> xRs = _rxConnection->getMetaData ()->getTypeInfo ();
|
|
Reference< XRow> xRow(xRs,UNO_QUERY);
|
|
// Information for a single SQL type
|
|
if(!xRs.is())
|
|
return;
|
|
|
|
Reference<XResultSetMetaData> xResultSetMetaData = Reference<XResultSetMetaDataSupplier>(xRs,UNO_QUERY_THROW)->getMetaData();
|
|
::connectivity::ORowSetValue aValue;
|
|
std::vector<sal_Int32> aTypes;
|
|
std::vector<bool> aNullable;
|
|
// Loop on the result set until we reach end of file
|
|
while (xRs->next())
|
|
{
|
|
TOTypeInfoSP pInfo = std::make_shared<OTypeInfo>();
|
|
sal_Int32 nPos = 1;
|
|
if ( aTypes.empty() )
|
|
{
|
|
sal_Int32 nCount = xResultSetMetaData->getColumnCount();
|
|
if ( nCount < 1 )
|
|
nCount = 18;
|
|
aTypes.reserve(nCount+1);
|
|
aTypes.push_back(-1);
|
|
aNullable.push_back(false);
|
|
for (sal_Int32 j = 1; j <= nCount ; ++j)
|
|
{
|
|
aTypes.push_back(xResultSetMetaData->getColumnType(j));
|
|
aNullable.push_back(xResultSetMetaData->isNullable(j) != ColumnValue::NO_NULLS);
|
|
}
|
|
}
|
|
|
|
aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
|
|
pInfo->aTypeName = aValue.getString();
|
|
++nPos;
|
|
aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
|
|
pInfo->nType = aValue.getInt32();
|
|
++nPos;
|
|
aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
|
|
pInfo->nPrecision = aValue.getInt32();
|
|
++nPos;
|
|
aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); // LiteralPrefix
|
|
++nPos;
|
|
aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); //LiteralSuffix
|
|
++nPos;
|
|
aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
|
|
pInfo->aCreateParams = aValue.getString();
|
|
++nPos;
|
|
aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
|
|
pInfo->bNullable = aValue.getInt32() == ColumnValue::NULLABLE;
|
|
++nPos;
|
|
aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
|
|
// bCaseSensitive
|
|
++nPos;
|
|
aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
|
|
pInfo->nSearchType = aValue.getInt16();
|
|
++nPos;
|
|
aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
|
|
// bUnsigned
|
|
++nPos;
|
|
aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
|
|
pInfo->bCurrency = aValue.getBool();
|
|
++nPos;
|
|
aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
|
|
pInfo->bAutoIncrement = aValue.getBool();
|
|
++nPos;
|
|
aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
|
|
pInfo->aLocalTypeName = aValue.getString();
|
|
++nPos;
|
|
aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
|
|
pInfo->nMinimumScale = aValue.getInt16();
|
|
++nPos;
|
|
aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
|
|
pInfo->nMaximumScale = aValue.getInt16();
|
|
assert(nPos == 15);
|
|
// 16 and 17 are unused
|
|
nPos = 18;
|
|
aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
|
|
pInfo->nNumPrecRadix = aValue.getInt32();
|
|
|
|
// check if values are less than zero like it happens in a oracle jdbc driver
|
|
if( pInfo->nPrecision < 0)
|
|
pInfo->nPrecision = 0;
|
|
if( pInfo->nMinimumScale < 0)
|
|
pInfo->nMinimumScale = 0;
|
|
if( pInfo->nMaximumScale < 0)
|
|
pInfo->nMaximumScale = 0;
|
|
if( pInfo->nNumPrecRadix <= 1)
|
|
pInfo->nNumPrecRadix = 10;
|
|
|
|
std::u16string_view aName;
|
|
switch(pInfo->nType)
|
|
{
|
|
case DataType::CHAR:
|
|
aName = o3tl::getToken(_rsTypeNames, TYPE_CHAR, ';');
|
|
break;
|
|
case DataType::VARCHAR:
|
|
aName = o3tl::getToken(_rsTypeNames, TYPE_TEXT, ';');
|
|
break;
|
|
case DataType::DECIMAL:
|
|
aName = o3tl::getToken(_rsTypeNames, TYPE_DECIMAL, ';');
|
|
break;
|
|
case DataType::NUMERIC:
|
|
aName = o3tl::getToken(_rsTypeNames, TYPE_NUMERIC, ';');
|
|
break;
|
|
case DataType::BIGINT:
|
|
aName = o3tl::getToken(_rsTypeNames, TYPE_BIGINT, ';');
|
|
break;
|
|
case DataType::FLOAT:
|
|
aName = o3tl::getToken(_rsTypeNames, TYPE_FLOAT, ';');
|
|
break;
|
|
case DataType::DOUBLE:
|
|
aName = o3tl::getToken(_rsTypeNames, TYPE_DOUBLE, ';');
|
|
break;
|
|
case DataType::LONGVARCHAR:
|
|
aName = o3tl::getToken(_rsTypeNames, TYPE_MEMO, ';');
|
|
break;
|
|
case DataType::LONGVARBINARY:
|
|
aName = o3tl::getToken(_rsTypeNames, TYPE_IMAGE, ';');
|
|
break;
|
|
case DataType::DATE:
|
|
aName = o3tl::getToken(_rsTypeNames, TYPE_DATE, ';');
|
|
break;
|
|
case DataType::TIME:
|
|
aName = o3tl::getToken(_rsTypeNames, TYPE_TIME, ';');
|
|
break;
|
|
case DataType::TIMESTAMP:
|
|
aName = o3tl::getToken(_rsTypeNames, TYPE_DATETIME, ';');
|
|
break;
|
|
case DataType::BIT:
|
|
if ( !pInfo->aCreateParams.isEmpty() )
|
|
{
|
|
aName = o3tl::getToken(_rsTypeNames, TYPE_BIT, ';');
|
|
break;
|
|
}
|
|
[[fallthrough]];
|
|
case DataType::BOOLEAN:
|
|
aName = o3tl::getToken(_rsTypeNames, TYPE_BOOL, ';');
|
|
break;
|
|
case DataType::TINYINT:
|
|
aName = o3tl::getToken(_rsTypeNames, TYPE_TINYINT, ';');
|
|
break;
|
|
case DataType::SMALLINT:
|
|
aName = o3tl::getToken(_rsTypeNames, TYPE_SMALLINT, ';');
|
|
break;
|
|
case DataType::INTEGER:
|
|
aName = o3tl::getToken(_rsTypeNames, TYPE_INTEGER, ';');
|
|
break;
|
|
case DataType::REAL:
|
|
aName = o3tl::getToken(_rsTypeNames, TYPE_REAL, ';');
|
|
break;
|
|
case DataType::BINARY:
|
|
aName = o3tl::getToken(_rsTypeNames, TYPE_BINARY, ';');
|
|
break;
|
|
case DataType::VARBINARY:
|
|
aName = o3tl::getToken(_rsTypeNames, TYPE_VARBINARY, ';');
|
|
break;
|
|
case DataType::SQLNULL:
|
|
aName = o3tl::getToken(_rsTypeNames, TYPE_SQLNULL, ';');
|
|
break;
|
|
case DataType::OBJECT:
|
|
aName = o3tl::getToken(_rsTypeNames, TYPE_OBJECT, ';');
|
|
break;
|
|
case DataType::DISTINCT:
|
|
aName = o3tl::getToken(_rsTypeNames, TYPE_DISTINCT, ';');
|
|
break;
|
|
case DataType::STRUCT:
|
|
aName = o3tl::getToken(_rsTypeNames, TYPE_STRUCT, ';');
|
|
break;
|
|
case DataType::ARRAY:
|
|
aName = o3tl::getToken(_rsTypeNames, TYPE_ARRAY, ';');
|
|
break;
|
|
case DataType::BLOB:
|
|
aName = o3tl::getToken(_rsTypeNames, TYPE_BLOB, ';');
|
|
break;
|
|
case DataType::CLOB:
|
|
aName = o3tl::getToken(_rsTypeNames, TYPE_CLOB, ';');
|
|
break;
|
|
case DataType::REF:
|
|
aName = o3tl::getToken(_rsTypeNames, TYPE_REF, ';');
|
|
break;
|
|
case DataType::OTHER:
|
|
aName = o3tl::getToken(_rsTypeNames, TYPE_OTHER, ';');
|
|
break;
|
|
}
|
|
if ( !aName.empty() )
|
|
{
|
|
pInfo->aUIName = aName;
|
|
pInfo->aUIName += " [ ";
|
|
}
|
|
pInfo->aUIName += pInfo->aTypeName;
|
|
if ( !aName.empty() )
|
|
pInfo->aUIName += " ]";
|
|
// Now that we have the type info, save it in the multimap
|
|
_rTypeInfoMap.emplace(pInfo->nType,pInfo);
|
|
}
|
|
// for a faster index access
|
|
_rTypeInfoIters.reserve(_rTypeInfoMap.size());
|
|
|
|
OTypeInfoMap::iterator aIter = _rTypeInfoMap.begin();
|
|
OTypeInfoMap::const_iterator aEnd = _rTypeInfoMap.end();
|
|
for(;aIter != aEnd;++aIter)
|
|
_rTypeInfoIters.push_back(aIter);
|
|
|
|
// Close the result set/statement.
|
|
|
|
::comphelper::disposeComponent(xRs);
|
|
}
|
|
|
|
void setColumnProperties(const Reference<XPropertySet>& _rxColumn,const OFieldDescription* _pFieldDesc)
|
|
{
|
|
_rxColumn->setPropertyValue(PROPERTY_NAME,Any(_pFieldDesc->GetName()));
|
|
_rxColumn->setPropertyValue(PROPERTY_TYPENAME,Any(_pFieldDesc->getTypeInfo()->aTypeName));
|
|
_rxColumn->setPropertyValue(PROPERTY_TYPE,Any(_pFieldDesc->GetType()));
|
|
_rxColumn->setPropertyValue(PROPERTY_PRECISION,Any(_pFieldDesc->GetPrecision()));
|
|
_rxColumn->setPropertyValue(PROPERTY_SCALE,Any(_pFieldDesc->GetScale()));
|
|
_rxColumn->setPropertyValue(PROPERTY_ISNULLABLE, Any(_pFieldDesc->GetIsNullable()));
|
|
_rxColumn->setPropertyValue(PROPERTY_ISAUTOINCREMENT, css::uno::Any(_pFieldDesc->IsAutoIncrement()));
|
|
_rxColumn->setPropertyValue(PROPERTY_DESCRIPTION,Any(_pFieldDesc->GetDescription()));
|
|
if ( _rxColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_ISCURRENCY) && _pFieldDesc->IsCurrency() )
|
|
_rxColumn->setPropertyValue(PROPERTY_ISCURRENCY, css::uno::Any(_pFieldDesc->IsCurrency()));
|
|
// set autoincrement value when available
|
|
// and only set when the entry is not empty, that lets the value in the column untouched
|
|
if ( _pFieldDesc->IsAutoIncrement() && !_pFieldDesc->GetAutoIncrementValue().isEmpty() && _rxColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_AUTOINCREMENTCREATION) )
|
|
_rxColumn->setPropertyValue(PROPERTY_AUTOINCREMENTCREATION,Any(_pFieldDesc->GetAutoIncrementValue()));
|
|
}
|
|
|
|
OUString createDefaultName(const Reference< XDatabaseMetaData>& _xMetaData,const Reference<XNameAccess>& _xTables,const OUString& _sName)
|
|
{
|
|
OSL_ENSURE(_xMetaData.is(),"No MetaData!");
|
|
OUString sDefaultName = _sName;
|
|
try
|
|
{
|
|
OUString sCatalog,sSchema,sCompsedName;
|
|
if(_xMetaData->supportsCatalogsInTableDefinitions())
|
|
{
|
|
try
|
|
{
|
|
Reference< XConnection> xCon = _xMetaData->getConnection();
|
|
if ( xCon.is() )
|
|
sCatalog = xCon->getCatalog();
|
|
if ( sCatalog.isEmpty() )
|
|
{
|
|
Reference<XResultSet> xRes = _xMetaData->getCatalogs();
|
|
Reference<XRow> xRow(xRes,UNO_QUERY);
|
|
while(xRes.is() && xRes->next())
|
|
{
|
|
sCatalog = xRow->getString(1);
|
|
if(!xRow->wasNull())
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
catch(const SQLException&)
|
|
{
|
|
}
|
|
}
|
|
if(_xMetaData->supportsSchemasInTableDefinitions())
|
|
{
|
|
sSchema = _xMetaData->getUserName();
|
|
}
|
|
sCompsedName = ::dbtools::composeTableName( _xMetaData, sCatalog, sSchema, _sName, false, ::dbtools::EComposeRule::InDataManipulation );
|
|
sDefaultName = ::dbtools::createUniqueName(_xTables,sCompsedName);
|
|
}
|
|
catch(const SQLException&)
|
|
{
|
|
}
|
|
return sDefaultName;
|
|
}
|
|
|
|
bool checkDataSourceAvailable(const OUString& _sDataSourceName,const Reference< css::uno::XComponentContext >& _xContext)
|
|
{
|
|
Reference< XDatabaseContext > xDataBaseContext = DatabaseContext::create(_xContext);
|
|
bool bRet = xDataBaseContext->hasByName(_sDataSourceName);
|
|
if ( !bRet )
|
|
{ // try if this one is a URL
|
|
try
|
|
{
|
|
bRet = xDataBaseContext->getByName(_sDataSourceName).hasValue();
|
|
}
|
|
catch(const Exception&)
|
|
{
|
|
}
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
sal_Int32 mapTextAlign(const SvxCellHorJustify& _eAlignment)
|
|
{
|
|
sal_Int32 nAlignment = css::awt::TextAlign::LEFT;
|
|
switch (_eAlignment)
|
|
{
|
|
case SvxCellHorJustify::Standard:
|
|
case SvxCellHorJustify::Left: nAlignment = css::awt::TextAlign::LEFT; break;
|
|
case SvxCellHorJustify::Center: nAlignment = css::awt::TextAlign::CENTER; break;
|
|
case SvxCellHorJustify::Right: nAlignment = css::awt::TextAlign::RIGHT; break;
|
|
default:
|
|
SAL_WARN("dbaccess.ui", "Invalid TextAlign!");
|
|
}
|
|
return nAlignment;
|
|
}
|
|
|
|
SvxCellHorJustify mapTextJustify(sal_Int32 _nAlignment)
|
|
{
|
|
SvxCellHorJustify eJustify = SvxCellHorJustify::Left;
|
|
switch (_nAlignment)
|
|
{
|
|
case css::awt::TextAlign::LEFT : eJustify = SvxCellHorJustify::Left; break;
|
|
case css::awt::TextAlign::CENTER : eJustify = SvxCellHorJustify::Center; break;
|
|
case css::awt::TextAlign::RIGHT : eJustify = SvxCellHorJustify::Right; break;
|
|
default:
|
|
SAL_WARN("dbaccess.ui", "Invalid TextAlign!");
|
|
}
|
|
return eJustify;
|
|
}
|
|
|
|
void callColumnFormatDialog(const Reference<XPropertySet>& xAffectedCol,
|
|
const Reference<XPropertySet>& xField,
|
|
SvNumberFormatter* _pFormatter,
|
|
weld::Widget* _pParent)
|
|
{
|
|
if (!(xAffectedCol.is() && xField.is()))
|
|
return;
|
|
|
|
try
|
|
{
|
|
Reference< XPropertySetInfo > xInfo = xAffectedCol->getPropertySetInfo();
|
|
bool bHasFormat = xInfo->hasPropertyByName(PROPERTY_FORMATKEY);
|
|
sal_Int32 nDataType = ::comphelper::getINT32(xField->getPropertyValue(PROPERTY_TYPE));
|
|
|
|
SvxCellHorJustify eJustify(SvxCellHorJustify::Standard);
|
|
Any aAlignment = xAffectedCol->getPropertyValue(PROPERTY_ALIGN);
|
|
if (aAlignment.hasValue())
|
|
eJustify = dbaui::mapTextJustify(::comphelper::getINT16(aAlignment));
|
|
sal_Int32 nFormatKey = 0;
|
|
if ( bHasFormat )
|
|
nFormatKey = ::comphelper::getINT32(xAffectedCol->getPropertyValue(PROPERTY_FORMATKEY));
|
|
|
|
if(callColumnFormatDialog(_pParent,_pFormatter,nDataType,nFormatKey,eJustify,bHasFormat))
|
|
{
|
|
xAffectedCol->setPropertyValue(PROPERTY_ALIGN, Any(static_cast<sal_Int16>(dbaui::mapTextAlign(eJustify))));
|
|
if (bHasFormat)
|
|
xAffectedCol->setPropertyValue(PROPERTY_FORMATKEY, Any(nFormatKey));
|
|
|
|
}
|
|
}
|
|
catch( const Exception& )
|
|
{
|
|
DBG_UNHANDLED_EXCEPTION("dbaccess");
|
|
}
|
|
}
|
|
|
|
static ItemInfoPackage& getItemInfoPackageColumnFormatDialog()
|
|
{
|
|
class ItemInfoPackageColumnFormatDialog : public ItemInfoPackage
|
|
{
|
|
typedef std::array<ItemInfoStatic, SBA_ATTR_ALIGN_HOR_JUSTIFY - SBA_DEF_RANGEFORMAT + 1> ItemInfoArrayColumnFormatDialog;
|
|
ItemInfoArrayColumnFormatDialog maItemInfos {{
|
|
// m_nWhich, m_pItem, m_nSlotID, m_nItemInfoFlags
|
|
{ SBA_DEF_RANGEFORMAT, new SfxRangeItem(SBA_DEF_RANGEFORMAT, SBA_DEF_FMTVALUE, SBA_ATTR_ALIGN_HOR_JUSTIFY), 0, SFX_ITEMINFOFLAG_NONE },
|
|
{ SBA_DEF_FMTVALUE, new SfxUInt32Item(SBA_DEF_FMTVALUE), SID_ATTR_NUMBERFORMAT_VALUE, SFX_ITEMINFOFLAG_NONE },
|
|
{ SBA_ATTR_ALIGN_HOR_JUSTIFY, new SvxHorJustifyItem(SvxCellHorJustify::Standard, SBA_ATTR_ALIGN_HOR_JUSTIFY), SID_ATTR_ALIGN_HOR_JUSTIFY, SFX_ITEMINFOFLAG_NONE },
|
|
}};
|
|
|
|
virtual const ItemInfoStatic& getItemInfoStatic(size_t nIndex) const override { return maItemInfos[nIndex]; }
|
|
|
|
public:
|
|
virtual size_t size() const override { return maItemInfos.size(); }
|
|
virtual const ItemInfo& getItemInfo(size_t nIndex, SfxItemPool& /*rPool*/) override { return maItemInfos[nIndex]; }
|
|
};
|
|
|
|
static std::unique_ptr<ItemInfoPackageColumnFormatDialog> g_aItemInfoPackageColumnFormatDialog;
|
|
if (!g_aItemInfoPackageColumnFormatDialog)
|
|
g_aItemInfoPackageColumnFormatDialog.reset(new ItemInfoPackageColumnFormatDialog);
|
|
return *g_aItemInfoPackageColumnFormatDialog;
|
|
}
|
|
|
|
bool callColumnFormatDialog(weld::Widget* _pParent,
|
|
SvNumberFormatter* _pFormatter,
|
|
sal_Int32 _nDataType,
|
|
sal_Int32& _nFormatKey,
|
|
SvxCellHorJustify& _eJustify,
|
|
bool _bHasFormat)
|
|
{
|
|
bool bRet = false;
|
|
|
|
// UNO->ItemSet
|
|
static const auto aAttrMap = svl::Items<
|
|
SBA_DEF_RANGEFORMAT, SBA_ATTR_ALIGN_HOR_JUSTIFY,
|
|
SID_ATTR_NUMBERFORMAT_INFO, SID_ATTR_NUMBERFORMAT_INFO,
|
|
SID_ATTR_NUMBERFORMAT_ONE_AREA, SID_ATTR_NUMBERFORMAT_ONE_AREA
|
|
>;
|
|
|
|
rtl::Reference<SfxItemPool> pPool(new SfxItemPool(u"GridBrowserProperties"_ustr));
|
|
pPool->registerItemInfoPackage(getItemInfoPackageColumnFormatDialog());
|
|
pPool->SetDefaultMetric( MapUnit::MapTwip ); // ripped, don't understand why
|
|
|
|
std::optional<SfxItemSet> pFormatDescriptor(SfxItemSet(*pPool, aAttrMap));
|
|
// fill it
|
|
pFormatDescriptor->Put(SvxHorJustifyItem(_eJustify, SBA_ATTR_ALIGN_HOR_JUSTIFY));
|
|
bool bText = false;
|
|
if (_bHasFormat)
|
|
{
|
|
// if the col is bound to a text field we have to disallow all non-text formats
|
|
if ((DataType::CHAR == _nDataType) || (DataType::VARCHAR == _nDataType) || (DataType::LONGVARCHAR == _nDataType) || (DataType::CLOB == _nDataType))
|
|
{
|
|
bText = true;
|
|
pFormatDescriptor->Put(SfxBoolItem(SID_ATTR_NUMBERFORMAT_ONE_AREA, true));
|
|
if (!_pFormatter->IsTextFormat(_nFormatKey))
|
|
// text fields can only have text formats
|
|
_nFormatKey = _pFormatter->GetStandardFormat(SvNumFormatType::TEXT, Application::GetSettings().GetLanguageTag().getLanguageType());
|
|
}
|
|
|
|
pFormatDescriptor->Put(SfxUInt32Item(SBA_DEF_FMTVALUE, _nFormatKey));
|
|
}
|
|
|
|
if (!bText)
|
|
{
|
|
SvxNumberInfoItem aFormatter(_pFormatter, 1234.56789, SID_ATTR_NUMBERFORMAT_INFO);
|
|
pFormatDescriptor->Put(aFormatter);
|
|
}
|
|
|
|
{ // want the dialog to be destroyed before our set
|
|
SbaSbAttrDlg aDlg(_pParent, &*pFormatDescriptor, _pFormatter, _bHasFormat);
|
|
if (RET_OK == aDlg.run())
|
|
{
|
|
// ItemSet->UNO
|
|
// UNO-properties
|
|
const SfxItemSet* pSet = aDlg.GetExampleSet();
|
|
// (of course we could put the modified items directly into the column, but then the UNO-model
|
|
// won't reflect these changes, and why do we have a model, then ?)
|
|
|
|
// horizontal justify
|
|
const SvxHorJustifyItem* pHorJustify = pSet->GetItem<SvxHorJustifyItem>(SBA_ATTR_ALIGN_HOR_JUSTIFY);
|
|
|
|
_eJustify = pHorJustify->GetValue();
|
|
|
|
// format key
|
|
if (_bHasFormat)
|
|
{
|
|
const SfxUInt32Item* pFormat = pSet->GetItem<SfxUInt32Item>(SBA_DEF_FMTVALUE);
|
|
_nFormatKey = static_cast<sal_Int32>(pFormat->GetValue());
|
|
}
|
|
bRet = true;
|
|
}
|
|
// deleted formats
|
|
const SfxItemSet* pResult = aDlg.GetOutputItemSet();
|
|
if (pResult)
|
|
{
|
|
const SfxPoolItem* pItem = pResult->GetItem( SID_ATTR_NUMBERFORMAT_INFO );
|
|
const SvxNumberInfoItem* pInfoItem = static_cast<const SvxNumberInfoItem*>(pItem);
|
|
if (pInfoItem)
|
|
{
|
|
for (sal_uInt32 key : pInfoItem->GetDelFormats())
|
|
_pFormatter->DeleteEntry(key);
|
|
}
|
|
}
|
|
}
|
|
|
|
pFormatDescriptor.reset();
|
|
pPool.clear();
|
|
|
|
return bRet;
|
|
}
|
|
|
|
std::shared_ptr<const SfxFilter> getStandardDatabaseFilter()
|
|
{
|
|
std::shared_ptr<const SfxFilter> pFilter = SfxFilter::GetFilterByName(u"StarOffice XML (Base)"_ustr);
|
|
OSL_ENSURE(pFilter,"Filter: StarOffice XML (Base) could not be found!");
|
|
return pFilter;
|
|
}
|
|
|
|
bool appendToFilter(const Reference<XConnection>& _xConnection,
|
|
const OUString& _sName,
|
|
const Reference< XComponentContext >& _rxContext,
|
|
weld::Window* pParent)
|
|
{
|
|
bool bRet = false;
|
|
Reference< XChild> xChild(_xConnection,UNO_QUERY);
|
|
if(xChild.is())
|
|
{
|
|
Reference< XPropertySet> xProp(xChild->getParent(),UNO_QUERY);
|
|
if(xProp.is())
|
|
{
|
|
Sequence< OUString > aFilter;
|
|
xProp->getPropertyValue(PROPERTY_TABLEFILTER) >>= aFilter;
|
|
// first check if we have something like SCHEMA.%
|
|
bool bHasToInsert = true;
|
|
for (const OUString& rItem : aFilter)
|
|
{
|
|
if(rItem.indexOf('%') != -1)
|
|
{
|
|
sal_Int32 nLen = rItem.lastIndexOf('.');
|
|
if(nLen != -1 && !rItem.compareTo(_sName,nLen))
|
|
bHasToInsert = false;
|
|
else if(rItem.getLength() == 1)
|
|
bHasToInsert = false;
|
|
}
|
|
}
|
|
|
|
bRet = true;
|
|
if(bHasToInsert)
|
|
{
|
|
if(! ::dbaui::checkDataSourceAvailable(::comphelper::getString(xProp->getPropertyValue(PROPERTY_NAME)),_rxContext))
|
|
{
|
|
OUString aMessage(DBA_RES(STR_TABLEDESIGN_DATASOURCE_DELETED));
|
|
OSQLWarningBox aWarning(pParent, aMessage);
|
|
aWarning.run();
|
|
bRet = false;
|
|
}
|
|
else
|
|
{
|
|
aFilter.realloc(aFilter.getLength()+1);
|
|
aFilter.getArray()[aFilter.getLength()-1] = _sName;
|
|
xProp->setPropertyValue(PROPERTY_TABLEFILTER,Any(aFilter));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
void notifySystemWindow(vcl::Window const * _pWindow, vcl::Window* _pToRegister, const ::comphelper::mem_fun1_t<TaskPaneList,vcl::Window*>& _rMemFunc)
|
|
{
|
|
OSL_ENSURE(_pWindow,"Window can not be null!");
|
|
SystemWindow* pSystemWindow = _pWindow ? _pWindow->GetSystemWindow() : nullptr;
|
|
if ( pSystemWindow )
|
|
{
|
|
_rMemFunc( pSystemWindow->GetTaskPaneList(), _pToRegister );
|
|
}
|
|
}
|
|
|
|
void adjustBrowseBoxColumnWidth( ::svt::EditBrowseBox* _pBox, sal_uInt16 _nColId )
|
|
{
|
|
sal_Int32 nColSize = -1;
|
|
::tools::Long nDefaultWidth = _pBox->GetDefaultColumnWidth( _pBox->GetColumnTitle( _nColId ) );
|
|
if ( nDefaultWidth != _pBox->GetColumnWidth( _nColId ) )
|
|
{
|
|
Size aSizeMM = _pBox->PixelToLogic( Size( _pBox->GetColumnWidth( _nColId ), 0 ), MapMode( MapUnit::MapMM ) );
|
|
nColSize = aSizeMM.Width() * 10;
|
|
}
|
|
|
|
Size aDefaultMM = _pBox->PixelToLogic( Size( nDefaultWidth, 0 ), MapMode( MapUnit::MapMM ) );
|
|
|
|
DlgSize aColumnSizeDlg(_pBox->GetFrameWeld(), nColSize, false, aDefaultMM.Width() * 10);
|
|
if (aColumnSizeDlg.run() != RET_OK)
|
|
return;
|
|
|
|
sal_Int32 nValue = aColumnSizeDlg.GetValue();
|
|
if ( -1 == nValue )
|
|
{ // default width
|
|
nValue = _pBox->GetDefaultColumnWidth( _pBox->GetColumnTitle( _nColId ) );
|
|
}
|
|
else
|
|
{
|
|
Size aSizeMM( nValue / 10, 0 );
|
|
nValue = _pBox->LogicToPixel( aSizeMM, MapMode( MapUnit::MapMM ) ).Width();
|
|
}
|
|
_pBox->SetColumnWidth( _nColId, nValue );
|
|
}
|
|
|
|
// check if SQL92 name checking is enabled
|
|
bool isSQL92CheckEnabled(const Reference<XConnection>& _xConnection)
|
|
{
|
|
return ::dbtools::getBooleanDataSourceSetting( _xConnection, PROPERTY_ENABLESQL92CHECK );
|
|
}
|
|
|
|
bool isAppendTableAliasEnabled(const Reference<XConnection>& _xConnection)
|
|
{
|
|
return ::dbtools::getBooleanDataSourceSetting( _xConnection, INFO_APPEND_TABLE_ALIAS );
|
|
}
|
|
|
|
bool generateAsBeforeTableAlias(const Reference<XConnection>& _xConnection)
|
|
{
|
|
return ::dbtools::getBooleanDataSourceSetting( _xConnection, INFO_AS_BEFORE_CORRELATION_NAME );
|
|
}
|
|
|
|
void fillAutoIncrementValue(const Reference<XPropertySet>& _xDatasource,
|
|
bool& _rAutoIncrementValueEnabled,
|
|
OUString& _rsAutoIncrementValue)
|
|
{
|
|
if ( !_xDatasource.is() )
|
|
return;
|
|
|
|
OSL_ENSURE(_xDatasource->getPropertySetInfo()->hasPropertyByName(PROPERTY_INFO),"NO datasource supplied!");
|
|
Sequence<PropertyValue> aInfo;
|
|
_xDatasource->getPropertyValue(PROPERTY_INFO) >>= aInfo;
|
|
|
|
// search the right propertyvalue
|
|
const PropertyValue* pValue =std::find_if(std::cbegin(aInfo), std::cend(aInfo),
|
|
[](const PropertyValue& lhs)
|
|
{return lhs.Name == PROPERTY_AUTOINCREMENTCREATION;} );
|
|
|
|
if ( pValue != std::cend(aInfo) )
|
|
pValue->Value >>= _rsAutoIncrementValue;
|
|
pValue =std::find_if(std::cbegin(aInfo), std::cend(aInfo),
|
|
[](const PropertyValue& lhs)
|
|
{return lhs.Name == "IsAutoRetrievingEnabled";} );
|
|
|
|
if ( pValue != std::cend(aInfo) )
|
|
pValue->Value >>= _rAutoIncrementValueEnabled;
|
|
}
|
|
|
|
void fillAutoIncrementValue(const Reference<XConnection>& _xConnection,
|
|
bool& _rAutoIncrementValueEnabled,
|
|
OUString& _rsAutoIncrementValue)
|
|
{
|
|
Reference< XChild> xChild(_xConnection,UNO_QUERY);
|
|
if(xChild.is())
|
|
{
|
|
Reference< XPropertySet> xProp(xChild->getParent(),UNO_QUERY);
|
|
fillAutoIncrementValue(xProp,_rAutoIncrementValueEnabled,_rsAutoIncrementValue);
|
|
}
|
|
}
|
|
|
|
OUString getStrippedDatabaseName(const Reference<XPropertySet>& _xDataSource,OUString& _rsDatabaseName)
|
|
{
|
|
if ( _rsDatabaseName.isEmpty() && _xDataSource.is() )
|
|
{
|
|
try
|
|
{
|
|
_xDataSource->getPropertyValue(PROPERTY_NAME) >>= _rsDatabaseName;
|
|
}
|
|
catch(const Exception& )
|
|
{
|
|
DBG_UNHANDLED_EXCEPTION("dbaccess");
|
|
}
|
|
}
|
|
OUString sName = _rsDatabaseName;
|
|
INetURLObject aURL(sName);
|
|
if ( aURL.GetProtocol() != INetProtocol::NotValid )
|
|
sName = aURL.getBase(INetURLObject::LAST_SEGMENT,true,INetURLObject::DecodeMechanism::Unambiguous);
|
|
return sName;
|
|
}
|
|
|
|
void setEvalDateFormatForFormatter(Reference< css::util::XNumberFormatter > const & _rxFormatter)
|
|
{
|
|
OSL_ENSURE( _rxFormatter.is(),"setEvalDateFormatForFormatter: Formatter is NULL!");
|
|
if ( !_rxFormatter.is() )
|
|
return;
|
|
|
|
Reference< css::util::XNumberFormatsSupplier > xSupplier = _rxFormatter->getNumberFormatsSupplier();
|
|
|
|
auto pSupplierImpl = comphelper::getFromUnoTunnel<SvNumberFormatsSupplierObj>(xSupplier);
|
|
OSL_ENSURE(pSupplierImpl,"No Supplier!");
|
|
|
|
if ( pSupplierImpl )
|
|
{
|
|
SvNumberFormatter* pFormatter = pSupplierImpl->GetNumberFormatter();
|
|
pFormatter->SetEvalDateFormat(NF_EVALDATEFORMAT_FORMAT);
|
|
}
|
|
}
|
|
|
|
static bool TypeIsGreater(const TOTypeInfoSP& lhs, const TOTypeInfoSP& rhs)
|
|
{
|
|
assert(lhs);
|
|
if (!rhs)
|
|
return true;
|
|
if (lhs->nNumPrecRadix == rhs->nNumPrecRadix)
|
|
return lhs->nPrecision > rhs->nPrecision;
|
|
if (lhs->nPrecision == rhs->nPrecision)
|
|
return lhs->nNumPrecRadix > rhs->nNumPrecRadix;
|
|
if ((lhs->nNumPrecRadix > rhs->nNumPrecRadix) == (lhs->nPrecision > rhs->nPrecision))
|
|
return lhs->nPrecision > rhs->nPrecision;
|
|
return std::pow(lhs->nNumPrecRadix, lhs->nPrecision)
|
|
> std::pow(rhs->nNumPrecRadix, rhs->nPrecision);
|
|
}
|
|
|
|
TOTypeInfoSP queryPrimaryKeyType(const OTypeInfoMap& _rTypeInfo)
|
|
{
|
|
TOTypeInfoSP pTypeInfo, pFallback;
|
|
// first we search for a largest type which supports autoIncrement
|
|
for (auto const& elem : _rTypeInfo)
|
|
{
|
|
if (elem.second->bAutoIncrement && TypeIsGreater(elem.second, pTypeInfo))
|
|
pTypeInfo = elem.second;
|
|
if (pTypeInfo)
|
|
continue;
|
|
if (elem.second->nType == DataType::INTEGER)
|
|
pFallback = elem.second; // default alternative
|
|
else if (!pFallback && elem.second->nType == DataType::DOUBLE)
|
|
pFallback = elem.second; // alternative
|
|
else if (!pFallback && elem.second->nType == DataType::REAL)
|
|
pFallback = elem.second; // alternative
|
|
}
|
|
if ( !pTypeInfo ) // just a fallback
|
|
pTypeInfo = pFallback ? std::move(pFallback) : queryTypeInfoByType(DataType::VARCHAR, _rTypeInfo);
|
|
|
|
OSL_ENSURE(pTypeInfo,"checkColumns: can't find a type which is usable as a key!");
|
|
return pTypeInfo;
|
|
}
|
|
|
|
TOTypeInfoSP queryTypeInfoByType(sal_Int32 _nDataType,const OTypeInfoMap& _rTypeInfo)
|
|
{
|
|
OTypeInfoMap::const_iterator aIter = _rTypeInfo.find(_nDataType);
|
|
if(aIter != _rTypeInfo.end())
|
|
return aIter->second;
|
|
// fall back if the type is unknown
|
|
TOTypeInfoSP pTypeInfo;
|
|
switch(_nDataType)
|
|
{
|
|
case DataType::TINYINT:
|
|
if( (pTypeInfo = queryTypeInfoByType(DataType::SMALLINT,_rTypeInfo) ) )
|
|
break;
|
|
[[fallthrough]];
|
|
case DataType::SMALLINT:
|
|
if( (pTypeInfo = queryTypeInfoByType(DataType::INTEGER,_rTypeInfo) ) )
|
|
break;
|
|
[[fallthrough]];
|
|
case DataType::INTEGER:
|
|
if( (pTypeInfo = queryTypeInfoByType(DataType::FLOAT,_rTypeInfo) ) )
|
|
break;
|
|
[[fallthrough]];
|
|
case DataType::FLOAT:
|
|
if( (pTypeInfo = queryTypeInfoByType(DataType::REAL,_rTypeInfo) ) )
|
|
break;
|
|
[[fallthrough]];
|
|
case DataType::DATE:
|
|
case DataType::TIME:
|
|
if( DataType::DATE == _nDataType || DataType::TIME == _nDataType )
|
|
{
|
|
if( (pTypeInfo = queryTypeInfoByType(DataType::TIMESTAMP,_rTypeInfo) ) )
|
|
break;
|
|
}
|
|
[[fallthrough]];
|
|
case DataType::TIMESTAMP:
|
|
case DataType::REAL:
|
|
case DataType::BIGINT:
|
|
if ( (pTypeInfo = queryTypeInfoByType(DataType::DOUBLE,_rTypeInfo) ) )
|
|
break;
|
|
[[fallthrough]];
|
|
case DataType::DOUBLE:
|
|
if ( (pTypeInfo = queryTypeInfoByType(DataType::NUMERIC,_rTypeInfo) ) )
|
|
break;
|
|
[[fallthrough]];
|
|
case DataType::NUMERIC:
|
|
pTypeInfo = queryTypeInfoByType(DataType::DECIMAL,_rTypeInfo);
|
|
break;
|
|
case DataType::DECIMAL:
|
|
if ( (pTypeInfo = queryTypeInfoByType(DataType::NUMERIC,_rTypeInfo) ) )
|
|
break;
|
|
if ( (pTypeInfo = queryTypeInfoByType(DataType::DOUBLE,_rTypeInfo) ) )
|
|
break;
|
|
break;
|
|
case DataType::VARCHAR:
|
|
if ( (pTypeInfo = queryTypeInfoByType(DataType::LONGVARCHAR,_rTypeInfo) ) )
|
|
break;
|
|
break;
|
|
case DataType::LONGVARCHAR:
|
|
if ( (pTypeInfo = queryTypeInfoByType(DataType::CLOB,_rTypeInfo) ) )
|
|
break;
|
|
break;
|
|
default:
|
|
;
|
|
}
|
|
if ( !pTypeInfo )
|
|
{
|
|
bool bForce = true;
|
|
pTypeInfo = ::dbaui::getTypeInfoFromType(_rTypeInfo,DataType::VARCHAR,OUString(),u"x"_ustr,50,0,false,bForce);
|
|
}
|
|
OSL_ENSURE(pTypeInfo,"Wrong DataType supplied!");
|
|
return pTypeInfo;
|
|
}
|
|
|
|
sal_Int32 askForUserAction(weld::Window* pParent, TranslateId pTitle, TranslateId pText, bool _bAll, std::u16string_view _sName)
|
|
{
|
|
SolarMutexGuard aGuard;
|
|
OUString aMsg = DBA_RES(pText);
|
|
aMsg = aMsg.replaceFirst("%1", _sName);
|
|
OSQLMessageBox aAsk(pParent, DBA_RES(pTitle), aMsg, MessBoxStyle::YesNo | MessBoxStyle::DefaultYes, MessageType::Query);
|
|
if ( _bAll )
|
|
{
|
|
aAsk.add_button(DBA_RES(STR_BUTTON_TEXT_ALL), RET_ALL, HID_CONFIRM_DROP_BUTTON_ALL);
|
|
}
|
|
return aAsk.run();
|
|
}
|
|
|
|
namespace
|
|
{
|
|
OUString lcl_createSDBCLevelStatement( const OUString& _rStatement, const Reference< XConnection >& _rxConnection )
|
|
{
|
|
OUString sSDBCLevelStatement( _rStatement );
|
|
try
|
|
{
|
|
Reference< XMultiServiceFactory > xAnalyzerFactory( _rxConnection, UNO_QUERY_THROW );
|
|
Reference< XSingleSelectQueryAnalyzer > xAnalyzer( xAnalyzerFactory->createInstance( SERVICE_NAME_SINGLESELECTQUERYCOMPOSER ), UNO_QUERY_THROW );
|
|
xAnalyzer->setQuery( _rStatement );
|
|
sSDBCLevelStatement = xAnalyzer->getQueryWithSubstitution();
|
|
}
|
|
catch( const Exception& )
|
|
{
|
|
DBG_UNHANDLED_EXCEPTION("dbaccess");
|
|
}
|
|
return sSDBCLevelStatement;
|
|
}
|
|
}
|
|
|
|
Reference< XPropertySet > createView( const OUString& _rName, const Reference< XConnection >& _rxConnection,
|
|
const OUString& _rCommand )
|
|
{
|
|
Reference<XViewsSupplier> xSup(_rxConnection,UNO_QUERY);
|
|
Reference< XNameAccess > xViews;
|
|
if(xSup.is())
|
|
xViews = xSup->getViews();
|
|
Reference<XDataDescriptorFactory> xFact(xViews,UNO_QUERY);
|
|
OSL_ENSURE(xFact.is(),"No XDataDescriptorFactory available!");
|
|
if(!xFact.is())
|
|
return nullptr;
|
|
|
|
Reference<XPropertySet> xView = xFact->createDataDescriptor();
|
|
if ( !xView.is() )
|
|
return nullptr;
|
|
|
|
OUString sCatalog,sSchema,sTable;
|
|
::dbtools::qualifiedNameComponents(_rxConnection->getMetaData(),
|
|
_rName,
|
|
sCatalog,
|
|
sSchema,
|
|
sTable,
|
|
::dbtools::EComposeRule::InDataManipulation);
|
|
|
|
xView->setPropertyValue(PROPERTY_CATALOGNAME,Any(sCatalog));
|
|
xView->setPropertyValue(PROPERTY_SCHEMANAME,Any(sSchema));
|
|
xView->setPropertyValue(PROPERTY_NAME,Any(sTable));
|
|
|
|
xView->setPropertyValue( PROPERTY_COMMAND, Any( _rCommand ) );
|
|
|
|
Reference<XAppend> xAppend(xViews,UNO_QUERY);
|
|
if(xAppend.is())
|
|
xAppend->appendByDescriptor(xView);
|
|
|
|
xView = nullptr;
|
|
// we need to reget the view because after appending it, it is no longer valid
|
|
// but this time it isn't a view object it is a table object with type "VIEW"
|
|
Reference<XTablesSupplier> xTabSup(_rxConnection,UNO_QUERY);
|
|
Reference< XNameAccess > xTables;
|
|
if ( xTabSup.is() )
|
|
{
|
|
xTables = xTabSup->getTables();
|
|
if ( xTables.is() && xTables->hasByName( _rName ) )
|
|
xTables->getByName( _rName ) >>= xView;
|
|
}
|
|
|
|
return xView;
|
|
}
|
|
|
|
Reference<XPropertySet> createView( const OUString& _rName, const Reference< XConnection >& _rxConnection
|
|
,const Reference<XPropertySet>& _rxSourceObject)
|
|
{
|
|
OUString sCommand;
|
|
Reference< XPropertySetInfo > xPSI( _rxSourceObject->getPropertySetInfo(), UNO_SET_THROW );
|
|
if ( xPSI->hasPropertyByName( PROPERTY_COMMAND ) )
|
|
{
|
|
_rxSourceObject->getPropertyValue( PROPERTY_COMMAND ) >>= sCommand;
|
|
|
|
bool bEscapeProcessing( false );
|
|
OSL_VERIFY( _rxSourceObject->getPropertyValue( PROPERTY_ESCAPE_PROCESSING ) >>= bEscapeProcessing );
|
|
if ( bEscapeProcessing )
|
|
sCommand = lcl_createSDBCLevelStatement( sCommand, _rxConnection );
|
|
}
|
|
else
|
|
{
|
|
sCommand = "SELECT * FROM " + composeTableNameForSelect( _rxConnection, _rxSourceObject );
|
|
}
|
|
return createView( _rName, _rxConnection, sCommand );
|
|
}
|
|
|
|
bool insertHierarchyElement(weld::Window* pParent, const Reference< XComponentContext >& _rxContext,
|
|
const Reference<XHierarchicalNameContainer>& _xNames,
|
|
const OUString& _sParentFolder,
|
|
bool _bForm,
|
|
bool _bCollection,
|
|
const Reference<XContent>& _xContent,
|
|
bool _bMove)
|
|
{
|
|
OSL_ENSURE( _xNames.is(), "insertHierarchyElement: illegal name container!" );
|
|
if ( !_xNames.is() )
|
|
return false;
|
|
|
|
Reference<XNameAccess> xNameAccess( _xNames, UNO_QUERY );
|
|
if ( _xNames->hasByHierarchicalName(_sParentFolder) )
|
|
{
|
|
Reference<XChild> xChild(_xNames->getByHierarchicalName(_sParentFolder),UNO_QUERY);
|
|
xNameAccess.set(xChild,UNO_QUERY);
|
|
if ( !xNameAccess.is() && xChild.is() )
|
|
xNameAccess.set(xChild->getParent(),UNO_QUERY);
|
|
}
|
|
|
|
OSL_ENSURE( xNameAccess.is(), "insertHierarchyElement: could not find the proper name container!" );
|
|
if ( !xNameAccess.is() )
|
|
return false;
|
|
|
|
OUString sNewName;
|
|
Reference<XPropertySet> xProp(_xContent,UNO_QUERY);
|
|
if ( xProp.is() )
|
|
xProp->getPropertyValue(PROPERTY_NAME) >>= sNewName;
|
|
|
|
if ( !_bMove || sNewName.isEmpty() )
|
|
{
|
|
if ( sNewName.isEmpty() || xNameAccess->hasByName(sNewName) )
|
|
{
|
|
OUString sLabel, sTargetName;
|
|
if ( !sNewName.isEmpty() )
|
|
sTargetName = sNewName;
|
|
else
|
|
sTargetName = DBA_RES( _bCollection ? STR_NEW_FOLDER : ((_bForm) ? RID_STR_FORM : RID_STR_REPORT));
|
|
sLabel = DBA_RES( _bCollection ? STR_FOLDER_LABEL : ((_bForm) ? STR_FRM_LABEL : STR_RPT_LABEL));
|
|
sTargetName = ::dbtools::createUniqueName(xNameAccess,sTargetName);
|
|
|
|
// here we have everything needed to create a new query object ...
|
|
HierarchicalNameCheck aNameChecker( _xNames, _sParentFolder );
|
|
// ... ehm, except a new name
|
|
OSaveAsDlg aAskForName(pParent,
|
|
_rxContext,
|
|
sTargetName,
|
|
sLabel,
|
|
aNameChecker,
|
|
SADFlags::AdditionalDescription | SADFlags::TitlePasteAs);
|
|
if ( RET_OK != aAskForName.run() )
|
|
// cancelled by the user
|
|
return false;
|
|
|
|
sNewName = aAskForName.getName();
|
|
}
|
|
}
|
|
else if ( xNameAccess->hasByName(sNewName) )
|
|
{
|
|
OUString sError(DBA_RES(STR_NAME_ALREADY_EXISTS));
|
|
sError = sError.replaceFirst("#",sNewName);
|
|
throw SQLException(sError,nullptr,u"S1000"_ustr,0,Any());
|
|
}
|
|
|
|
try
|
|
{
|
|
Reference<XMultiServiceFactory> xORB( xNameAccess, UNO_QUERY_THROW );
|
|
uno::Sequence<uno::Any> aArguments(comphelper::InitAnyPropertySequence(
|
|
{
|
|
{"Name", uno::Any(sNewName)}, // set as folder
|
|
{"Parent", uno::Any(xNameAccess)},
|
|
{PROPERTY_EMBEDDEDOBJECT, uno::Any(_xContent)},
|
|
}));
|
|
OUString sServiceName(_bCollection ? (_bForm ? SERVICE_NAME_FORM_COLLECTION : SERVICE_NAME_REPORT_COLLECTION) : SERVICE_SDB_DOCUMENTDEFINITION);
|
|
|
|
Reference<XContent > xNew( xORB->createInstanceWithArguments( sServiceName, aArguments ), UNO_QUERY_THROW );
|
|
Reference< XNameContainer > xNameContainer( xNameAccess, UNO_QUERY_THROW );
|
|
xNameContainer->insertByName( sNewName, Any( xNew ) );
|
|
}
|
|
catch( const IllegalArgumentException& e )
|
|
{
|
|
::dbtools::throwGenericSQLException( e.Message, e.Context );
|
|
}
|
|
catch( const Exception& )
|
|
{
|
|
DBG_UNHANDLED_EXCEPTION("dbaccess");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
Reference< XNumberFormatter > getNumberFormatter(const Reference< XConnection >& _rxConnection, const Reference< css::uno::XComponentContext >& _rxContext )
|
|
{
|
|
// create a formatter working with the connections format supplier
|
|
Reference< XNumberFormatter > xFormatter;
|
|
|
|
try
|
|
{
|
|
Reference< css::util::XNumberFormatsSupplier > xSupplier(::dbtools::getNumberFormats(_rxConnection, true, _rxContext));
|
|
|
|
if ( xSupplier.is() )
|
|
{
|
|
// create a new formatter
|
|
xFormatter.set(util::NumberFormatter::create( _rxContext ), UNO_QUERY_THROW);
|
|
xFormatter->attachNumberFormatsSupplier(xSupplier);
|
|
}
|
|
}
|
|
catch(const Exception&)
|
|
{
|
|
DBG_UNHANDLED_EXCEPTION("dbaccess");
|
|
}
|
|
return xFormatter;
|
|
}
|
|
|
|
} // dbaui
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|