cid#1636690 Dereference after null check
[LibreOffice.git] / connectivity / source / commontools / dbtools2.cxx
blobc85a5440238fceba0ca32215ea75387e1481321a
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
50 #include <algorithm>
51 #include <string_view>
53 namespace dbtools
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();
74 OUString sTypeName;
75 sal_Int32 nDataType = 0;
76 sal_Int32 nPrecision = 0;
77 sal_Int32 nScale = 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;
86 OUStringBuffer aSql;
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();
98 if(xRes.is())
100 Reference<XRow> xRow(xRes,UNO_QUERY);
101 while(xRes->next())
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())
114 bUseLiteral = true;
115 break;
121 if ( !sAutoIncrementValue.isEmpty() )
123 sal_Int32 nIndex = sTypeName.indexOf(sAutoIncrementValue);
124 if (nIndex != -1)
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);
142 else
143 aSql.append(sTypeName.subView(0, nParenPos));
144 aSql.append("(");
146 if ( nPrecision > 0 && !bTimed )
148 aSql.append(nPrecision);
149 if ( (nScale > 0) || (!_sCreatePattern.empty() && sCreateParams.indexOf(_sCreatePattern) != -1) )
150 aSql.append(",");
152 if ( (nScale > 0) || ( !_sCreatePattern.empty() && sCreateParams.indexOf(_sCreatePattern) != -1 ) || bTimed )
153 aSql.append(nScale);
155 if ( nParenPos == -1 )
156 aSql.append(")");
157 else
159 if ( bTimed )
160 aSql.append(")");
161 else
162 nParenPos = sTypeName.indexOf(')',nParenPos);
163 aSql.append(sTypeName.subView(nParenPos));
166 else
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);
206 if ( _pHelper )
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 + " (");
231 // columns
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() )
245 aSql.append(
246 createStandardColumnPart(xColProp,_xConnection,_pHelper,_sCreatePattern)
247 + ",");
250 return aSql.makeStringAndClear();
252 namespace
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)))) +
267 ",");
270 if ( nColCount )
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();
281 OUStringBuffer aSql;
282 // keys
283 Reference<XKeysSupplier> xKeySup(descriptor,UNO_QUERY);
284 Reference<XIndexAccess> xKeys = xKeySup->getKeys();
285 if ( xKeys.is() )
287 Reference< XPropertySet > xColProp;
288 Reference<XIndexAccess> xColumns;
289 Reference<XColumnsSupplier> xColumnSup;
290 OUString sCatalog,sSchema,sTable,sComposedName;
291 bool bPKey = false;
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 )
301 if(bPKey)
302 ::dbtools::throwFunctionSequenceException(_xConnection);
304 bPKey = true;
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,
333 sRefTable,
334 sCatalog,
335 sSchema,
336 sTable,
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));
346 switch(nDeleteRule)
348 case KeyRule::CASCADE:
349 aSql.append(" ON DELETE CASCADE ");
350 break;
351 case KeyRule::RESTRICT:
352 aSql.append(" ON DELETE RESTRICT ");
353 break;
354 case KeyRule::SET_NULL:
355 aSql.append(" ON DELETE SET NULL ");
356 break;
357 case KeyRule::SET_DEFAULT:
358 aSql.append(" ON DELETE SET DEFAULT ");
359 break;
360 default:
368 if ( !aSql.isEmpty() )
370 if ( aSql[aSql.getLength() - 1] == ',' )
371 aSql[aSql.getLength() - 1] = ')';
372 else
373 aSql.append(")");
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() )
386 aSql += sKeyStmt;
387 else
389 if ( aSql.endsWith(",") )
390 aSql = aSql.replaceAt(aSql.getLength()-1, 1, u")");
391 else
392 aSql += ")";
394 return aSql;
396 namespace
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,
405 bool _bCase,
406 bool _bQueryForInfo,
407 bool _bIsAutoIncrement,
408 bool _bIsCurrency,
409 sal_Int32 _nDataType)
411 Reference<XPropertySet> xProp;
412 Reference<XDatabaseMetaData> xMetaData = _xConnection->getMetaData();
413 Reference< XResultSet > xResult = xMetaData->getColumns(_aCatalog, _aSchema, _aTable, _rQueryName);
414 OUString sCatalog;
415 _aCatalog >>= sCatalog;
417 if ( xResult.is() )
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;
466 else
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;
476 break;
481 catch(SQLException&)
483 TOOLS_WARN_EXCEPTION( "connectivity.commontools", "lcl_createSDBCXColumn" );
487 xProp = new connectivity::sdbcx::OColumn(_rName,
488 aField6,
489 sField13,
490 sField12,
491 nField11,
492 nField7,
493 nField9,
494 nField5,
495 bAutoIncrement,
496 false,
497 bIsCurrency,
498 _bCase,
499 sCatalog,
500 _aSchema,
501 _aTable);
503 break;
508 return xProp;
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);
521 return xModel;
525 Reference<XPropertySet> createSDBCXColumn(const Reference<XPropertySet>& _xTable,
526 const Reference<XConnection>& _xConnection,
527 const OUString& _rName,
528 bool _bCase,
529 bool _bQueryForInfo,
530 bool _bIsAutoIncrement,
531 bool _bIsCurrency,
532 sal_Int32 _nDataType)
534 Reference<XPropertySet> xProp;
535 OSL_ENSURE(_xTable.is(),"Table is NULL!");
536 if ( !_xTable.is() )
537 return xProp;
539 ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap();
540 Any aCatalog = _xTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_CATALOGNAME));
541 OUString sCatalog;
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);
551 if ( !xProp.is() )
553 xProp = lcl_createSDBCXColumn(xPrimaryKeyColumns,_xConnection,aCatalog, aSchema, aTable, u"%"_ustr,_rName,_bCase,_bQueryForInfo,_bIsAutoIncrement,_bIsCurrency,_nDataType);
554 if ( !xProp.is() )
555 xProp = new connectivity::sdbcx::OColumn(_rName,
556 OUString(),OUString(),OUString(),
557 ColumnValue::NULLABLE_UNKNOWN,
560 DataType::VARCHAR,
561 _bIsAutoIncrement,
562 false,
563 _bIsCurrency,
564 _bCase,
565 sCatalog,
566 aSchema,
567 aTable);
571 return xProp;
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),
591 UNO_QUERY_THROW
593 OSL_VERIFY( xSettings->getPropertyValue( rSettingName ) >>= bValue );
596 catch( const Exception& )
598 DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
600 return bValue;
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() )
611 return false;
613 const Reference< XPropertySet > xSettings(
614 xDataSourceProperties->getPropertyValue(u"Settings"_ustr),
615 UNO_QUERY_THROW
618 _rSettingsValue = xSettings->getPropertyValue( _sAsciiSettingsName );
619 bIsPresent = true;
621 catch( const Exception& )
623 bIsPresent = false;
625 return bIsPresent;
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);
641 if ( xProp.is() )
643 Sequence< PropertyValue > aInfo;
644 xProp->getPropertyValue(u"Info"_ustr) >>= aInfo;
645 const PropertyValue* pValue =std::find_if(std::cbegin(aInfo),
646 std::cend(aInfo),
647 [&_sProperty](const PropertyValue& lhs)
648 { return lhs.Name == _sProperty; });
649 if ( pValue != std::cend(aInfo) )
650 pValue->Value >>= bEnabled;
653 catch(SQLException&)
655 DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
657 return bEnabled;
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 );
671 if ( xSupp.is() )
673 xTablesSup = xSupp->getDataDefinitionByConnection( _xConnection );
674 OSL_ENSURE(xTablesSup.is(),"No table supplier!");
677 catch( const Exception& )
679 DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
681 return xTablesSup;
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;
694 Any aVal;
695 if(!_sCatalog.isEmpty())
696 aVal <<= _sCatalog;
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))
721 continue;
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))
760 continue;
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 |
790 Privilege::ALTER |
791 Privilege::CREATE |
792 Privilege::READ |
793 Privilege::DELETE |
794 Privilege::UPDATE |
795 Privilege::INSERT |
796 Privilege::SELECT;
797 else
798 OSL_FAIL("Could not collect the privileges !");
800 return nPrivileges;
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 +
811 " WHERE 0 = 1";
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 );
844 if ( xModel.is() )
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))
856 bIsEmbedded = true;
857 break;
860 break;
865 catch(Exception&)
867 // not interested in
869 return bIsEmbedded;
872 namespace
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(),
892 _eEncoding,
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 )
904 throw SQLException(
905 sMessage,
906 nullptr,
907 u"22018"_ustr,
908 22018,
909 Any()
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 )
930 throw SQLException(
931 sMessage,
932 nullptr,
933 u"22001"_ustr,
934 22001,
935 Any()
939 return nLen;
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() )
959 OUString sRet;
960 aReportEngine.getNodeValue(u"ServiceName"_ustr) >>= sRet;
961 return sRet;
965 else
966 return u"org.libreoffice.report.pentaho.SOReportJobFactory"_ustr;
968 else
969 return u"org.libreoffice.report.pentaho.SOReportJobFactory"_ustr;
970 return OUString();
973 bool isAggregateColumn(const Reference< XSingleSelectQueryComposer > &_xParser, const Reference< XPropertySet > &_xField)
975 OUString sName;
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);
990 assert(xProp.is());
991 return isAggregateColumn( xProp );
993 return false;
996 bool isAggregateColumn( const Reference< XPropertySet > &_xColumn )
998 bool bAgg(false);
1000 static constexpr OUString sAgg = u"AggregateFunction"_ustr;
1001 if ( _xColumn->getPropertySetInfo()->hasPropertyByName(sAgg) )
1002 _xColumn->getPropertyValue(sAgg) >>= bAgg;
1004 return bAgg;
1008 } // namespace dbtools
1011 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */