1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <connectivity/dbtools.hxx>
21 #include <connectivity/dbconversion.hxx>
22 #include <connectivity/dbcharset.hxx>
23 #include <SQLStatementHelper.hxx>
24 #include <unotools/confignode.hxx>
25 #include <resource/sharedresources.hxx>
26 #include <strings.hrc>
27 #include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
28 #include <com/sun/star/sdbc/SQLException.hpp>
29 #include <com/sun/star/sdbc/XConnection.hpp>
30 #include <com/sun/star/sdbc/XDataSource.hpp>
31 #include <com/sun/star/sdbc/ColumnValue.hpp>
32 #include <com/sun/star/sdbc/DataType.hpp>
33 #include <com/sun/star/sdbc/DriverManager.hpp>
34 #include <com/sun/star/sdbc/XRow.hpp>
35 #include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
36 #include <com/sun/star/sdbcx/XKeysSupplier.hpp>
37 #include <com/sun/star/sdbcx/XDataDefinitionSupplier.hpp>
38 #include <com/sun/star/sdbcx/Privilege.hpp>
39 #include <com/sun/star/container/XIndexAccess.hpp>
40 #include <com/sun/star/sdbc/KeyRule.hpp>
41 #include <com/sun/star/sdbcx/KeyType.hpp>
42 #include <TConnection.hxx>
43 #include <connectivity/sdbcx/VColumn.hxx>
44 #include <com/sun/star/frame/XModel.hpp>
45 #include <com/sun/star/container/XChild.hpp>
47 #include <comphelper/types.hxx>
48 #include <comphelper/diagnose_ex.hxx>
49 #include <unotools/sharedunocomponent.hxx>
51 #include <string_view>
56 using namespace ::com::sun::star::uno
;
57 using namespace ::com::sun::star::beans
;
58 using namespace ::com::sun::star::sdb
;
59 using namespace ::com::sun::star::sdbc
;
60 using namespace ::com::sun::star::sdbcx
;
61 using namespace ::com::sun::star::lang
;
62 using namespace ::com::sun::star::container
;
63 using namespace ::com::sun::star::frame
;
64 using namespace connectivity
;
65 using namespace comphelper
;
67 OUString
createStandardTypePart(const Reference
< XPropertySet
>& xColProp
,const Reference
< XConnection
>& _xConnection
,std::u16string_view _sCreatePattern
)
70 Reference
<XDatabaseMetaData
> xMetaData
= _xConnection
->getMetaData();
72 ::dbtools::OPropertyMap
& rPropMap
= OMetaConnection::getPropMap();
75 sal_Int32 nDataType
= 0;
76 sal_Int32 nPrecision
= 0;
79 nDataType
= nPrecision
= nScale
= 0;
81 xColProp
->getPropertyValue(rPropMap
.getNameByIndex(PROPERTY_ID_TYPENAME
)) >>= sTypeName
;
82 xColProp
->getPropertyValue(rPropMap
.getNameByIndex(PROPERTY_ID_TYPE
)) >>= nDataType
;
83 xColProp
->getPropertyValue(rPropMap
.getNameByIndex(PROPERTY_ID_PRECISION
)) >>= nPrecision
;
84 xColProp
->getPropertyValue(rPropMap
.getNameByIndex(PROPERTY_ID_SCALE
)) >>= nScale
;
88 // check if the user enter a specific string to create autoincrement values
89 OUString sAutoIncrementValue
;
90 Reference
<XPropertySetInfo
> xPropInfo
= xColProp
->getPropertySetInfo();
91 if ( xPropInfo
.is() && xPropInfo
->hasPropertyByName(rPropMap
.getNameByIndex(PROPERTY_ID_AUTOINCREMENTCREATION
)) )
92 xColProp
->getPropertyValue(rPropMap
.getNameByIndex(PROPERTY_ID_AUTOINCREMENTCREATION
)) >>= sAutoIncrementValue
;
93 // look if we have to use precisions
94 bool bUseLiteral
= false;
95 OUString sPrefix
,sPostfix
,sCreateParams
;
97 Reference
<XResultSet
> xRes
= xMetaData
->getTypeInfo();
100 Reference
<XRow
> xRow(xRes
,UNO_QUERY
);
103 OUString sTypeName2Cmp
= xRow
->getString(1);
104 sal_Int32 nType
= xRow
->getShort(2);
105 sPrefix
= xRow
->getString (4);
106 sPostfix
= xRow
->getString (5);
107 sCreateParams
= xRow
->getString(6);
108 // first identical type will be used if typename is empty
109 if ( sTypeName
.isEmpty() && nType
== nDataType
)
110 sTypeName
= sTypeName2Cmp
;
112 if( sTypeName
.equalsIgnoreAsciiCase(sTypeName2Cmp
) && nType
== nDataType
&& !sCreateParams
.isEmpty() && !xRow
->wasNull())
121 if ( !sAutoIncrementValue
.isEmpty() )
123 sal_Int32 nIndex
= sTypeName
.indexOf(sAutoIncrementValue
);
125 sTypeName
= sTypeName
.replaceAt(nIndex
,sTypeName
.getLength() - nIndex
, u
"");
128 if ( (nPrecision
> 0 || nScale
> 0) && bUseLiteral
)
130 bool bTimed
= (nDataType
== DataType::TIME
||
131 nDataType
== DataType::TIME_WITH_TIMEZONE
||
132 nDataType
== DataType::TIMESTAMP
||
133 nDataType
== DataType::TIMESTAMP_WITH_TIMEZONE
);
135 sal_Int32 nParenPos
= (nDataType
== DataType::TIME_WITH_TIMEZONE
||
136 nDataType
== DataType::TIMESTAMP_WITH_TIMEZONE
) ?
137 sTypeName
.indexOf(' ') :
138 sTypeName
.indexOf('(');
140 if ( nParenPos
== -1 )
141 aSql
.append(sTypeName
);
143 aSql
.append(sTypeName
.subView(0, nParenPos
));
146 if ( nPrecision
> 0 && !bTimed
)
148 aSql
.append(nPrecision
);
149 if ( (nScale
> 0) || (!_sCreatePattern
.empty() && sCreateParams
.indexOf(_sCreatePattern
) != -1) )
152 if ( (nScale
> 0) || ( !_sCreatePattern
.empty() && sCreateParams
.indexOf(_sCreatePattern
) != -1 ) || bTimed
)
155 if ( nParenPos
== -1 )
162 nParenPos
= sTypeName
.indexOf(')',nParenPos
);
163 aSql
.append(sTypeName
.subView(nParenPos
));
167 aSql
.append(sTypeName
); // simply add the type name
169 OUString aDefault
= ::comphelper::getString(xColProp
->getPropertyValue(rPropMap
.getNameByIndex(PROPERTY_ID_DEFAULTVALUE
)));
170 if ( !aDefault
.isEmpty() )
172 aSql
.append(" DEFAULT " + sPrefix
+ aDefault
+ sPostfix
);
173 } // if ( aDefault.getLength() )
175 return aSql
.makeStringAndClear();
178 OUString
createStandardColumnPart(const Reference
< XPropertySet
>& xColProp
,const Reference
< XConnection
>& _xConnection
,ISQLStatementHelper
* _pHelper
,std::u16string_view _sCreatePattern
)
180 Reference
<XDatabaseMetaData
> xMetaData
= _xConnection
->getMetaData();
182 ::dbtools::OPropertyMap
& rPropMap
= OMetaConnection::getPropMap();
184 bool bIsAutoIncrement
= false;
185 xColProp
->getPropertyValue(rPropMap
.getNameByIndex(PROPERTY_ID_ISAUTOINCREMENT
)) >>= bIsAutoIncrement
;
187 const OUString sQuoteString
= xMetaData
->getIdentifierQuoteString();
188 OUStringBuffer
aSql(::dbtools::quoteName(sQuoteString
,::comphelper::getString(xColProp
->getPropertyValue(rPropMap
.getNameByIndex(PROPERTY_ID_NAME
)))));
190 // check if the user enter a specific string to create autoincrement values
191 OUString sAutoIncrementValue
;
192 Reference
<XPropertySetInfo
> xPropInfo
= xColProp
->getPropertySetInfo();
193 if ( xPropInfo
.is() && xPropInfo
->hasPropertyByName(rPropMap
.getNameByIndex(PROPERTY_ID_AUTOINCREMENTCREATION
)) )
194 xColProp
->getPropertyValue(rPropMap
.getNameByIndex(PROPERTY_ID_AUTOINCREMENTCREATION
)) >>= sAutoIncrementValue
;
196 aSql
.append(" " + createStandardTypePart(xColProp
, _xConnection
, _sCreatePattern
));
198 if(::comphelper::getINT32(xColProp
->getPropertyValue(rPropMap
.getNameByIndex(PROPERTY_ID_ISNULLABLE
))) == ColumnValue::NO_NULLS
)
199 aSql
.append(" NOT NULL");
201 if ( bIsAutoIncrement
&& !sAutoIncrementValue
.isEmpty())
203 aSql
.append(" " + sAutoIncrementValue
);
207 _pHelper
->addComment(xColProp
,aSql
);
209 return aSql
.makeStringAndClear();
213 OUString
createStandardCreateStatement(const Reference
< XPropertySet
>& descriptor
,const Reference
< XConnection
>& _xConnection
,ISQLStatementHelper
* _pHelper
,std::u16string_view _sCreatePattern
)
215 OUStringBuffer
aSql("CREATE TABLE ");
216 OUString sCatalog
,sSchema
,sTable
,sComposedName
;
218 Reference
<XDatabaseMetaData
> xMetaData
= _xConnection
->getMetaData();
219 ::dbtools::OPropertyMap
& rPropMap
= OMetaConnection::getPropMap();
221 descriptor
->getPropertyValue(rPropMap
.getNameByIndex(PROPERTY_ID_CATALOGNAME
)) >>= sCatalog
;
222 descriptor
->getPropertyValue(rPropMap
.getNameByIndex(PROPERTY_ID_SCHEMANAME
)) >>= sSchema
;
223 descriptor
->getPropertyValue(rPropMap
.getNameByIndex(PROPERTY_ID_NAME
)) >>= sTable
;
225 sComposedName
= ::dbtools::composeTableName( xMetaData
, sCatalog
, sSchema
, sTable
, true, ::dbtools::EComposeRule::InTableDefinitions
);
226 if ( sComposedName
.isEmpty() )
227 ::dbtools::throwFunctionSequenceException(_xConnection
);
229 aSql
.append(sComposedName
+ " (");
232 Reference
<XColumnsSupplier
> xColumnSup(descriptor
,UNO_QUERY
);
233 Reference
<XIndexAccess
> xColumns(xColumnSup
->getColumns(),UNO_QUERY
);
234 // check if there are columns
235 if(!xColumns
.is() || !xColumns
->getCount())
236 ::dbtools::throwFunctionSequenceException(_xConnection
);
238 Reference
< XPropertySet
> xColProp
;
240 sal_Int32 nCount
= xColumns
->getCount();
241 for(sal_Int32 i
=0;i
<nCount
;++i
)
243 if ( (xColumns
->getByIndex(i
) >>= xColProp
) && xColProp
.is() )
246 createStandardColumnPart(xColProp
,_xConnection
,_pHelper
,_sCreatePattern
)
250 return aSql
.makeStringAndClear();
254 OUString
generateColumnNames(const Reference
<XIndexAccess
>& _xColumns
,const Reference
<XDatabaseMetaData
>& _xMetaData
)
256 ::dbtools::OPropertyMap
& rPropMap
= OMetaConnection::getPropMap();
258 const OUString
sQuote(_xMetaData
->getIdentifierQuoteString());
259 OUStringBuffer
sSql( " (" );
260 Reference
< XPropertySet
> xColProp
;
262 sal_Int32 nColCount
= _xColumns
->getCount();
263 for(sal_Int32 i
=0;i
<nColCount
;++i
)
265 if ( (_xColumns
->getByIndex(i
) >>= xColProp
) && xColProp
.is() )
266 sSql
.append( ::dbtools::quoteName(sQuote
,::comphelper::getString(xColProp
->getPropertyValue(rPropMap
.getNameByIndex(PROPERTY_ID_NAME
)))) +
271 sSql
[sSql
.getLength()-1] = ')';
272 return sSql
.makeStringAndClear();
276 OUString
createStandardKeyStatement(const Reference
< XPropertySet
>& descriptor
,const Reference
< XConnection
>& _xConnection
)
278 Reference
<XDatabaseMetaData
> xMetaData
= _xConnection
->getMetaData();
279 ::dbtools::OPropertyMap
& rPropMap
= OMetaConnection::getPropMap();
283 Reference
<XKeysSupplier
> xKeySup(descriptor
,UNO_QUERY
);
284 Reference
<XIndexAccess
> xKeys
= xKeySup
->getKeys();
287 Reference
< XPropertySet
> xColProp
;
288 Reference
<XIndexAccess
> xColumns
;
289 Reference
<XColumnsSupplier
> xColumnSup
;
290 OUString sCatalog
,sSchema
,sTable
,sComposedName
;
292 for(sal_Int32 i
=0;i
<xKeys
->getCount();++i
)
294 if ( (xKeys
->getByIndex(i
) >>= xColProp
) && xColProp
.is() )
297 sal_Int32 nKeyType
= ::comphelper::getINT32(xColProp
->getPropertyValue(rPropMap
.getNameByIndex(PROPERTY_ID_TYPE
)));
299 if ( nKeyType
== KeyType::PRIMARY
)
302 ::dbtools::throwFunctionSequenceException(_xConnection
);
305 xColumnSup
.set(xColProp
,UNO_QUERY
);
306 xColumns
.set(xColumnSup
->getColumns(),UNO_QUERY
);
307 if(!xColumns
.is() || !xColumns
->getCount())
308 ::dbtools::throwFunctionSequenceException(_xConnection
);
310 aSql
.append(" PRIMARY KEY " + generateColumnNames(xColumns
,xMetaData
));
312 else if(nKeyType
== KeyType::UNIQUE
)
314 xColumnSup
.set(xColProp
,UNO_QUERY
);
315 xColumns
.set(xColumnSup
->getColumns(),UNO_QUERY
);
316 if(!xColumns
.is() || !xColumns
->getCount())
317 ::dbtools::throwFunctionSequenceException(_xConnection
);
319 aSql
.append(" UNIQUE " + generateColumnNames(xColumns
,xMetaData
));
321 else if(nKeyType
== KeyType::FOREIGN
)
323 sal_Int32 nDeleteRule
= getINT32(xColProp
->getPropertyValue(rPropMap
.getNameByIndex(PROPERTY_ID_DELETERULE
)));
325 xColumnSup
.set(xColProp
,UNO_QUERY
);
326 xColumns
.set(xColumnSup
->getColumns(),UNO_QUERY
);
327 if(!xColumns
.is() || !xColumns
->getCount())
328 ::dbtools::throwFunctionSequenceException(_xConnection
);
330 aSql
.append(" FOREIGN KEY ");
331 OUString sRefTable
= getString(xColProp
->getPropertyValue(rPropMap
.getNameByIndex(PROPERTY_ID_REFERENCEDTABLE
)));
332 ::dbtools::qualifiedNameComponents(xMetaData
,
337 ::dbtools::EComposeRule::InDataManipulation
);
338 sComposedName
= ::dbtools::composeTableName( xMetaData
, sCatalog
, sSchema
, sTable
, true, ::dbtools::EComposeRule::InTableDefinitions
);
341 if ( sComposedName
.isEmpty() )
342 ::dbtools::throwFunctionSequenceException(_xConnection
);
344 aSql
.append(generateColumnNames(xColumns
,xMetaData
));
348 case KeyRule::CASCADE
:
349 aSql
.append(" ON DELETE CASCADE ");
351 case KeyRule::RESTRICT
:
352 aSql
.append(" ON DELETE RESTRICT ");
354 case KeyRule::SET_NULL
:
355 aSql
.append(" ON DELETE SET NULL ");
357 case KeyRule::SET_DEFAULT
:
358 aSql
.append(" ON DELETE SET DEFAULT ");
368 if ( !aSql
.isEmpty() )
370 if ( aSql
[aSql
.getLength() - 1] == ',' )
371 aSql
[aSql
.getLength() - 1] = ')';
376 return aSql
.makeStringAndClear();
380 OUString
createSqlCreateTableStatement( const Reference
< XPropertySet
>& descriptor
,
381 const Reference
< XConnection
>& _xConnection
)
383 OUString aSql
= ::dbtools::createStandardCreateStatement(descriptor
,_xConnection
,nullptr,{});
384 const OUString sKeyStmt
= ::dbtools::createStandardKeyStatement(descriptor
,_xConnection
);
385 if ( !sKeyStmt
.isEmpty() )
389 if ( aSql
.endsWith(",") )
390 aSql
= aSql
.replaceAt(aSql
.getLength()-1, 1, u
")");
398 Reference
<XPropertySet
> lcl_createSDBCXColumn(const Reference
<XNameAccess
>& _xPrimaryKeyColumns
,
399 const Reference
<XConnection
>& _xConnection
,
400 const Any
& _aCatalog
,
401 const OUString
& _aSchema
,
402 const OUString
& _aTable
,
403 const OUString
& _rQueryName
,
404 const OUString
& _rName
,
407 bool _bIsAutoIncrement
,
409 sal_Int32 _nDataType
)
411 Reference
<XPropertySet
> xProp
;
412 Reference
<XDatabaseMetaData
> xMetaData
= _xConnection
->getMetaData();
413 Reference
< XResultSet
> xResult
= xMetaData
->getColumns(_aCatalog
, _aSchema
, _aTable
, _rQueryName
);
415 _aCatalog
>>= sCatalog
;
419 UStringMixEqual
aMixCompare(_bCase
);
420 Reference
< XRow
> xRow(xResult
,UNO_QUERY
);
421 while( xResult
->next() )
423 if ( aMixCompare(xRow
->getString(4),_rName
) )
425 sal_Int32 nField5
= xRow
->getInt(5);
426 OUString aField6
= xRow
->getString(6);
427 sal_Int32 nField7
= xRow
->getInt(7)
428 , nField9
= xRow
->getInt(9)
429 , nField11
= xRow
->getInt(11);
430 OUString sField12
= xRow
->getString(12),
431 sField13
= xRow
->getString(13);
432 ::comphelper::disposeComponent(xRow
);
434 bool bAutoIncrement
= _bIsAutoIncrement
435 ,bIsCurrency
= _bIsCurrency
;
436 if ( _bQueryForInfo
)
438 const OUString sQuote
= xMetaData
->getIdentifierQuoteString();
439 OUString sQuotedName
= ::dbtools::quoteName(sQuote
,_rName
);
440 OUString sComposedName
= composeTableNameForSelect(_xConnection
, getString( _aCatalog
), _aSchema
, _aTable
);
442 ColumnInformationMap
aInfo((UStringMixLess(_bCase
)));
443 collectColumnInformation(_xConnection
,sComposedName
,sQuotedName
,aInfo
);
444 ColumnInformationMap::const_iterator aIter
= aInfo
.begin();
445 if ( aIter
!= aInfo
.end() )
447 bAutoIncrement
= aIter
->second
.first
.first
;
448 bIsCurrency
= aIter
->second
.first
.second
;
449 if ( DataType::OTHER
== nField5
)
450 nField5
= aIter
->second
.second
;
453 else if ( DataType::OTHER
== nField5
)
454 nField5
= _nDataType
;
456 if ( nField11
!= ColumnValue::NO_NULLS
)
460 if ( _xPrimaryKeyColumns
.is() )
462 if ( _xPrimaryKeyColumns
->hasByName(_rName
) )
463 nField11
= ColumnValue::NO_NULLS
;
468 Reference
< XResultSet
> xPKeys
= xMetaData
->getPrimaryKeys( _aCatalog
, _aSchema
, _aTable
);
469 Reference
< XRow
> xPKeyRow( xPKeys
, UNO_QUERY_THROW
);
470 while( xPKeys
->next() ) // there can be only one primary key
472 OUString sKeyColumn
= xPKeyRow
->getString(4);
473 if ( aMixCompare(_rName
,sKeyColumn
) )
475 nField11
= ColumnValue::NO_NULLS
;
483 TOOLS_WARN_EXCEPTION( "connectivity.commontools", "lcl_createSDBCXColumn" );
487 xProp
= new connectivity::sdbcx::OColumn(_rName
,
511 Reference
< XModel
> lcl_getXModel(const Reference
< XInterface
>& _xIface
)
513 Reference
< XInterface
> xParent
= _xIface
;
514 Reference
< XModel
> xModel(xParent
,UNO_QUERY
);
515 while( xParent
.is() && !xModel
.is() )
517 Reference
<XChild
> xChild(xParent
,UNO_QUERY
);
518 xParent
.set(xChild
.is() ? xChild
->getParent() : Reference
< XInterface
>(),UNO_QUERY
);
519 xModel
.set(xParent
,UNO_QUERY
);
525 Reference
<XPropertySet
> createSDBCXColumn(const Reference
<XPropertySet
>& _xTable
,
526 const Reference
<XConnection
>& _xConnection
,
527 const OUString
& _rName
,
530 bool _bIsAutoIncrement
,
532 sal_Int32 _nDataType
)
534 Reference
<XPropertySet
> xProp
;
535 OSL_ENSURE(_xTable
.is(),"Table is NULL!");
539 ::dbtools::OPropertyMap
& rPropMap
= OMetaConnection::getPropMap();
540 Any aCatalog
= _xTable
->getPropertyValue(rPropMap
.getNameByIndex(PROPERTY_ID_CATALOGNAME
));
542 aCatalog
>>= sCatalog
;
544 OUString aSchema
, aTable
;
545 _xTable
->getPropertyValue(rPropMap
.getNameByIndex(PROPERTY_ID_SCHEMANAME
)) >>= aSchema
;
546 _xTable
->getPropertyValue(rPropMap
.getNameByIndex(PROPERTY_ID_NAME
)) >>= aTable
;
548 Reference
<XNameAccess
> xPrimaryKeyColumns
= getPrimaryKeyColumns_throw(_xTable
);
550 xProp
= lcl_createSDBCXColumn(xPrimaryKeyColumns
,_xConnection
,aCatalog
, aSchema
, aTable
, _rName
,_rName
,_bCase
,_bQueryForInfo
,_bIsAutoIncrement
,_bIsCurrency
,_nDataType
);
553 xProp
= lcl_createSDBCXColumn(xPrimaryKeyColumns
,_xConnection
,aCatalog
, aSchema
, aTable
, u
"%"_ustr
,_rName
,_bCase
,_bQueryForInfo
,_bIsAutoIncrement
,_bIsCurrency
,_nDataType
);
555 xProp
= new connectivity::sdbcx::OColumn(_rName
,
556 OUString(),OUString(),OUString(),
557 ColumnValue::NULLABLE_UNKNOWN
,
575 bool getBooleanDataSourceSetting( const Reference
< XConnection
>& _rxConnection
, const char* _pAsciiSettingName
)
577 return getBooleanDataSourceSetting(_rxConnection
, OUString::createFromAscii( _pAsciiSettingName
));
580 bool getBooleanDataSourceSetting( const Reference
< XConnection
>& _rxConnection
, const OUString
& rSettingName
)
582 bool bValue( false );
585 Reference
< XPropertySet
> xDataSourceProperties( findDataSource( _rxConnection
), UNO_QUERY
);
586 OSL_ENSURE( xDataSourceProperties
.is(), "::dbtools::getBooleanDataSourceSetting: somebody is using this with a non-SDB-level connection!" );
587 if ( xDataSourceProperties
.is() )
589 Reference
< XPropertySet
> xSettings(
590 xDataSourceProperties
->getPropertyValue(u
"Settings"_ustr
),
593 OSL_VERIFY( xSettings
->getPropertyValue( rSettingName
) >>= bValue
);
596 catch( const Exception
& )
598 DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
603 bool getDataSourceSetting( const Reference
< XInterface
>& _xChild
, const OUString
& _sAsciiSettingsName
,
604 Any
& /* [out] */ _rSettingsValue
)
606 bool bIsPresent
= false;
609 const Reference
< XPropertySet
> xDataSourceProperties( findDataSource( _xChild
), UNO_QUERY
);
610 if ( !xDataSourceProperties
.is() )
613 const Reference
< XPropertySet
> xSettings(
614 xDataSourceProperties
->getPropertyValue(u
"Settings"_ustr
),
618 _rSettingsValue
= xSettings
->getPropertyValue( _sAsciiSettingsName
);
621 catch( const Exception
& )
628 bool getDataSourceSetting( const Reference
< XInterface
>& _rxDataSource
, const char* _pAsciiSettingsName
,
629 Any
& /* [out] */ _rSettingsValue
)
631 OUString sAsciiSettingsName
= OUString::createFromAscii(_pAsciiSettingsName
);
632 return getDataSourceSetting( _rxDataSource
, sAsciiSettingsName
,_rSettingsValue
);
635 bool isDataSourcePropertyEnabled(const Reference
<XInterface
>& _xProp
, const OUString
& _sProperty
, bool _bDefault
)
637 bool bEnabled
= _bDefault
;
640 Reference
< XPropertySet
> xProp(findDataSource(_xProp
),UNO_QUERY
);
643 Sequence
< PropertyValue
> aInfo
;
644 xProp
->getPropertyValue(u
"Info"_ustr
) >>= aInfo
;
645 const PropertyValue
* pValue
=std::find_if(std::cbegin(aInfo
),
647 [&_sProperty
](const PropertyValue
& lhs
)
648 { return lhs
.Name
== _sProperty
; });
649 if ( pValue
!= std::cend(aInfo
) )
650 pValue
->Value
>>= bEnabled
;
655 DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
660 Reference
< XTablesSupplier
> getDataDefinitionByURLAndConnection(
661 const OUString
& _rsUrl
,
662 const Reference
< XConnection
>& _xConnection
,
663 const Reference
< XComponentContext
>& _rxContext
)
665 Reference
< XTablesSupplier
> xTablesSup
;
668 Reference
< XDriverManager2
> xManager
= DriverManager::create( _rxContext
);
669 Reference
< XDataDefinitionSupplier
> xSupp( xManager
->getDriverByURL( _rsUrl
), UNO_QUERY
);
673 xTablesSup
= xSupp
->getDataDefinitionByConnection( _xConnection
);
674 OSL_ENSURE(xTablesSup
.is(),"No table supplier!");
677 catch( const Exception
& )
679 DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
685 sal_Int32
getTablePrivileges(const Reference
< XDatabaseMetaData
>& _xMetaData
,
686 const OUString
& _sCatalog
,
687 const OUString
& _sSchema
,
688 const OUString
& _sTable
)
690 OSL_ENSURE(_xMetaData
.is(),"Invalid metadata!");
691 sal_Int32 nPrivileges
= 0;
695 if(!_sCatalog
.isEmpty())
697 Reference
< XResultSet
> xPrivileges
= _xMetaData
->getTablePrivileges(aVal
, _sSchema
, _sTable
);
698 Reference
< XRow
> xCurrentRow(xPrivileges
, UNO_QUERY
);
700 const OUString sUserWorkingFor
= _xMetaData
->getUserName();
701 static const char sSELECT
[] = "SELECT";
702 static const char sINSERT
[] = "INSERT";
703 static const char sUPDATE
[] = "UPDATE";
704 static const char sDELETE
[] = "DELETE";
705 static const char sREAD
[] = "READ";
706 static const char sCREATE
[] = "CREATE";
707 static const char sALTER
[] = "ALTER";
708 static const char sREFERENCE
[] = "REFERENCE";
709 static const char sDROP
[] = "DROP";
711 if ( xCurrentRow
.is() )
713 // after creation the set is positioned before the first record, per definition
714 OUString sPrivilege
, sGrantee
;
715 while ( xPrivileges
->next() )
717 sGrantee
= xCurrentRow
->getString(5);
718 sPrivilege
= xCurrentRow
->getString(6);
720 if (!sUserWorkingFor
.equalsIgnoreAsciiCase(sGrantee
))
723 if (sPrivilege
.equalsIgnoreAsciiCase(sSELECT
))
724 nPrivileges
|= Privilege::SELECT
;
725 else if (sPrivilege
.equalsIgnoreAsciiCase(sINSERT
))
726 nPrivileges
|= Privilege::INSERT
;
727 else if (sPrivilege
.equalsIgnoreAsciiCase(sUPDATE
))
728 nPrivileges
|= Privilege::UPDATE
;
729 else if (sPrivilege
.equalsIgnoreAsciiCase(sDELETE
))
730 nPrivileges
|= Privilege::DELETE
;
731 else if (sPrivilege
.equalsIgnoreAsciiCase(sREAD
))
732 nPrivileges
|= Privilege::READ
;
733 else if (sPrivilege
.equalsIgnoreAsciiCase(sCREATE
))
734 nPrivileges
|= Privilege::CREATE
;
735 else if (sPrivilege
.equalsIgnoreAsciiCase(sALTER
))
736 nPrivileges
|= Privilege::ALTER
;
737 else if (sPrivilege
.equalsIgnoreAsciiCase(sREFERENCE
))
738 nPrivileges
|= Privilege::REFERENCE
;
739 else if (sPrivilege
.equalsIgnoreAsciiCase(sDROP
))
740 nPrivileges
|= Privilege::DROP
;
743 disposeComponent(xPrivileges
);
745 // Some drivers put a table privilege as soon as any column has the privilege,
746 // some drivers only if all columns have the privilege.
747 // To unify the situation, collect column privileges here, too.
748 Reference
< XResultSet
> xColumnPrivileges
= _xMetaData
->getColumnPrivileges(aVal
, _sSchema
, _sTable
, u
"%"_ustr
);
749 Reference
< XRow
> xColumnCurrentRow(xColumnPrivileges
, UNO_QUERY
);
750 if ( xColumnCurrentRow
.is() )
752 // after creation the set is positioned before the first record, per definition
753 OUString sPrivilege
, sGrantee
;
754 while ( xColumnPrivileges
->next() )
756 sGrantee
= xColumnCurrentRow
->getString(6);
757 sPrivilege
= xColumnCurrentRow
->getString(7);
759 if (!sUserWorkingFor
.equalsIgnoreAsciiCase(sGrantee
))
762 if (sPrivilege
.equalsIgnoreAsciiCase(sSELECT
))
763 nPrivileges
|= Privilege::SELECT
;
764 else if (sPrivilege
.equalsIgnoreAsciiCase(sINSERT
))
765 nPrivileges
|= Privilege::INSERT
;
766 else if (sPrivilege
.equalsIgnoreAsciiCase(sUPDATE
))
767 nPrivileges
|= Privilege::UPDATE
;
768 else if (sPrivilege
.equalsIgnoreAsciiCase(sDELETE
))
769 nPrivileges
|= Privilege::DELETE
;
770 else if (sPrivilege
.equalsIgnoreAsciiCase(sREAD
))
771 nPrivileges
|= Privilege::READ
;
772 else if (sPrivilege
.equalsIgnoreAsciiCase(sCREATE
))
773 nPrivileges
|= Privilege::CREATE
;
774 else if (sPrivilege
.equalsIgnoreAsciiCase(sALTER
))
775 nPrivileges
|= Privilege::ALTER
;
776 else if (sPrivilege
.equalsIgnoreAsciiCase(sREFERENCE
))
777 nPrivileges
|= Privilege::REFERENCE
;
778 else if (sPrivilege
.equalsIgnoreAsciiCase(sDROP
))
779 nPrivileges
|= Privilege::DROP
;
782 disposeComponent(xColumnPrivileges
);
784 catch(const SQLException
& e
)
786 // some drivers don't support any privileges so we assume that we are allowed to do all we want :-)
787 if(e
.SQLState
== "IM001")
788 nPrivileges
|= Privilege::DROP
|
789 Privilege::REFERENCE
|
798 OSL_FAIL("Could not collect the privileges !");
803 // we need some more information about the column
804 void collectColumnInformation(const Reference
< XConnection
>& _xConnection
,
805 std::u16string_view _sComposedName
,
806 std::u16string_view _rName
,
807 ColumnInformationMap
& _rInfo
)
809 OUString sSelect
= OUString::Concat("SELECT ") + _rName
+
810 " FROM " + _sComposedName
+
815 ::utl::SharedUNOComponent
< XStatement
> xStmt( _xConnection
->createStatement() );
816 Reference
< XPropertySet
> xStatementProps( xStmt
, UNO_QUERY_THROW
);
817 xStatementProps
->setPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_ESCAPEPROCESSING
), Any( false ) );
818 Reference
< XResultSet
> xResult( xStmt
->executeQuery( sSelect
), UNO_SET_THROW
);
819 Reference
< XResultSetMetaDataSupplier
> xSuppMeta( xResult
, UNO_QUERY_THROW
);
820 Reference
< XResultSetMetaData
> xMeta( xSuppMeta
->getMetaData(), UNO_SET_THROW
);
822 sal_Int32 nCount
= xMeta
->getColumnCount();
823 OSL_ENSURE( nCount
!= 0, "::dbtools::collectColumnInformation: result set has empty (column-less) meta data!" );
824 for (sal_Int32 i
=1; i
<= nCount
; ++i
)
826 _rInfo
.emplace( xMeta
->getColumnName(i
),
827 ColumnInformation(TBoolPair(xMeta
->isAutoIncrement(i
),xMeta
->isCurrency(i
)),xMeta
->getColumnType(i
)));
830 catch( const Exception
& )
832 DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
837 bool isEmbeddedInDatabase( const Reference
< XInterface
>& _rxComponent
, Reference
< XConnection
>& _rxActualConnection
)
839 bool bIsEmbedded
= false;
842 Reference
< XModel
> xModel
= lcl_getXModel( _rxComponent
);
846 for (auto& arg
: xModel
->getArgs())
848 if (arg
.Name
== "ComponentData")
850 Sequence
<PropertyValue
> aDocumentContext
;
851 arg
.Value
>>= aDocumentContext
;
852 for (auto& item
: aDocumentContext
)
854 if (item
.Name
== "ActiveConnection" && (item
.Value
>>= _rxActualConnection
))
874 OUString
lcl_getEncodingName( rtl_TextEncoding _eEncoding
)
876 OUString sEncodingName
;
878 OCharsetMap aCharsets
;
879 OCharsetMap::CharsetIterator aEncodingPos
= aCharsets
.find( _eEncoding
);
880 OSL_ENSURE( aEncodingPos
!= aCharsets
.end(), "lcl_getEncodingName: *which* encoding?" );
881 if ( aEncodingPos
!= aCharsets
.end() )
882 sEncodingName
= (*aEncodingPos
).getIanaName();
884 return sEncodingName
;
889 sal_Int32
DBTypeConversion::convertUnicodeString( const OUString
& _rSource
, OString
& _rDest
, rtl_TextEncoding _eEncoding
)
891 if ( !rtl_convertUStringToString( &_rDest
.pData
, _rSource
.getStr(), _rSource
.getLength(),
893 RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
|
894 RTL_UNICODETOTEXT_FLAGS_UNDEFINED_REPLACE
|
895 RTL_UNICODETOTEXT_FLAGS_PRIVATE_MAPTO0
)
898 SharedResources aResources
;
899 OUString sMessage
= aResources
.getResourceStringWithSubstitution( STR_CANNOT_CONVERT_STRING
,
900 "$string$", _rSource
,
901 "$charset$", lcl_getEncodingName( _eEncoding
)
913 return _rDest
.getLength();
917 sal_Int32
DBTypeConversion::convertUnicodeStringToLength( const OUString
& _rSource
, OString
& _rDest
,
918 sal_Int32 _nMaxLen
, rtl_TextEncoding _eEncoding
)
920 sal_Int32 nLen
= convertUnicodeString( _rSource
, _rDest
, _eEncoding
);
921 if ( nLen
> _nMaxLen
)
923 SharedResources aResources
;
924 OUString sMessage
= aResources
.getResourceStringWithSubstitution( STR_STRING_LENGTH_EXCEEDED
,
925 "$string$", _rSource
,
926 "$maxlen$", OUString::number( _nMaxLen
),
927 "$charset$", lcl_getEncodingName( _eEncoding
)
942 OUString
getDefaultReportEngineServiceName(const Reference
< XComponentContext
>& _rxORB
)
944 ::utl::OConfigurationTreeRoot aReportEngines
= ::utl::OConfigurationTreeRoot::createWithComponentContext(
945 _rxORB
, u
"org.openoffice.Office.DataAccess/ReportEngines"_ustr
, -1, ::utl::OConfigurationTreeRoot::CM_READONLY
);
947 if ( aReportEngines
.isValid() )
949 OUString sDefaultReportEngineName
;
950 aReportEngines
.getNodeValue(u
"DefaultReportEngine"_ustr
) >>= sDefaultReportEngineName
;
951 if ( !sDefaultReportEngineName
.isEmpty() )
953 ::utl::OConfigurationNode aReportEngineNames
= aReportEngines
.openNode(u
"ReportEngineNames"_ustr
);
954 if ( aReportEngineNames
.isValid() )
956 ::utl::OConfigurationNode aReportEngine
= aReportEngineNames
.openNode(sDefaultReportEngineName
);
957 if ( aReportEngine
.isValid() )
960 aReportEngine
.getNodeValue(u
"ServiceName"_ustr
) >>= sRet
;
966 return u
"org.libreoffice.report.pentaho.SOReportJobFactory"_ustr
;
969 return u
"org.libreoffice.report.pentaho.SOReportJobFactory"_ustr
;
973 bool isAggregateColumn(const Reference
< XSingleSelectQueryComposer
> &_xParser
, const Reference
< XPropertySet
> &_xField
)
976 _xField
->getPropertyValue(u
"Name"_ustr
) >>= sName
;
977 Reference
< XColumnsSupplier
> xColumnsSupplier(_xParser
, UNO_QUERY
);
978 Reference
< css::container::XNameAccess
> xCols
;
979 if (xColumnsSupplier
.is())
980 xCols
= xColumnsSupplier
->getColumns();
982 return isAggregateColumn(xCols
, sName
);
985 bool isAggregateColumn(const Reference
< XNameAccess
> &_xColumns
, const OUString
&_sName
)
987 if ( _xColumns
.is() && _xColumns
->hasByName(_sName
) )
989 Reference
<XPropertySet
> xProp(_xColumns
->getByName(_sName
),UNO_QUERY
);
991 return isAggregateColumn( xProp
);
996 bool isAggregateColumn( const Reference
< XPropertySet
> &_xColumn
)
1000 static constexpr OUString sAgg
= u
"AggregateFunction"_ustr
;
1001 if ( _xColumn
->getPropertySetInfo()->hasPropertyByName(sAgg
) )
1002 _xColumn
->getPropertyValue(sAgg
) >>= bAgg
;
1008 } // namespace dbtools
1011 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */