/* -*- 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 <connectivity/dbtools.hxx>
#include <connectivity/dbconversion.hxx>
#include <connectivity/dbcharset.hxx>
#include <SQLStatementHelper.hxx>
#include <unotools/confignode.hxx>
#include <resource/sharedresources.hxx>
#include <strings.hrc>
#include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
#include <com/sun/star/sdbc/SQLException.hpp>
#include <com/sun/star/sdbc/XConnection.hpp>
#include <com/sun/star/sdbc/XDataSource.hpp>
#include <com/sun/star/sdbc/ColumnValue.hpp>
#include <com/sun/star/sdbc/DataType.hpp>
#include <com/sun/star/sdbc/DriverManager.hpp>
#include <com/sun/star/sdbc/XRow.hpp>
#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
#include <com/sun/star/sdbcx/XKeysSupplier.hpp>
#include <com/sun/star/sdbcx/XDataDefinitionSupplier.hpp>
#include <com/sun/star/sdbcx/Privilege.hpp>
#include <com/sun/star/container/XIndexAccess.hpp>
#include <com/sun/star/sdbc/KeyRule.hpp>
#include <com/sun/star/sdbcx/KeyType.hpp>
#include <TConnection.hxx>
#include <connectivity/sdbcx/VColumn.hxx>
#include <com/sun/star/frame/XModel.hpp>
#include <com/sun/star/container/XChild.hpp>
#include <comphelper/types.hxx>
#include <comphelper/diagnose_ex.hxx>
#include <unotools/sharedunocomponent.hxx>
#include <algorithm>
#include <string_view>
namespace dbtools
{
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::sdb;
using namespace ::com::sun::star::sdbc;
using namespace ::com::sun::star::sdbcx;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::container;
using namespace ::com::sun::star::frame;
using namespace connectivity;
using namespace comphelper;
OUString createStandardTypePart(const Reference< XPropertySet >& xColProp,const Reference< XConnection>& _xConnection,std::u16string_view _sCreatePattern)
{
Reference<XDatabaseMetaData> xMetaData = _xConnection->getMetaData();
::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap();
OUString sTypeName;
sal_Int32 nDataType = 0;
sal_Int32 nPrecision = 0;
sal_Int32 nScale = 0;
nDataType = nPrecision = nScale = 0;
xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_TYPENAME)) >>= sTypeName;
xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_TYPE)) >>= nDataType;
xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_PRECISION)) >>= nPrecision;
xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_SCALE)) >>= nScale;
OUStringBuffer aSql;
// check if the user enter a specific string to create autoincrement values
OUString sAutoIncrementValue;
Reference<XPropertySetInfo> xPropInfo = xColProp->getPropertySetInfo();
if ( xPropInfo.is() && xPropInfo->hasPropertyByName(rPropMap.getNameByIndex(PROPERTY_ID_AUTOINCREMENTCREATION)) )
xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_AUTOINCREMENTCREATION)) >>= sAutoIncrementValue;
// look if we have to use precisions
bool bUseLiteral = false;
OUString sPrefix,sPostfix,sCreateParams;
{
Reference<XResultSet> xRes = xMetaData->getTypeInfo();
if(xRes.is())
{
Reference<XRow> xRow(xRes,UNO_QUERY);
while(xRes->next())
{
OUString sTypeName2Cmp = xRow->getString(1);
sal_Int32 nType = xRow->getShort(2);
sPrefix = xRow->getString (4);
sPostfix = xRow->getString (5);
sCreateParams = xRow->getString(6);
// first identical type will be used if typename is empty
if ( sTypeName.isEmpty() && nType == nDataType )
sTypeName = sTypeName2Cmp;
if( sTypeName.equalsIgnoreAsciiCase(sTypeName2Cmp) && nType == nDataType && !sCreateParams.isEmpty() && !xRow->wasNull())
{
bUseLiteral = true;
break;
}
}
}
}
if ( !sAutoIncrementValue.isEmpty() )
{
sal_Int32 nIndex = sTypeName.indexOf(sAutoIncrementValue);
if (nIndex != -1)
sTypeName = sTypeName.replaceAt(nIndex,sTypeName.getLength() - nIndex, u"");
}
if ( (nPrecision > 0 || nScale > 0) && bUseLiteral )
{
bool bTimed = (nDataType == DataType::TIME ||
nDataType == DataType::TIME_WITH_TIMEZONE ||
nDataType == DataType::TIMESTAMP ||
nDataType == DataType::TIMESTAMP_WITH_TIMEZONE);
sal_Int32 nParenPos = (nDataType == DataType::TIME_WITH_TIMEZONE ||
nDataType == DataType::TIMESTAMP_WITH_TIMEZONE) ?
sTypeName.indexOf(' ') :
sTypeName.indexOf('(');
if ( nParenPos == -1 )
aSql.append(sTypeName);
else
aSql.append(sTypeName.subView(0, nParenPos));
aSql.append("(");
if ( nPrecision > 0 && !bTimed )
{
aSql.append(nPrecision);
if ( (nScale > 0) || (!_sCreatePattern.empty() && sCreateParams.indexOf(_sCreatePattern) != -1) )
aSql.append(",");
}
if ( (nScale > 0) || ( !_sCreatePattern.empty() && sCreateParams.indexOf(_sCreatePattern) != -1 ) || bTimed )
aSql.append(nScale);
if ( nParenPos == -1 )
aSql.append(")");
else
{
if ( bTimed )
aSql.append(")");
else
nParenPos = sTypeName.indexOf(')',nParenPos);
aSql.append(sTypeName.subView(nParenPos));
}
}
else
aSql.append(sTypeName); // simply add the type name
OUString aDefault = ::comphelper::getString(xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_DEFAULTVALUE)));
if ( !aDefault.isEmpty() )
{
aSql.append(" DEFAULT " + sPrefix + aDefault + sPostfix);
} // if ( aDefault.getLength() )
return aSql.makeStringAndClear();
}
OUString createStandardColumnPart(const Reference< XPropertySet >& xColProp,const Reference< XConnection>& _xConnection,ISQLStatementHelper* _pHelper,std::u16string_view _sCreatePattern)
{
Reference<XDatabaseMetaData> xMetaData = _xConnection->getMetaData();
::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap();
bool bIsAutoIncrement = false;
xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_ISAUTOINCREMENT)) >>= bIsAutoIncrement;
const OUString sQuoteString = xMetaData->getIdentifierQuoteString();
OUStringBuffer aSql(::dbtools::quoteName(sQuoteString,::comphelper::getString(xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME)))));
// check if the user enter a specific string to create autoincrement values
OUString sAutoIncrementValue;
Reference<XPropertySetInfo> xPropInfo = xColProp->getPropertySetInfo();
if ( xPropInfo.is() && xPropInfo->hasPropertyByName(rPropMap.getNameByIndex(PROPERTY_ID_AUTOINCREMENTCREATION)) )
xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_AUTOINCREMENTCREATION)) >>= sAutoIncrementValue;
aSql.append(" " + createStandardTypePart(xColProp, _xConnection, _sCreatePattern));
if(::comphelper::getINT32(xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_ISNULLABLE))) == ColumnValue::NO_NULLS)
aSql.append(" NOT NULL");
if ( bIsAutoIncrement && !sAutoIncrementValue.isEmpty())
{
aSql.append(" " + sAutoIncrementValue);
}
if ( _pHelper )
_pHelper->addComment(xColProp,aSql);
return aSql.makeStringAndClear();
}
OUString createStandardCreateStatement(const Reference< XPropertySet >& descriptor,const Reference< XConnection>& _xConnection,ISQLStatementHelper* _pHelper,std::u16string_view _sCreatePattern)
{
OUStringBuffer aSql("CREATE TABLE ");
OUString sCatalog,sSchema,sTable,sComposedName;
Reference<XDatabaseMetaData> xMetaData = _xConnection->getMetaData();
::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap();
descriptor->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_CATALOGNAME)) >>= sCatalog;
descriptor->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_SCHEMANAME)) >>= sSchema;
descriptor->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME)) >>= sTable;
sComposedName = ::dbtools::composeTableName( xMetaData, sCatalog, sSchema, sTable, true, ::dbtools::EComposeRule::InTableDefinitions );
if ( sComposedName.isEmpty() )
::dbtools::throwFunctionSequenceException(_xConnection);
aSql.append(sComposedName + " (");
// columns
Reference<XColumnsSupplier> xColumnSup(descriptor,UNO_QUERY);
Reference<XIndexAccess> xColumns(xColumnSup->getColumns(),UNO_QUERY);
// check if there are columns
if(!xColumns.is() || !xColumns->getCount())
::dbtools::throwFunctionSequenceException(_xConnection);
Reference< XPropertySet > xColProp;
sal_Int32 nCount = xColumns->getCount();
for(sal_Int32 i=0;i<nCount;++i)
{
if ( (xColumns->getByIndex(i) >>= xColProp) && xColProp.is() )
{
aSql.append(
createStandardColumnPart(xColProp,_xConnection,_pHelper,_sCreatePattern)
+ ",");
}
}
return aSql.makeStringAndClear();
}
namespace
{
OUString generateColumnNames(const Reference<XIndexAccess>& _xColumns,const Reference<XDatabaseMetaData>& _xMetaData)
{
::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap();
const OUString sQuote(_xMetaData->getIdentifierQuoteString());
OUStringBuffer sSql( " (" );
Reference< XPropertySet > xColProp;
sal_Int32 nColCount = _xColumns->getCount();
for(sal_Int32 i=0;i<nColCount;++i)
{
if ( (_xColumns->getByIndex(i) >>= xColProp) && xColProp.is() )
sSql.append( ::dbtools::quoteName(sQuote,::comphelper::getString(xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME)))) +
",");
}
if ( nColCount )
sSql[sSql.getLength()-1] = ')';
return sSql.makeStringAndClear();
}
}
OUString createStandardKeyStatement(const Reference< XPropertySet >& descriptor,const Reference< XConnection>& _xConnection)
{
Reference<XDatabaseMetaData> xMetaData = _xConnection->getMetaData();
::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap();
OUStringBuffer aSql;
// keys
Reference<XKeysSupplier> xKeySup(descriptor,UNO_QUERY);
Reference<XIndexAccess> xKeys = xKeySup->getKeys();
if ( xKeys.is() )
{
Reference< XPropertySet > xColProp;
Reference<XIndexAccess> xColumns;
Reference<XColumnsSupplier> xColumnSup;
OUString sCatalog,sSchema,sTable,sComposedName;
bool bPKey = false;
for(sal_Int32 i=0;i<xKeys->getCount();++i)
{
if ( (xKeys->getByIndex(i) >>= xColProp) && xColProp.is() )
{
sal_Int32 nKeyType = ::comphelper::getINT32(xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_TYPE)));
if ( nKeyType == KeyType::PRIMARY )
{
if(bPKey)
::dbtools::throwFunctionSequenceException(_xConnection);
bPKey = true;
xColumnSup.set(xColProp,UNO_QUERY);
xColumns.set(xColumnSup->getColumns(),UNO_QUERY);
if(!xColumns.is() || !xColumns->getCount())
::dbtools::throwFunctionSequenceException(_xConnection);
aSql.append(" PRIMARY KEY " + generateColumnNames(xColumns,xMetaData));
}
else if(nKeyType == KeyType::UNIQUE)
{
xColumnSup.set(xColProp,UNO_QUERY);
xColumns.set(xColumnSup->getColumns(),UNO_QUERY);
if(!xColumns.is() || !xColumns->getCount())
::dbtools::throwFunctionSequenceException(_xConnection);
aSql.append(" UNIQUE " + generateColumnNames(xColumns,xMetaData));
}
else if(nKeyType == KeyType::FOREIGN)
{
sal_Int32 nDeleteRule = getINT32(xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_DELETERULE)));
xColumnSup.set(xColProp,UNO_QUERY);
xColumns.set(xColumnSup->getColumns(),UNO_QUERY);
if(!xColumns.is() || !xColumns->getCount())
::dbtools::throwFunctionSequenceException(_xConnection);
aSql.append(" FOREIGN KEY ");
OUString sRefTable = getString(xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_REFERENCEDTABLE)));
::dbtools::qualifiedNameComponents(xMetaData,
sRefTable,
sCatalog,
sSchema,
sTable,
::dbtools::EComposeRule::InDataManipulation);
sComposedName = ::dbtools::composeTableName( xMetaData, sCatalog, sSchema, sTable, true, ::dbtools::EComposeRule::InTableDefinitions );
if ( sComposedName.isEmpty() )
::dbtools::throwFunctionSequenceException(_xConnection);
aSql.append(generateColumnNames(xColumns,xMetaData));
switch(nDeleteRule)
{
case KeyRule::CASCADE:
aSql.append(" ON DELETE CASCADE ");
break;
case KeyRule::RESTRICT:
aSql.append(" ON DELETE RESTRICT ");
break;
case KeyRule::SET_NULL:
aSql.append(" ON DELETE SET NULL ");
break;
case KeyRule::SET_DEFAULT:
aSql.append(" ON DELETE SET DEFAULT ");
break;
default:
;
}
}
}
}
}
if ( !aSql.isEmpty() )
{
if ( aSql[aSql.getLength() - 1] == ',' )
aSql[aSql.getLength() - 1] = ')';
else
aSql.append(")");
}
return aSql.makeStringAndClear();
}
OUString createSqlCreateTableStatement( const Reference< XPropertySet >& descriptor,
const Reference< XConnection>& _xConnection)
{
OUString aSql = ::dbtools::createStandardCreateStatement(descriptor,_xConnection,nullptr,{});
const OUString sKeyStmt = ::dbtools::createStandardKeyStatement(descriptor,_xConnection);
if ( !sKeyStmt.isEmpty() )
aSql += sKeyStmt;
else
{
if ( aSql.endsWith(",") )
aSql = aSql.replaceAt(aSql.getLength()-1, 1, u")");
else
aSql += ")";
}
return aSql;
}
namespace
{
Reference<XPropertySet> lcl_createSDBCXColumn(const Reference<XNameAccess>& _xPrimaryKeyColumns,
const Reference<XConnection>& _xConnection,
const Any& _aCatalog,
const OUString& _aSchema,
const OUString& _aTable,
const OUString& _rQueryName,
const OUString& _rName,
bool _bCase,
bool _bQueryForInfo,
bool _bIsAutoIncrement,
bool _bIsCurrency,
sal_Int32 _nDataType)
{
Reference<XPropertySet> xProp;
Reference<XDatabaseMetaData> xMetaData = _xConnection->getMetaData();
Reference< XResultSet > xResult = xMetaData->getColumns(_aCatalog, _aSchema, _aTable, _rQueryName);
OUString sCatalog;
_aCatalog >>= sCatalog;
if ( xResult.is() )
{
UStringMixEqual aMixCompare(_bCase);
Reference< XRow > xRow(xResult,UNO_QUERY);
while( xResult->next() )
{
if ( aMixCompare(xRow->getString(4),_rName) )
{
sal_Int32 nField5 = xRow->getInt(5);
OUString aField6 = xRow->getString(6);
sal_Int32 nField7 = xRow->getInt(7)
, nField9 = xRow->getInt(9)
, nField11= xRow->getInt(11);
OUString sField12 = xRow->getString(12),
sField13 = xRow->getString(13);
::comphelper::disposeComponent(xRow);
bool bAutoIncrement = _bIsAutoIncrement
,bIsCurrency = _bIsCurrency;
if ( _bQueryForInfo )
{
const OUString sQuote = xMetaData->getIdentifierQuoteString();
OUString sQuotedName = ::dbtools::quoteName(sQuote,_rName);
OUString sComposedName = composeTableNameForSelect(_xConnection, getString( _aCatalog ), _aSchema, _aTable );
ColumnInformationMap aInfo((UStringMixLess(_bCase)));
collectColumnInformation(_xConnection,sComposedName,sQuotedName,aInfo);
ColumnInformationMap::const_iterator aIter = aInfo.begin();
if ( aIter != aInfo.end() )
{
bAutoIncrement = aIter->second.first.first;
bIsCurrency = aIter->second.first.second;
if ( DataType::OTHER == nField5 )
nField5 = aIter->second.second;
}
}
else if ( DataType::OTHER == nField5 )
nField5 = _nDataType;
if ( nField11 != ColumnValue::NO_NULLS )
{
try
{
if ( _xPrimaryKeyColumns.is() )
{
if ( _xPrimaryKeyColumns->hasByName(_rName) )
nField11 = ColumnValue::NO_NULLS;
}
else
{
Reference< XResultSet > xPKeys = xMetaData->getPrimaryKeys( _aCatalog, _aSchema, _aTable );
Reference< XRow > xPKeyRow( xPKeys, UNO_QUERY_THROW );
while( xPKeys->next() ) // there can be only one primary key
{
OUString sKeyColumn = xPKeyRow->getString(4);
if ( aMixCompare(_rName,sKeyColumn) )
{
nField11 = ColumnValue::NO_NULLS;
break;
}
}
}
}
catch(SQLException&)
{
TOOLS_WARN_EXCEPTION( "connectivity.commontools", "lcl_createSDBCXColumn" );
}
}
xProp = new connectivity::sdbcx::OColumn(_rName,
aField6,
sField13,
sField12,
nField11,
nField7,
nField9,
nField5,
bAutoIncrement,
false,
bIsCurrency,
_bCase,
sCatalog,
_aSchema,
_aTable);
break;
}
}
}
return xProp;
}
Reference< XModel> lcl_getXModel(const Reference< XInterface>& _xIface)
{
Reference< XInterface > xParent = _xIface;
Reference< XModel > xModel(xParent,UNO_QUERY);
while( xParent.is() && !xModel.is() )
{
Reference<XChild> xChild(xParent,UNO_QUERY);
xParent.set(xChild.is() ? xChild->getParent() : Reference< XInterface >(),UNO_QUERY);
xModel.set(xParent,UNO_QUERY);
}
return xModel;
}
}
Reference<XPropertySet> createSDBCXColumn(const Reference<XPropertySet>& _xTable,
const Reference<XConnection>& _xConnection,
const OUString& _rName,
bool _bCase,
bool _bQueryForInfo,
bool _bIsAutoIncrement,
bool _bIsCurrency,
sal_Int32 _nDataType)
{
Reference<XPropertySet> xProp;
OSL_ENSURE(_xTable.is(),"Table is NULL!");
if ( !_xTable.is() )
return xProp;
::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap();
Any aCatalog = _xTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_CATALOGNAME));
OUString sCatalog;
aCatalog >>= sCatalog;
OUString aSchema, aTable;
_xTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_SCHEMANAME)) >>= aSchema;
_xTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME)) >>= aTable;
Reference<XNameAccess> xPrimaryKeyColumns = getPrimaryKeyColumns_throw(_xTable);
xProp = lcl_createSDBCXColumn(xPrimaryKeyColumns,_xConnection,aCatalog, aSchema, aTable, _rName,_rName,_bCase,_bQueryForInfo,_bIsAutoIncrement,_bIsCurrency,_nDataType);
if ( !xProp.is() )
{
xProp = lcl_createSDBCXColumn(xPrimaryKeyColumns,_xConnection,aCatalog, aSchema, aTable, u"%"_ustr,_rName,_bCase,_bQueryForInfo,_bIsAutoIncrement,_bIsCurrency,_nDataType);
if ( !xProp.is() )
xProp = new connectivity::sdbcx::OColumn(_rName,
OUString(),OUString(),OUString(),
ColumnValue::NULLABLE_UNKNOWN,
0,
0,
DataType::VARCHAR,
_bIsAutoIncrement,
false,
_bIsCurrency,
_bCase,
sCatalog,
aSchema,
aTable);
}
return xProp;
}
bool getBooleanDataSourceSetting( const Reference< XConnection >& _rxConnection, const char* _pAsciiSettingName )
{
return getBooleanDataSourceSetting(_rxConnection, OUString::createFromAscii( _pAsciiSettingName ));
}
bool getBooleanDataSourceSetting( const Reference< XConnection >& _rxConnection, const OUString & rSettingName )
{
bool bValue( false );
try
{
Reference< XPropertySet> xDataSourceProperties( findDataSource( _rxConnection ), UNO_QUERY );
OSL_ENSURE( xDataSourceProperties.is(), "::dbtools::getBooleanDataSourceSetting: somebody is using this with a non-SDB-level connection!" );
if ( xDataSourceProperties.is() )
{
Reference< XPropertySet > xSettings(
xDataSourceProperties->getPropertyValue(u"Settings"_ustr),
UNO_QUERY_THROW
);
OSL_VERIFY( xSettings->getPropertyValue( rSettingName ) >>= bValue );
}
}
catch( const Exception& )
{
DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
}
return bValue;
}
bool getDataSourceSetting( const Reference< XInterface >& _xChild, const OUString& _sAsciiSettingsName,
Any& /* [out] */ _rSettingsValue )
{
bool bIsPresent = false;
try
{
const Reference< XPropertySet> xDataSourceProperties( findDataSource( _xChild ), UNO_QUERY );
if ( !xDataSourceProperties.is() )
return false;
const Reference< XPropertySet > xSettings(
xDataSourceProperties->getPropertyValue(u"Settings"_ustr),
UNO_QUERY_THROW
);
_rSettingsValue = xSettings->getPropertyValue( _sAsciiSettingsName );
bIsPresent = true;
}
catch( const Exception& )
{
bIsPresent = false;
}
return bIsPresent;
}
bool getDataSourceSetting( const Reference< XInterface >& _rxDataSource, const char* _pAsciiSettingsName,
Any& /* [out] */ _rSettingsValue )
{
OUString sAsciiSettingsName = OUString::createFromAscii(_pAsciiSettingsName);
return getDataSourceSetting( _rxDataSource, sAsciiSettingsName,_rSettingsValue );
}
bool isDataSourcePropertyEnabled(const Reference<XInterface>& _xProp, const OUString& _sProperty, bool _bDefault)
{
bool bEnabled = _bDefault;
try
{
Reference< XPropertySet> xProp(findDataSource(_xProp),UNO_QUERY);
if ( xProp.is() )
{
Sequence< PropertyValue > aInfo;
xProp->getPropertyValue(u"Info"_ustr) >>= aInfo;
const PropertyValue* pValue =std::find_if(std::cbegin(aInfo),
std::cend(aInfo),
[&_sProperty](const PropertyValue& lhs)
{ return lhs.Name == _sProperty; });
if ( pValue != std::cend(aInfo) )
pValue->Value >>= bEnabled;
}
}
catch(SQLException&)
{
DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
}
return bEnabled;
}
Reference< XTablesSupplier> getDataDefinitionByURLAndConnection(
const OUString& _rsUrl,
const Reference< XConnection>& _xConnection,
const Reference< XComponentContext >& _rxContext)
{
Reference< XTablesSupplier> xTablesSup;
try
{
Reference< XDriverManager2 > xManager = DriverManager::create( _rxContext );
Reference< XDataDefinitionSupplier > xSupp( xManager->getDriverByURL( _rsUrl ), UNO_QUERY );
if ( xSupp.is() )
{
xTablesSup = xSupp->getDataDefinitionByConnection( _xConnection );
OSL_ENSURE(xTablesSup.is(),"No table supplier!");
}
}
catch( const Exception& )
{
DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
}
return xTablesSup;
}
sal_Int32 getTablePrivileges(const Reference< XDatabaseMetaData>& _xMetaData,
const OUString& _sCatalog,
const OUString& _sSchema,
const OUString& _sTable)
{
OSL_ENSURE(_xMetaData.is(),"Invalid metadata!");
sal_Int32 nPrivileges = 0;
try
{
Any aVal;
if(!_sCatalog.isEmpty())
aVal <<= _sCatalog;
Reference< XResultSet > xPrivileges = _xMetaData->getTablePrivileges(aVal, _sSchema, _sTable);
Reference< XRow > xCurrentRow(xPrivileges, UNO_QUERY);
const OUString sUserWorkingFor = _xMetaData->getUserName();
static const char sSELECT[] = "SELECT";
static const char sINSERT[] = "INSERT";
static const char sUPDATE[] = "UPDATE";
static const char sDELETE[] = "DELETE";
static const char sREAD[] = "READ";
static const char sCREATE[] = "CREATE";
static const char sALTER[] = "ALTER";
static const char sREFERENCE[] = "REFERENCE";
static const char sDROP[] = "DROP";
if ( xCurrentRow.is() )
{
// after creation the set is positioned before the first record, per definition
OUString sPrivilege, sGrantee;
while ( xPrivileges->next() )
{
sGrantee = xCurrentRow->getString(5);
sPrivilege = xCurrentRow->getString(6);
if (!sUserWorkingFor.equalsIgnoreAsciiCase(sGrantee))
continue;
if (sPrivilege.equalsIgnoreAsciiCase(sSELECT))
nPrivileges |= Privilege::SELECT;
else if (sPrivilege.equalsIgnoreAsciiCase(sINSERT))
nPrivileges |= Privilege::INSERT;
else if (sPrivilege.equalsIgnoreAsciiCase(sUPDATE))
nPrivileges |= Privilege::UPDATE;
else if (sPrivilege.equalsIgnoreAsciiCase(sDELETE))
nPrivileges |= Privilege::DELETE;
else if (sPrivilege.equalsIgnoreAsciiCase(sREAD))
nPrivileges |= Privilege::READ;
else if (sPrivilege.equalsIgnoreAsciiCase(sCREATE))
nPrivileges |= Privilege::CREATE;
else if (sPrivilege.equalsIgnoreAsciiCase(sALTER))
nPrivileges |= Privilege::ALTER;
else if (sPrivilege.equalsIgnoreAsciiCase(sREFERENCE))
nPrivileges |= Privilege::REFERENCE;
else if (sPrivilege.equalsIgnoreAsciiCase(sDROP))
nPrivileges |= Privilege::DROP;
}
}
disposeComponent(xPrivileges);
// Some drivers put a table privilege as soon as any column has the privilege,
// some drivers only if all columns have the privilege.
// To unify the situation, collect column privileges here, too.
Reference< XResultSet > xColumnPrivileges = _xMetaData->getColumnPrivileges(aVal, _sSchema, _sTable, u"%"_ustr);
Reference< XRow > xColumnCurrentRow(xColumnPrivileges, UNO_QUERY);
if ( xColumnCurrentRow.is() )
{
// after creation the set is positioned before the first record, per definition
OUString sPrivilege, sGrantee;
while ( xColumnPrivileges->next() )
{
sGrantee = xColumnCurrentRow->getString(6);
sPrivilege = xColumnCurrentRow->getString(7);
if (!sUserWorkingFor.equalsIgnoreAsciiCase(sGrantee))
continue;
if (sPrivilege.equalsIgnoreAsciiCase(sSELECT))
nPrivileges |= Privilege::SELECT;
else if (sPrivilege.equalsIgnoreAsciiCase(sINSERT))
nPrivileges |= Privilege::INSERT;
else if (sPrivilege.equalsIgnoreAsciiCase(sUPDATE))
nPrivileges |= Privilege::UPDATE;
else if (sPrivilege.equalsIgnoreAsciiCase(sDELETE))
nPrivileges |= Privilege::DELETE;
else if (sPrivilege.equalsIgnoreAsciiCase(sREAD))
nPrivileges |= Privilege::READ;
else if (sPrivilege.equalsIgnoreAsciiCase(sCREATE))
nPrivileges |= Privilege::CREATE;
else if (sPrivilege.equalsIgnoreAsciiCase(sALTER))
nPrivileges |= Privilege::ALTER;
else if (sPrivilege.equalsIgnoreAsciiCase(sREFERENCE))
nPrivileges |= Privilege::REFERENCE;
else if (sPrivilege.equalsIgnoreAsciiCase(sDROP))
nPrivileges |= Privilege::DROP;
}
}
disposeComponent(xColumnPrivileges);
}
catch(const SQLException& e)
{
// some drivers don't support any privileges so we assume that we are allowed to do all we want :-)
if(e.SQLState == "IM001")
nPrivileges |= Privilege::DROP |
Privilege::REFERENCE |
Privilege::ALTER |
Privilege::CREATE |
Privilege::READ |
Privilege::DELETE |
Privilege::UPDATE |
Privilege::INSERT |
Privilege::SELECT;
else
OSL_FAIL("Could not collect the privileges !");
}
return nPrivileges;
}
// we need some more information about the column
void collectColumnInformation(const Reference< XConnection>& _xConnection,
std::u16string_view _sComposedName,
std::u16string_view _rName,
ColumnInformationMap& _rInfo)
{
OUString sSelect = OUString::Concat("SELECT ") + _rName +
" FROM " + _sComposedName +
" WHERE 0 = 1";
try
{
::utl::SharedUNOComponent< XStatement > xStmt( _xConnection->createStatement() );
Reference< XPropertySet > xStatementProps( xStmt, UNO_QUERY_THROW );
xStatementProps->setPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_ESCAPEPROCESSING ), Any( false ) );
Reference< XResultSet > xResult( xStmt->executeQuery( sSelect ), UNO_SET_THROW );
Reference< XResultSetMetaDataSupplier > xSuppMeta( xResult, UNO_QUERY_THROW );
Reference< XResultSetMetaData > xMeta( xSuppMeta->getMetaData(), UNO_SET_THROW );
sal_Int32 nCount = xMeta->getColumnCount();
OSL_ENSURE( nCount != 0, "::dbtools::collectColumnInformation: result set has empty (column-less) meta data!" );
for (sal_Int32 i=1; i <= nCount ; ++i)
{
_rInfo.emplace( xMeta->getColumnName(i),
ColumnInformation(TBoolPair(xMeta->isAutoIncrement(i),xMeta->isCurrency(i)),xMeta->getColumnType(i)));
}
}
catch( const Exception& )
{
DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
}
}
bool isEmbeddedInDatabase( const Reference< XInterface >& _rxComponent, Reference< XConnection >& _rxActualConnection )
{
bool bIsEmbedded = false;
try
{
Reference< XModel > xModel = lcl_getXModel( _rxComponent );
if ( xModel.is() )
{
for (auto& arg : xModel->getArgs())
{
if (arg.Name == "ComponentData")
{
Sequence<PropertyValue> aDocumentContext;
arg.Value >>= aDocumentContext;
for (auto& item : aDocumentContext)
{
if (item.Name == "ActiveConnection" && (item.Value >>= _rxActualConnection))
{
bIsEmbedded = true;
break;
}
}
break;
}
}
}
}
catch(Exception&)
{
// not interested in
}
return bIsEmbedded;
}
namespace
{
OUString lcl_getEncodingName( rtl_TextEncoding _eEncoding )
{
OUString sEncodingName;
OCharsetMap aCharsets;
OCharsetMap::CharsetIterator aEncodingPos = aCharsets.find( _eEncoding );
OSL_ENSURE( aEncodingPos != aCharsets.end(), "lcl_getEncodingName: *which* encoding?" );
if ( aEncodingPos != aCharsets.end() )
sEncodingName = (*aEncodingPos).getIanaName();
return sEncodingName;
}
}
sal_Int32 DBTypeConversion::convertUnicodeString( const OUString& _rSource, OString& _rDest, rtl_TextEncoding _eEncoding )
{
if ( !rtl_convertUStringToString( &_rDest.pData, _rSource.getStr(), _rSource.getLength(),
_eEncoding,
RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR |
RTL_UNICODETOTEXT_FLAGS_UNDEFINED_REPLACE |
RTL_UNICODETOTEXT_FLAGS_PRIVATE_MAPTO0 )
)
{
SharedResources aResources;
OUString sMessage = aResources.getResourceStringWithSubstitution( STR_CANNOT_CONVERT_STRING,
"$string$", _rSource,
"$charset$", lcl_getEncodingName( _eEncoding )
);
throw SQLException(
sMessage,
nullptr,
u"22018"_ustr,
22018,
Any()
);
}
return _rDest.getLength();
}
sal_Int32 DBTypeConversion::convertUnicodeStringToLength( const OUString& _rSource, OString& _rDest,
sal_Int32 _nMaxLen, rtl_TextEncoding _eEncoding )
{
sal_Int32 nLen = convertUnicodeString( _rSource, _rDest, _eEncoding );
if ( nLen > _nMaxLen )
{
SharedResources aResources;
OUString sMessage = aResources.getResourceStringWithSubstitution( STR_STRING_LENGTH_EXCEEDED,
"$string$", _rSource,
"$maxlen$", OUString::number( _nMaxLen ),
"$charset$", lcl_getEncodingName( _eEncoding )
);
throw SQLException(
sMessage,
nullptr,
u"22001"_ustr,
22001,
Any()
);
}
return nLen;
}
OUString getDefaultReportEngineServiceName(const Reference< XComponentContext >& _rxORB)
{
::utl::OConfigurationTreeRoot aReportEngines = ::utl::OConfigurationTreeRoot::createWithComponentContext(
_rxORB, u"org.openoffice.Office.DataAccess/ReportEngines"_ustr, -1, ::utl::OConfigurationTreeRoot::CM_READONLY);
if ( aReportEngines.isValid() )
{
OUString sDefaultReportEngineName;
aReportEngines.getNodeValue(u"DefaultReportEngine"_ustr) >>= sDefaultReportEngineName;
if ( !sDefaultReportEngineName.isEmpty() )
{
::utl::OConfigurationNode aReportEngineNames = aReportEngines.openNode(u"ReportEngineNames"_ustr);
if ( aReportEngineNames.isValid() )
{
::utl::OConfigurationNode aReportEngine = aReportEngineNames.openNode(sDefaultReportEngineName);
if ( aReportEngine.isValid() )
{
OUString sRet;
aReportEngine.getNodeValue(u"ServiceName"_ustr) >>= sRet;
return sRet;
}
}
}
else
return u"org.libreoffice.report.pentaho.SOReportJobFactory"_ustr;
}
else
return u"org.libreoffice.report.pentaho.SOReportJobFactory"_ustr;
return OUString();
}
bool isAggregateColumn(const Reference< XSingleSelectQueryComposer > &_xParser, const Reference< XPropertySet > &_xField)
{
OUString sName;
_xField->getPropertyValue(u"Name"_ustr) >>= sName;
Reference< XColumnsSupplier > xColumnsSupplier(_xParser, UNO_QUERY);
Reference< css::container::XNameAccess > xCols;
if (xColumnsSupplier.is())
xCols = xColumnsSupplier->getColumns();
return isAggregateColumn(xCols, sName);
}
bool isAggregateColumn(const Reference< XNameAccess > &_xColumns, const OUString &_sName)
{
if ( _xColumns.is() && _xColumns->hasByName(_sName) )
{
Reference<XPropertySet> xProp(_xColumns->getByName(_sName),UNO_QUERY);
assert(xProp.is());
return isAggregateColumn( xProp );
}
return false;
}
bool isAggregateColumn( const Reference< XPropertySet > &_xColumn )
{
bool bAgg(false);
static constexpr OUString sAgg = u"AggregateFunction"_ustr;
if ( _xColumn->getPropertySetInfo()->hasPropertyByName(sAgg) )
_xColumn->getPropertyValue(sAgg) >>= bAgg;
return bAgg;
}
} // namespace dbtools
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
↑ V530 The return value of function 'append' is required to be utilized.
↑ V530 The return value of function 'append' is required to be utilized.
↑ V530 The return value of function 'append' is required to be utilized.
↑ V530 The return value of function 'append' is required to be utilized.
↑ V560 A part of conditional expression is always false: nPrecision > 0.
↑ V560 A part of conditional expression is always false: nScale > 0.