/* -*- 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 <callbacks.hxx>
#include <core_resource.hxx>
#include <stringconstants.hxx>
#include <dbu_pageids.hxx>
#include <dlgsave.hxx>
#include <dbtreelistbox.hxx>
#include <defaultobjectnamecheck.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/XKeysSupplier.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/XIndexAccess.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 <toolkit/helper/vclunohelper.hxx>
#include <toolkit/awt/vclxwindow.hxx>
#include <vcl/stdtext.hxx>
#include <vcl/settings.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/XContainer.hpp>
#include <com/sun/star/container/XHierarchicalNameContainer.hpp>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <com/sun/star/awt/TextAlign.hpp>
#include <com/sun/star/awt/FontDescriptor.hpp>
#include <com/sun/star/awt/FontWeight.hpp>
#include <com/sun/star/awt/FontRelief.hpp>
#include <com/sun/star/awt/FontWidth.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/itempool.hxx>
#include <helpids.h>
#include <svl/itemset.hxx>
#include <sbagrid.hrc>
#include <svl/rngitem.hxx>
#include <svl/intitem.hxx>
#include <svx/algitem.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 <com/sun/star/util/NumberFormat.hpp>
#include <com/sun/star/util/URL.hpp>
#include <vcl/toolbox.hxx>
#include <dlgsize.hxx>
#include <svtools/editbrowsebox.hxx>
#include <unotools/configmgr.hxx>
#include <svtools/helpopt.hxx>
#include <ucbhelper/content.hxx>
#include <tools/urlobj.hxx>
#include <tools/diagnose_ex.h>
#include <svl/numuno.hxx>
#include <unotools/pathoptions.hxx>
#include <svl/filenotation.hxx>
#include <svtools/fileview.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 ::com::sun::star::ui::dialogs;
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&)
    {
    }
    SQLExceptionInfo aInfo;
 
    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), UNO_QUERY);
                _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&) { SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::OnExpandEntry: could not connect - unknown exception!"); }
 
    return aInfo;
}
 
Reference< XDataSource > getDataSourceByName( const OUString& _rDataSourceName,
    vcl::Window* _pErrorMessageParent, const Reference< XComponentContext >& _rxContext, ::dbtools::SQLExceptionInfo* _pErrorInfo )
{
    Reference< XDatabaseContext > xDatabaseContext = DatabaseContext::create(_rxContext);
 
    Reference< XDataSource > xDatasource;
    Any aError;
    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 );
            if ( !aSQLError.isValid() )
                aError = e.TargetException;
        }
    }
    catch( const Exception& )
    {
        DBG_UNHANDLED_EXCEPTION("dbaccess");
    }
 
    if ( xDatasource.is() )
        return xDatasource;
 
    if ( aSQLError.isValid() )
    {
        if ( _pErrorInfo )
        {
            *_pErrorInfo = aSQLError;
        }
        else
        {
            showError( aSQLError, _pErrorMessageParent, _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;
}
 
void showError(const SQLExceptionInfo& _rInfo, vcl::Window* _pParent,const Reference< XComponentContext >& _rxContext)
{
    OSL_ENSURE(_pParent,"showError: Parent window must be NOT NULL!");
    ::dbtools::showError(_rInfo,VCLUnoHelper::GetInterface(_pParent), _rxContext);
}
 
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,
                    const OUString& _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())
    {
        Reference<XResultSetMetaData> xResultSetMetaData = Reference<XResultSetMetaDataSupplier>(xRs,UNO_QUERY)->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(new 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;
            ++nPos;
            aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
            pInfo->nType            = aValue;
            ++nPos;
            aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
            pInfo->nPrecision       = aValue;
            ++nPos;
            aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
            pInfo->aLiteralPrefix   = aValue;
            ++nPos;
            aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
            pInfo->aLiteralSuffix   = aValue;
            ++nPos;
            aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
            pInfo->aCreateParams    = aValue;
            ++nPos;
            aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
            pInfo->bNullable        = static_cast<sal_Int32>(aValue) == ColumnValue::NULLABLE;
            ++nPos;
            aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
            // bCaseSensitive
            ++nPos;
            aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
            pInfo->nSearchType      = aValue;
            ++nPos;
            aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
            // bUnsigned
            ++nPos;
            aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
            pInfo->bCurrency        = static_cast<bool>(aValue);
            ++nPos;
            aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
            pInfo->bAutoIncrement   = static_cast<bool>(aValue);
            ++nPos;
            aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
            pInfo->aLocalTypeName   = aValue;
            ++nPos;
            aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
            pInfo->nMinimumScale    = aValue;
            ++nPos;
            aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
            pInfo->nMaximumScale    = aValue;
            assert(nPos == 15);
            // 16 and 17 are unused
            nPos = 18;
            aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
            pInfo->nNumPrecRadix    = aValue;
 
            // 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;
 
            OUString aName;
            switch(pInfo->nType)
            {
                case DataType::CHAR:
                    aName = _rsTypeNames.getToken(TYPE_CHAR, ';');
                    break;
                case DataType::VARCHAR:
                    aName = _rsTypeNames.getToken(TYPE_TEXT, ';');
                    break;
                case DataType::DECIMAL:
                    aName = _rsTypeNames.getToken(TYPE_DECIMAL, ';');
                    break;
                case DataType::NUMERIC:
                    aName = _rsTypeNames.getToken(TYPE_NUMERIC, ';');
                    break;
                case DataType::BIGINT:
                    aName = _rsTypeNames.getToken(TYPE_BIGINT, ';');
                    break;
                case DataType::FLOAT:
                    aName = _rsTypeNames.getToken(TYPE_FLOAT, ';');
                    break;
                case DataType::DOUBLE:
                    aName = _rsTypeNames.getToken(TYPE_DOUBLE, ';');
                    break;
                case DataType::LONGVARCHAR:
                    aName = _rsTypeNames.getToken(TYPE_MEMO, ';');
                    break;
                case DataType::LONGVARBINARY:
                    aName = _rsTypeNames.getToken(TYPE_IMAGE, ';');
                    break;
                case DataType::DATE:
                    aName = _rsTypeNames.getToken(TYPE_DATE, ';');
                    break;
                case DataType::TIME:
                    aName = _rsTypeNames.getToken(TYPE_TIME, ';');
                    break;
                case DataType::TIMESTAMP:
                    aName = _rsTypeNames.getToken(TYPE_DATETIME, ';');
                    break;
                case DataType::BIT:
                    if ( !pInfo->aCreateParams.isEmpty() )
                    {
                        aName = _rsTypeNames.getToken(TYPE_BIT, ';');
                        break;
                    }
                    SAL_FALLTHROUGH;
                case DataType::BOOLEAN:
                    aName = _rsTypeNames.getToken(TYPE_BOOL, ';');
                    break;
                case DataType::TINYINT:
                    aName = _rsTypeNames.getToken(TYPE_TINYINT, ';');
                    break;
                case DataType::SMALLINT:
                    aName = _rsTypeNames.getToken(TYPE_SMALLINT, ';');
                    break;
                case DataType::INTEGER:
                    aName = _rsTypeNames.getToken(TYPE_INTEGER, ';');
                    break;
                case DataType::REAL:
                    aName = _rsTypeNames.getToken(TYPE_REAL, ';');
                    break;
                case DataType::BINARY:
                    aName = _rsTypeNames.getToken(TYPE_BINARY, ';');
                    break;
                case DataType::VARBINARY:
                    aName = _rsTypeNames.getToken(TYPE_VARBINARY, ';');
                    break;
                case DataType::SQLNULL:
                    aName = _rsTypeNames.getToken(TYPE_SQLNULL, ';');
                    break;
                case DataType::OBJECT:
                    aName = _rsTypeNames.getToken(TYPE_OBJECT, ';');
                    break;
                case DataType::DISTINCT:
                    aName = _rsTypeNames.getToken(TYPE_DISTINCT, ';');
                    break;
                case DataType::STRUCT:
                    aName = _rsTypeNames.getToken(TYPE_STRUCT, ';');
                    break;
                case DataType::ARRAY:
                    aName = _rsTypeNames.getToken(TYPE_ARRAY, ';');
                    break;
                case DataType::BLOB:
                    aName = _rsTypeNames.getToken(TYPE_BLOB, ';');
                    break;
                case DataType::CLOB:
                    aName = _rsTypeNames.getToken(TYPE_CLOB, ';');
                    break;
                case DataType::REF:
                    aName = _rsTypeNames.getToken(TYPE_REF, ';');
                    break;
                case DataType::OTHER:
                    aName = _rsTypeNames.getToken(TYPE_OTHER, ';');
                    break;
            }
            if ( !aName.isEmpty() )
            {
                pInfo->aUIName = aName;
                pInfo->aUIName += " [ ";
            }
            pInfo->aUIName += pInfo->aTypeName;
            if ( !aName.isEmpty() )
                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,makeAny(_pFieldDesc->GetName()));
    _rxColumn->setPropertyValue(PROPERTY_TYPENAME,makeAny(_pFieldDesc->getTypeInfo()->aTypeName));
    _rxColumn->setPropertyValue(PROPERTY_TYPE,makeAny(_pFieldDesc->GetType()));
    _rxColumn->setPropertyValue(PROPERTY_PRECISION,makeAny(_pFieldDesc->GetPrecision()));
    _rxColumn->setPropertyValue(PROPERTY_SCALE,makeAny(_pFieldDesc->GetScale()));
    _rxColumn->setPropertyValue(PROPERTY_ISNULLABLE, makeAny(_pFieldDesc->GetIsNullable()));
    _rxColumn->setPropertyValue(PROPERTY_ISAUTOINCREMENT, css::uno::makeAny(_pFieldDesc->IsAutoIncrement()));
    _rxColumn->setPropertyValue(PROPERTY_DESCRIPTION,makeAny(_pFieldDesc->GetDescription()));
    if ( _rxColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_ISCURRENCY) && _pFieldDesc->IsCurrency() )
        _rxColumn->setPropertyValue(PROPERTY_ISCURRENCY, css::uno::makeAny(_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,makeAny(_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 mapTextAllign(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,
                            vcl::Window* _pParent)
{
    if (xAffectedCol.is() && xField.is())
    {
        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, makeAny(static_cast<sal_Int16>(dbaui::mapTextAllign(eJustify))));
                if (bHasFormat)
                    xAffectedCol->setPropertyValue(PROPERTY_FORMATKEY, makeAny(nFormatKey));
 
            }
        }
        catch( const Exception& )
        {
            DBG_UNHANDLED_EXCEPTION("dbaccess");
        }
    }
}
 
bool callColumnFormatDialog(vcl::Window* _pParent,
                                SvNumberFormatter* _pFormatter,
                                sal_Int32 _nDataType,
                                sal_Int32& _nFormatKey,
                                SvxCellHorJustify& _eJustify,
                                bool  _bHasFormat)
{
    bool bRet = false;
 
    // UNO->ItemSet
    static SfxItemInfo aItemInfos[] =
    {
        { 0, false },
        { SID_ATTR_NUMBERFORMAT_VALUE,      true },
        { SID_ATTR_ALIGN_HOR_JUSTIFY,       true },
        { SID_ATTR_NUMBERFORMAT_ONE_AREA,   true },
        { SID_ATTR_NUMBERFORMAT_INFO,       true }
    };
    static const sal_uInt16 aAttrMap[] =
    {
        SBA_DEF_RANGEFORMAT, SBA_ATTR_ALIGN_HOR_JUSTIFY,
        SID_ATTR_NUMBERFORMAT_ONE_AREA, SID_ATTR_NUMBERFORMAT_ONE_AREA,
        SID_ATTR_NUMBERFORMAT_INFO, SID_ATTR_NUMBERFORMAT_INFO,
        0
    };
 
    std::vector<SfxPoolItem*> pDefaults
    {
        new SfxRangeItem(SBA_DEF_RANGEFORMAT, SBA_DEF_FMTVALUE, SBA_ATTR_ALIGN_HOR_JUSTIFY),
        new SfxUInt32Item(SBA_DEF_FMTVALUE),
        new SvxHorJustifyItem(SvxCellHorJustify::Standard, SBA_ATTR_ALIGN_HOR_JUSTIFY),
        new SfxBoolItem(SID_ATTR_NUMBERFORMAT_ONE_AREA, false),
        new SvxNumberInfoItem(SID_ATTR_NUMBERFORMAT_INFO)
    };
 
    SfxItemPool* pPool = new SfxItemPool("GridBrowserProperties", SBA_DEF_RANGEFORMAT, SBA_ATTR_ALIGN_HOR_JUSTIFY, aItemInfos, &pDefaults);
    pPool->SetDefaultMetric( MapUnit::MapTwip );    // ripped, don't understand why
    pPool->FreezeIdRanges();                        // the same
 
    std::unique_ptr<SfxItemSet> pFormatDescriptor(new 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,_pParent->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
        ScopedVclPtrInstance< SbaSbAttrDlg > aDlg(_pParent, pFormatDescriptor.get(), _pFormatter, _bHasFormat);
        if (RET_OK == aDlg->Execute())
        {
            // 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();
    SfxItemPool::Free(pPool);
    for (SfxPoolItem* pDefault : pDefaults)
        delete pDefault;
 
    return bRet;
}
 
std::shared_ptr<const SfxFilter> getStandardDatabaseFilter()
{
    std::shared_ptr<const SfxFilter> pFilter = SfxFilter::GetFilterByName("StarOffice XML (Base)");
    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;
                    if((nLen = rItem.lastIndexOf('.')) != -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,makeAny(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 adjustToolBoxSize(ToolBox* _pToolBox)
{
    // adjust the toolbox size, otherwise large bitmaps don't fit into
    Size aOldSize = _pToolBox->GetSizePixel();
    Size aSize = _pToolBox->CalcWindowSizePixel();
    if ( !aSize.Width() )
        aSize.setWidth( aOldSize.Width() );
    else if ( !aSize.Height() )
        aSize.setHeight( aOldSize.Height() );
 
    Size aTbSize = _pToolBox->GetSizePixel();
    if ( (aSize.Width() && aSize.Width() != aTbSize.Width()) ||
            (aSize.Height() && aSize.Height() != aTbSize.Height()) )
    {
        _pToolBox->SetPosSizePixel( _pToolBox->GetPosPixel(), aSize );
        _pToolBox->Invalidate();
    }
}
 
void adjustBrowseBoxColumnWidth( ::svt::EditBrowseBox* _pBox, sal_uInt16 _nColId )
{
    sal_Int32 nColSize = -1;
    sal_uInt32 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 ) );
 
    ScopedVclPtrInstance< DlgSize > aColumnSizeDlg( _pBox, nColSize, false, aDefaultMM.Width() * 10 );
    if ( aColumnSizeDlg->Execute() )
    {
        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() )
    {
        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(aInfo.begin(), aInfo.end(),
                                            [](const PropertyValue& lhs)
                                            {return lhs.Name == PROPERTY_AUTOINCREMENTCREATION;} );
 
        if ( pValue != aInfo.end() )
            pValue->Value >>= _rsAutoIncrementValue;
        pValue =std::find_if(aInfo.begin(), aInfo.end(),
                             [](const PropertyValue& lhs)
                             {return lhs.Name == "IsAutoRetrievingEnabled";} );
 
        if ( pValue != aInfo.end() )
            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() )
    {
        Reference< css::util::XNumberFormatsSupplier >  xSupplier = _rxFormatter->getNumberFormatsSupplier();
 
        Reference< XUnoTunnel > xTunnel(xSupplier,UNO_QUERY);
        SvNumberFormatsSupplierObj* pSupplierImpl = reinterpret_cast<SvNumberFormatsSupplierObj*>(xTunnel->getSomething(SvNumberFormatsSupplierObj::getUnoTunnelId()));
        OSL_ENSURE(pSupplierImpl,"No Supplier!");
 
        if ( pSupplierImpl )
        {
            SvNumberFormatter* pFormatter = pSupplierImpl->GetNumberFormatter();
            pFormatter->SetEvalDateFormat(NF_EVALDATEFORMAT_FORMAT);
        }
    }
}
 
TOTypeInfoSP queryPrimaryKeyType(const OTypeInfoMap& _rTypeInfo)
{
    TOTypeInfoSP pTypeInfo;
    // first we search for a type which supports autoIncrement
    for (auto const& elem : _rTypeInfo)
    {
        // OJ: we don't want to set an autoincrement column to be key
        // because we don't have the possibility to know how to create
        // such auto increment column later on
        // so until we know how to do it, we create a column without autoincrement
        // therefore we have searched
        if ( elem.second->nType == DataType::INTEGER )
        {
            pTypeInfo = elem.second; // alternative
            break;
        }
        else if ( !pTypeInfo.get() && elem.second->nType == DataType::DOUBLE )
            pTypeInfo = elem.second; // alternative
        else if ( !pTypeInfo.get() && elem.second->nType == DataType::REAL )
            pTypeInfo = elem.second; // alternative
    }
    if ( !pTypeInfo.get() ) // just a fallback
        pTypeInfo = queryTypeInfoByType(DataType::VARCHAR,_rTypeInfo);
 
    OSL_ENSURE(pTypeInfo.get(),"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;
            SAL_FALLTHROUGH;
        case DataType::SMALLINT:
            if( (pTypeInfo = queryTypeInfoByType(DataType::INTEGER,_rTypeInfo) ) )
                break;
            SAL_FALLTHROUGH;
        case DataType::INTEGER:
            if( (pTypeInfo = queryTypeInfoByType(DataType::FLOAT,_rTypeInfo) ) )
                break;
            SAL_FALLTHROUGH;
        case DataType::FLOAT:
            if( (pTypeInfo = queryTypeInfoByType(DataType::REAL,_rTypeInfo) ) )
                break;
            SAL_FALLTHROUGH;
        case DataType::DATE:
        case DataType::TIME:
            if( DataType::DATE == _nDataType || DataType::TIME == _nDataType )
            {
                if( (pTypeInfo = queryTypeInfoByType(DataType::TIMESTAMP,_rTypeInfo) ) )
                    break;
            }
            SAL_FALLTHROUGH;
        case DataType::TIMESTAMP:
        case DataType::REAL:
        case DataType::BIGINT:
            if (  (pTypeInfo = queryTypeInfoByType(DataType::DOUBLE,_rTypeInfo) ) )
                break;
            SAL_FALLTHROUGH;
        case DataType::DOUBLE:
            if (  (pTypeInfo = queryTypeInfoByType(DataType::NUMERIC,_rTypeInfo) ) )
                break;
            SAL_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(),"x",50,0,false,bForce);
    }
    OSL_ENSURE(pTypeInfo,"Wrong DataType supplied!");
    return pTypeInfo;
}
 
sal_Int32 askForUserAction(weld::Window* pParent, const char* pTitle, const char* pText, bool _bAll, const OUString& _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,makeAny(sCatalog));
    xView->setPropertyValue(PROPERTY_SCHEMANAME,makeAny(sSchema));
    xView->setPropertyValue(PROPERTY_NAME,makeAny(sTable));
 
    xView->setPropertyValue( PROPERTY_COMMAND, makeAny( _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 insertHierachyElement( vcl::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(), "insertHierachyElement: 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(), "insertHierachyElement: 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() )
    {
        OUString sTargetName,sLabel;
        if ( sNewName.isEmpty() || xNameAccess->hasByName(sNewName) )
        {
            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.get(), _sParentFolder );
            // ... ehm, except a new name
            ScopedVclPtrInstance<OSaveAsDlg> aAskForName(
                                   _pParent,
                                    _rxContext,
                                    sTargetName,
                                    sLabel,
                                    aNameChecker,
                                    SADFlags::AdditionalDescription | SADFlags::TitlePasteAs );
            if ( RET_OK != aAskForName->Execute() )
                // 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,"S1000",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 ? OUString(SERVICE_NAME_FORM_COLLECTION) : OUString(SERVICE_NAME_REPORT_COLLECTION)) : OUString(SERVICE_SDB_DOCUMENTDEFINITION));
 
        Reference<XContent > xNew( xORB->createInstanceWithArguments( sServiceName, aArguments ), UNO_QUERY_THROW );
        Reference< XNameContainer > xNameContainer( xNameAccess, UNO_QUERY_THROW );
        xNameContainer->insertByName( sNewName, makeAny( 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: */

V728 An excessive check can be simplified. The '||' operator is surrounded by opposite expressions '!_bAutoIncrement' and '_bAutoIncrement'.

V728 An excessive check can be simplified. The '||' operator is surrounded by opposite expressions '!_bAutoIncrement' and '_bAutoIncrement'.

V728 An excessive check can be simplified. The '||' operator is surrounded by opposite expressions '!_bAutoIncrement' and '_bAutoIncrement'.

V547 Expression 'bEscapeProcessing' is always false.