xref: /core/dbaccess/source/ui/misc/UITools.cxx (revision 51b5b930)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <UITools.hxx>
21 #include <sfx2/docfilt.hxx>
22 #include <callbacks.hxx>
23 #include <core_resource.hxx>
24 #include <stringconstants.hxx>
25 #include <dlgsave.hxx>
26 #include <dbtreelistbox.hxx>
27 #include <defaultobjectnamecheck.hxx>
28 #include <comphelper/extract.hxx>
29 #include <com/sun/star/sdb/DatabaseContext.hpp>
30 #include <com/sun/star/sdb/XSingleSelectQueryAnalyzer.hpp>
31 #include <com/sun/star/sdb/XCompletedConnection.hpp>
32 #include <com/sun/star/sdbc/XDataSource.hpp>
33 #include <com/sun/star/sdb/SQLContext.hpp>
34 #include <com/sun/star/sdbcx/XKeysSupplier.hpp>
35 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
36 #include <com/sun/star/sdbcx/XViewsSupplier.hpp>
37 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
38 #include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp>
39 #include <com/sun/star/sdbcx/XAppend.hpp>
40 #include <com/sun/star/sdbc/XRow.hpp>
41 #include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
42 #include <com/sun/star/sdbc/XResultSetMetaData.hpp>
43 #include <com/sun/star/sdbc/ColumnValue.hpp>
44 #include <com/sun/star/task/InteractionHandler.hpp>
45 #include <com/sun/star/ucb/XContent.hpp>
46 #include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
47 #include <com/sun/star/beans/PropertyValue.hpp>
48 #include <com/sun/star/container/XIndexAccess.hpp>
49 #include <com/sun/star/container/XNameContainer.hpp>
50 #include <com/sun/star/ucb/InteractiveIOException.hpp>
51 #include <com/sun/star/sdb/XDocumentDataSource.hpp>
52 #include <com/sun/star/ucb/IOErrorCode.hpp>
53 #include <toolkit/helper/vclunohelper.hxx>
54 #include <toolkit/awt/vclxwindow.hxx>
55 #include <vcl/stdtext.hxx>
56 #include <vcl/settings.hxx>
57 #include <vcl/svapp.hxx>
58 #include <com/sun/star/beans/XPropertySetInfo.hpp>
59 #include <com/sun/star/beans/XPropertySet.hpp>
60 #include <com/sun/star/container/XNameAccess.hpp>
61 #include <com/sun/star/container/XContainer.hpp>
62 #include <com/sun/star/container/XHierarchicalNameContainer.hpp>
63 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
64 #include <com/sun/star/awt/TextAlign.hpp>
65 #include <com/sun/star/awt/FontDescriptor.hpp>
66 #include <com/sun/star/awt/FontWeight.hpp>
67 #include <com/sun/star/awt/FontRelief.hpp>
68 #include <com/sun/star/awt/FontWidth.hpp>
69 #include <com/sun/star/awt/XWindow.hpp>
70 #include <TypeInfo.hxx>
71 #include <FieldDescriptions.hxx>
72 #include <comphelper/stl_types.hxx>
73 #include <comphelper/types.hxx>
74 #include <comphelper/propertysequence.hxx>
75 
76 #include <svx/svxids.hrc>
77 
78 #include <sal/log.hxx>
79 #include <svl/itempool.hxx>
80 #include <helpids.h>
81 #include <svl/itemset.hxx>
82 #include <sbagrid.hrc>
83 #include <svl/rngitem.hxx>
84 #include <svl/intitem.hxx>
85 #include <svx/algitem.hxx>
86 #include <svx/numinf.hxx>
87 #include <svl/zforlist.hxx>
88 #include <dlgattr.hxx>
89 #include <com/sun/star/container/XChild.hpp>
90 #include <com/sun/star/util/NumberFormatter.hpp>
91 #include <com/sun/star/util/XNumberFormatsSupplier.hpp>
92 #include <com/sun/star/util/XNumberFormatter.hpp>
93 #include <strings.hrc>
94 #include <sqlmessage.hxx>
95 #include <com/sun/star/util/NumberFormat.hpp>
96 #include <com/sun/star/util/URL.hpp>
97 #include <vcl/toolbox.hxx>
98 #include <dlgsize.hxx>
99 #include <svtools/editbrowsebox.hxx>
100 #include <unotools/configmgr.hxx>
101 #include <svtools/helpopt.hxx>
102 #include <ucbhelper/content.hxx>
103 #include <tools/urlobj.hxx>
104 #include <tools/diagnose_ex.h>
105 #include <svl/numuno.hxx>
106 #include <unotools/pathoptions.hxx>
107 #include <svl/filenotation.hxx>
108 #include <connectivity/FValue.hxx>
109 
110 #include <editeng/justifyitem.hxx>
111 #include <memory>
112 
113 namespace dbaui
114 {
115 using namespace ::dbtools;
116 using namespace ::comphelper;
117 using namespace ::com::sun::star;
118 using namespace ::com::sun::star::uno;
119 using namespace ::com::sun::star::task;
120 using namespace ::com::sun::star::sdbcx;
121 using namespace ::com::sun::star::sdbc;
122 using namespace ::com::sun::star::sdb;
123 using namespace ::com::sun::star::util;
124 using namespace ::com::sun::star::ucb;
125 using namespace ::com::sun::star::beans;
126 using namespace ::com::sun::star::container;
127 using namespace ::com::sun::star::lang;
128 using namespace ::com::sun::star::ui::dialogs;
129 using namespace ::svt;
130 using ::com::sun::star::ucb::InteractiveIOException;
131 using ::com::sun::star::ucb::IOErrorCode_NO_FILE;
132 using ::com::sun::star::ucb::IOErrorCode_NOT_EXISTING;
133 
134 SQLExceptionInfo createConnection(  const OUString& _rsDataSourceName,
135                                      const Reference< css::container::XNameAccess >& _xDatabaseContext,
136                                     const Reference< css::uno::XComponentContext >& _rxContext,
137                                     Reference< css::lang::XEventListener> const & _rEvtLst,
138                                     Reference< css::sdbc::XConnection>& _rOUTConnection )
139 {
140     Reference<XPropertySet> xProp;
141     try
142     {
143         xProp.set(_xDatabaseContext->getByName(_rsDataSourceName),UNO_QUERY);
144     }
145     catch(const Exception&)
146     {
147     }
148 
149     return createConnection(xProp,_rxContext,_rEvtLst,_rOUTConnection);
150 }
151 
152 SQLExceptionInfo createConnection(  const Reference< css::beans::XPropertySet>& _xDataSource,
153                                     const Reference< css::uno::XComponentContext >& _rxContext,
154                                     Reference< css::lang::XEventListener> const & _rEvtLst,
155                                     Reference< css::sdbc::XConnection>& _rOUTConnection )
156 {
157     SQLExceptionInfo aInfo;
158     if ( !_xDataSource.is() )
159     {
160         SAL_WARN("dbaccess.ui", "createConnection: could not retrieve the data source!");
161         return aInfo;
162     }
163 
164     OUString sPwd, sUser;
165     bool bPwdReq = false;
166     try
167     {
168         _xDataSource->getPropertyValue(PROPERTY_PASSWORD) >>= sPwd;
169         bPwdReq = ::cppu::any2bool(_xDataSource->getPropertyValue(PROPERTY_ISPASSWORDREQUIRED));
170         _xDataSource->getPropertyValue(PROPERTY_USER) >>= sUser;
171     }
172     catch(const Exception&)
173     {
174         SAL_WARN("dbaccess.ui", "createConnection: error while retrieving data source properties!");
175     }
176 
177     try
178     {
179         if(bPwdReq && sPwd.isEmpty())
180         {   // password required, but empty -> connect using an interaction handler
181             Reference<XCompletedConnection> xConnectionCompletion(_xDataSource, UNO_QUERY);
182             if (!xConnectionCompletion.is())
183             {
184                 SAL_WARN("dbaccess.ui", "createConnection: missing an interface ... need an error message here!");
185             }
186             else
187             {   // instantiate the default SDB interaction handler
188                 Reference< XInteractionHandler > xHandler = InteractionHandler::createWithParent(_rxContext, nullptr);
189                 _rOUTConnection = xConnectionCompletion->connectWithCompletion(xHandler);
190             }
191         }
192         else
193         {
194             Reference<XDataSource> xDataSource(_xDataSource,UNO_QUERY);
195             _rOUTConnection = xDataSource->getConnection(sUser, sPwd);
196         }
197         // be notified when connection is in disposing
198         Reference< XComponent >  xComponent(_rOUTConnection, UNO_QUERY);
199         if (xComponent.is() && _rEvtLst.is())
200             xComponent->addEventListener(_rEvtLst);
201     }
202     catch(const SQLContext& e) { aInfo = SQLExceptionInfo(e); }
203     catch(const SQLWarning& e) { aInfo = SQLExceptionInfo(e); }
204     catch(const SQLException& e) { aInfo = SQLExceptionInfo(e); }
205     catch(const Exception&) {
206         TOOLS_WARN_EXCEPTION("dbaccess.ui", "SbaTableQueryBrowser::OnExpandEntry: could not connect - unknown exception");
207     }
208 
209     return aInfo;
210 }
211 
212 Reference< XDataSource > getDataSourceByName( const OUString& _rDataSourceName,
213     weld::Window* _pErrorMessageParent, const Reference< XComponentContext >& _rxContext, ::dbtools::SQLExceptionInfo* _pErrorInfo )
214 {
215     Reference< XDatabaseContext > xDatabaseContext = DatabaseContext::create(_rxContext);
216 
217     Reference< XDataSource > xDatasource;
218     Any aError;
219     SQLExceptionInfo aSQLError;
220     try
221     {
222         xDatabaseContext->getByName( _rDataSourceName ) >>= xDatasource;
223     }
224     catch(const WrappedTargetException& e)
225     {
226         InteractiveIOException aIOException;
227         if  (   ( e.TargetException >>= aIOException )
228             &&  (   ( aIOException.Code == IOErrorCode_NO_FILE )
229                 ||  ( aIOException.Code == IOErrorCode_NOT_EXISTING )
230                 )
231             )
232         {
233             OUString sErrorMessage( DBA_RES( STR_FILE_DOES_NOT_EXIST ) );
234             OFileNotation aTransformer( e.Message );
235             sErrorMessage = sErrorMessage.replaceFirst( "$file$", aTransformer.get( OFileNotation::N_SYSTEM ) );
236             aSQLError = SQLExceptionInfo( sErrorMessage ).get();
237         }
238         else
239         {
240             aSQLError = SQLExceptionInfo( e.TargetException );
241             if ( !aSQLError.isValid() )
242                 aError = e.TargetException;
243         }
244     }
245     catch( const Exception& )
246     {
247         DBG_UNHANDLED_EXCEPTION("dbaccess");
248     }
249 
250     if ( xDatasource.is() )
251         return xDatasource;
252 
253     if ( aSQLError.isValid() )
254     {
255         if ( _pErrorInfo )
256         {
257             *_pErrorInfo = aSQLError;
258         }
259         else
260         {
261             showError( aSQLError, _pErrorMessageParent ? _pErrorMessageParent->GetXWindow() : nullptr, _rxContext );
262         }
263     }
264 
265     return Reference<XDataSource>();
266 }
267 
268 Reference< XInterface > getDataSourceOrModel(const Reference< XInterface >& _xObject)
269 {
270     Reference< XInterface > xRet;
271     Reference<XDocumentDataSource> xDocumentDataSource(_xObject,UNO_QUERY);
272     if ( xDocumentDataSource.is() )
273         xRet = xDocumentDataSource->getDatabaseDocument();
274 
275     if ( !xRet.is() )
276     {
277         Reference<XOfficeDatabaseDocument> xOfficeDoc(_xObject,UNO_QUERY);
278         if ( xOfficeDoc.is() )
279             xRet = xOfficeDoc->getDataSource();
280     }
281 
282     return xRet;
283 }
284 
285 TOTypeInfoSP getTypeInfoFromType(const OTypeInfoMap& _rTypeInfo,
286                                sal_Int32 _nType,
287                                const OUString& _sTypeName,
288                                const OUString& _sCreateParams,
289                                sal_Int32 _nPrecision,
290                                sal_Int32 _nScale,
291                                bool _bAutoIncrement,
292                                bool& _brForceToType)
293 {
294     TOTypeInfoSP pTypeInfo;
295     _brForceToType = false;
296     // search for type
297     std::pair<OTypeInfoMap::const_iterator, OTypeInfoMap::const_iterator> aPair = _rTypeInfo.equal_range(_nType);
298     OTypeInfoMap::const_iterator aIter = aPair.first;
299     if(aIter != _rTypeInfo.end()) // compare with end is correct here
300     {
301         for(;aIter != aPair.second;++aIter)
302         {
303             // search the best matching type
304     #ifdef DBG_UTIL
305             OUString sDBTypeName         = aIter->second->aTypeName;         (void)sDBTypeName;
306     #endif
307             if  (   (
308                         _sTypeName.isEmpty()
309                     ||  (aIter->second->aTypeName.equalsIgnoreAsciiCase(_sTypeName))
310                     )
311                 &&  (
312                         (
313                                 !aIter->second->aCreateParams.getLength()
314                             &&  _sCreateParams.isEmpty()
315                         )
316                     ||  (
317                                 (aIter->second->nPrecision      >= _nPrecision)
318                             &&  (aIter->second->nMaximumScale   >= _nScale)
319                             &&  ( (_bAutoIncrement && aIter->second->bAutoIncrement) || !_bAutoIncrement )
320                         )
321                     )
322                 )
323                 break;
324         }
325 
326         if (aIter == aPair.second)
327         {
328             for(aIter = aPair.first; aIter != aPair.second; ++aIter)
329             {
330                 sal_Int32 nPrec = aIter->second->nPrecision;
331                 sal_Int32 nScale = aIter->second->nMaximumScale;
332                 // search the best matching type (now comparing the local names)
333                 if  (   (aIter->second->aLocalTypeName.equalsIgnoreAsciiCase(_sTypeName))
334                     &&  (nPrec  >= _nPrecision)
335                     &&  (nScale >= _nScale)
336                     &&  ( (_bAutoIncrement && aIter->second->bAutoIncrement) || !_bAutoIncrement )
337                     )
338                 {
339                     SAL_WARN("dbaccess.ui", "getTypeInfoFromType: assuming column type " <<
340                              aIter->second->aTypeName <<  "\" (expected type name " <<
341                              _sTypeName << " matches the type's local name).");
342                     break;
343                 }
344             }
345         }
346 
347         if (aIter == aPair.second)
348         {   // no match for the names, no match for the local names
349             // -> drop the precision and the scale restriction, accept any type with the property
350             // type id (nType)
351 
352             for(aIter = aPair.first; aIter != aPair.second; ++aIter)
353             {
354                 // search the best matching type (now comparing the local names)
355                 sal_Int32 nPrec = aIter->second->nPrecision;
356                 sal_Int32 nScale = aIter->second->nMaximumScale;
357                 if  (   (nPrec  >= _nPrecision)
358                     &&  (nScale >= _nScale)
359                     &&  ( (_bAutoIncrement && aIter->second->bAutoIncrement) || !_bAutoIncrement )
360                     )
361                     break;
362             }
363         }
364         if (aIter == aPair.second)
365         {
366             if ( _bAutoIncrement )
367             {
368                 for(aIter = aPair.first; aIter != aPair.second; ++aIter)
369                 {
370                     // search the best matching type (now comparing the local names)
371                     sal_Int32 nScale = aIter->second->nMaximumScale;
372                     if  (   (nScale >= _nScale)
373                         &&  (aIter->second->bAutoIncrement  == _bAutoIncrement)
374                         )
375                         break;
376                 }
377                 if ( aIter == aPair.second )
378                 {
379                     // try it without the auto increment flag
380                     pTypeInfo = getTypeInfoFromType(_rTypeInfo,
381                                    _nType,
382                                    _sTypeName,
383                                    _sCreateParams,
384                                    _nPrecision,
385                                    _nScale,
386                                    false,
387                                    _brForceToType);
388                 }
389                 else
390                     pTypeInfo = aIter->second;
391             }
392             else
393             {
394                 pTypeInfo = aPair.first->second;
395                 _brForceToType = true;
396             }
397         }
398         else
399             pTypeInfo = aIter->second;
400     }
401     else
402     {
403         ::comphelper::UStringMixEqual aCase(false);
404         // search for typeinfo where the typename is equal _sTypeName
405         for (auto const& elem : _rTypeInfo)
406         {
407             if ( aCase( elem.second->getDBName() , _sTypeName ) )
408             {
409                 pTypeInfo = elem.second;
410                 break;
411             }
412         }
413     }
414 
415     OSL_ENSURE(pTypeInfo, "getTypeInfoFromType: no type info found for this type!");
416     return pTypeInfo;
417 }
418 
419 void fillTypeInfo(  const Reference< css::sdbc::XConnection>& _rxConnection,
420                     const OUString& _rsTypeNames,
421                     OTypeInfoMap& _rTypeInfoMap,
422                     std::vector<OTypeInfoMap::iterator>& _rTypeInfoIters)
423 {
424     if(!_rxConnection.is())
425         return;
426     Reference< XResultSet> xRs = _rxConnection->getMetaData ()->getTypeInfo ();
427     Reference< XRow> xRow(xRs,UNO_QUERY);
428     // Information for a single SQL type
429     if(xRs.is())
430     {
431         Reference<XResultSetMetaData> xResultSetMetaData = Reference<XResultSetMetaDataSupplier>(xRs,UNO_QUERY_THROW)->getMetaData();
432         ::connectivity::ORowSetValue aValue;
433         std::vector<sal_Int32> aTypes;
434         std::vector<bool> aNullable;
435         // Loop on the result set until we reach end of file
436         while (xRs->next())
437         {
438             TOTypeInfoSP pInfo = std::make_shared<OTypeInfo>();
439             sal_Int32 nPos = 1;
440             if ( aTypes.empty() )
441             {
442                 sal_Int32 nCount = xResultSetMetaData->getColumnCount();
443                 if ( nCount < 1 )
444                     nCount = 18;
445                 aTypes.reserve(nCount+1);
446                 aTypes.push_back(-1);
447                 aNullable.push_back(false);
448                 for (sal_Int32 j = 1; j <= nCount ; ++j)
449                 {
450                     aTypes.push_back(xResultSetMetaData->getColumnType(j));
451                     aNullable.push_back(xResultSetMetaData->isNullable(j) != ColumnValue::NO_NULLS);
452                 }
453             }
454 
455             aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
456             pInfo->aTypeName        = aValue;
457             ++nPos;
458             aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
459             pInfo->nType            = aValue;
460             ++nPos;
461             aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
462             pInfo->nPrecision       = aValue;
463             ++nPos;
464             aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); // LiteralPrefix
465             ++nPos;
466             aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); //LiteralSuffix
467             ++nPos;
468             aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
469             pInfo->aCreateParams    = aValue;
470             ++nPos;
471             aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
472             pInfo->bNullable        = static_cast<sal_Int32>(aValue) == ColumnValue::NULLABLE;
473             ++nPos;
474             aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
475             // bCaseSensitive
476             ++nPos;
477             aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
478             pInfo->nSearchType      = aValue;
479             ++nPos;
480             aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
481             // bUnsigned
482             ++nPos;
483             aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
484             pInfo->bCurrency        = static_cast<bool>(aValue);
485             ++nPos;
486             aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
487             pInfo->bAutoIncrement   = static_cast<bool>(aValue);
488             ++nPos;
489             aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
490             pInfo->aLocalTypeName   = aValue;
491             ++nPos;
492             aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
493             pInfo->nMinimumScale    = aValue;
494             ++nPos;
495             aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
496             pInfo->nMaximumScale    = aValue;
497             assert(nPos == 15);
498             // 16 and 17 are unused
499             nPos = 18;
500             aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
501             pInfo->nNumPrecRadix    = aValue;
502 
503             // check if values are less than zero like it happens in a oracle jdbc driver
504             if( pInfo->nPrecision < 0)
505                 pInfo->nPrecision = 0;
506             if( pInfo->nMinimumScale < 0)
507                 pInfo->nMinimumScale = 0;
508             if( pInfo->nMaximumScale < 0)
509                 pInfo->nMaximumScale = 0;
510             if( pInfo->nNumPrecRadix <= 1)
511                 pInfo->nNumPrecRadix = 10;
512 
513             OUString aName;
514             switch(pInfo->nType)
515             {
516                 case DataType::CHAR:
517                     aName = _rsTypeNames.getToken(TYPE_CHAR, ';');
518                     break;
519                 case DataType::VARCHAR:
520                     aName = _rsTypeNames.getToken(TYPE_TEXT, ';');
521                     break;
522                 case DataType::DECIMAL:
523                     aName = _rsTypeNames.getToken(TYPE_DECIMAL, ';');
524                     break;
525                 case DataType::NUMERIC:
526                     aName = _rsTypeNames.getToken(TYPE_NUMERIC, ';');
527                     break;
528                 case DataType::BIGINT:
529                     aName = _rsTypeNames.getToken(TYPE_BIGINT, ';');
530                     break;
531                 case DataType::FLOAT:
532                     aName = _rsTypeNames.getToken(TYPE_FLOAT, ';');
533                     break;
534                 case DataType::DOUBLE:
535                     aName = _rsTypeNames.getToken(TYPE_DOUBLE, ';');
536                     break;
537                 case DataType::LONGVARCHAR:
538                     aName = _rsTypeNames.getToken(TYPE_MEMO, ';');
539                     break;
540                 case DataType::LONGVARBINARY:
541                     aName = _rsTypeNames.getToken(TYPE_IMAGE, ';');
542                     break;
543                 case DataType::DATE:
544                     aName = _rsTypeNames.getToken(TYPE_DATE, ';');
545                     break;
546                 case DataType::TIME:
547                     aName = _rsTypeNames.getToken(TYPE_TIME, ';');
548                     break;
549                 case DataType::TIMESTAMP:
550                     aName = _rsTypeNames.getToken(TYPE_DATETIME, ';');
551                     break;
552                 case DataType::BIT:
553                     if ( !pInfo->aCreateParams.isEmpty() )
554                     {
555                         aName = _rsTypeNames.getToken(TYPE_BIT, ';');
556                         break;
557                     }
558                     [[fallthrough]];
559                 case DataType::BOOLEAN:
560                     aName = _rsTypeNames.getToken(TYPE_BOOL, ';');
561                     break;
562                 case DataType::TINYINT:
563                     aName = _rsTypeNames.getToken(TYPE_TINYINT, ';');
564                     break;
565                 case DataType::SMALLINT:
566                     aName = _rsTypeNames.getToken(TYPE_SMALLINT, ';');
567                     break;
568                 case DataType::INTEGER:
569                     aName = _rsTypeNames.getToken(TYPE_INTEGER, ';');
570                     break;
571                 case DataType::REAL:
572                     aName = _rsTypeNames.getToken(TYPE_REAL, ';');
573                     break;
574                 case DataType::BINARY:
575                     aName = _rsTypeNames.getToken(TYPE_BINARY, ';');
576                     break;
577                 case DataType::VARBINARY:
578                     aName = _rsTypeNames.getToken(TYPE_VARBINARY, ';');
579                     break;
580                 case DataType::SQLNULL:
581                     aName = _rsTypeNames.getToken(TYPE_SQLNULL, ';');
582                     break;
583                 case DataType::OBJECT:
584                     aName = _rsTypeNames.getToken(TYPE_OBJECT, ';');
585                     break;
586                 case DataType::DISTINCT:
587                     aName = _rsTypeNames.getToken(TYPE_DISTINCT, ';');
588                     break;
589                 case DataType::STRUCT:
590                     aName = _rsTypeNames.getToken(TYPE_STRUCT, ';');
591                     break;
592                 case DataType::ARRAY:
593                     aName = _rsTypeNames.getToken(TYPE_ARRAY, ';');
594                     break;
595                 case DataType::BLOB:
596                     aName = _rsTypeNames.getToken(TYPE_BLOB, ';');
597                     break;
598                 case DataType::CLOB:
599                     aName = _rsTypeNames.getToken(TYPE_CLOB, ';');
600                     break;
601                 case DataType::REF:
602                     aName = _rsTypeNames.getToken(TYPE_REF, ';');
603                     break;
604                 case DataType::OTHER:
605                     aName = _rsTypeNames.getToken(TYPE_OTHER, ';');
606                     break;
607             }
608             if ( !aName.isEmpty() )
609             {
610                 pInfo->aUIName = aName;
611                 pInfo->aUIName += " [ ";
612             }
613             pInfo->aUIName += pInfo->aTypeName;
614             if ( !aName.isEmpty() )
615                 pInfo->aUIName += " ]";
616             // Now that we have the type info, save it in the multimap
617             _rTypeInfoMap.emplace(pInfo->nType,pInfo);
618         }
619         // for a faster index access
620         _rTypeInfoIters.reserve(_rTypeInfoMap.size());
621 
622         OTypeInfoMap::iterator aIter = _rTypeInfoMap.begin();
623         OTypeInfoMap::const_iterator aEnd = _rTypeInfoMap.end();
624         for(;aIter != aEnd;++aIter)
625             _rTypeInfoIters.push_back(aIter);
626 
627         // Close the result set/statement.
628 
629         ::comphelper::disposeComponent(xRs);
630     }
631 }
632 
633 void setColumnProperties(const Reference<XPropertySet>& _rxColumn,const OFieldDescription* _pFieldDesc)
634 {
635     _rxColumn->setPropertyValue(PROPERTY_NAME,makeAny(_pFieldDesc->GetName()));
636     _rxColumn->setPropertyValue(PROPERTY_TYPENAME,makeAny(_pFieldDesc->getTypeInfo()->aTypeName));
637     _rxColumn->setPropertyValue(PROPERTY_TYPE,makeAny(_pFieldDesc->GetType()));
638     _rxColumn->setPropertyValue(PROPERTY_PRECISION,makeAny(_pFieldDesc->GetPrecision()));
639     _rxColumn->setPropertyValue(PROPERTY_SCALE,makeAny(_pFieldDesc->GetScale()));
640     _rxColumn->setPropertyValue(PROPERTY_ISNULLABLE, makeAny(_pFieldDesc->GetIsNullable()));
641     _rxColumn->setPropertyValue(PROPERTY_ISAUTOINCREMENT, css::uno::makeAny(_pFieldDesc->IsAutoIncrement()));
642     _rxColumn->setPropertyValue(PROPERTY_DESCRIPTION,makeAny(_pFieldDesc->GetDescription()));
643     if ( _rxColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_ISCURRENCY) && _pFieldDesc->IsCurrency() )
644         _rxColumn->setPropertyValue(PROPERTY_ISCURRENCY, css::uno::makeAny(_pFieldDesc->IsCurrency()));
645     // set autoincrement value when available
646     // and only set when the entry is not empty, that lets the value in the column untouched
647     if ( _pFieldDesc->IsAutoIncrement() && !_pFieldDesc->GetAutoIncrementValue().isEmpty() && _rxColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_AUTOINCREMENTCREATION) )
648         _rxColumn->setPropertyValue(PROPERTY_AUTOINCREMENTCREATION,makeAny(_pFieldDesc->GetAutoIncrementValue()));
649 }
650 
651 OUString createDefaultName(const Reference< XDatabaseMetaData>& _xMetaData,const Reference<XNameAccess>& _xTables,const OUString& _sName)
652 {
653     OSL_ENSURE(_xMetaData.is(),"No MetaData!");
654     OUString sDefaultName = _sName;
655     try
656     {
657         OUString sCatalog,sSchema,sCompsedName;
658         if(_xMetaData->supportsCatalogsInTableDefinitions())
659         {
660             try
661             {
662                 Reference< XConnection> xCon = _xMetaData->getConnection();
663                 if ( xCon.is() )
664                     sCatalog = xCon->getCatalog();
665                 if ( sCatalog.isEmpty() )
666                 {
667                     Reference<XResultSet> xRes = _xMetaData->getCatalogs();
668                     Reference<XRow> xRow(xRes,UNO_QUERY);
669                     while(xRes.is() && xRes->next())
670                     {
671                         sCatalog = xRow->getString(1);
672                         if(!xRow->wasNull())
673                             break;
674                     }
675                 }
676             }
677             catch(const SQLException&)
678             {
679             }
680         }
681         if(_xMetaData->supportsSchemasInTableDefinitions())
682         {
683             sSchema = _xMetaData->getUserName();
684         }
685         sCompsedName = ::dbtools::composeTableName( _xMetaData, sCatalog, sSchema, _sName, false, ::dbtools::EComposeRule::InDataManipulation );
686         sDefaultName = ::dbtools::createUniqueName(_xTables,sCompsedName);
687     }
688     catch(const SQLException&)
689     {
690     }
691     return sDefaultName;
692 }
693 
694 bool checkDataSourceAvailable(const OUString& _sDataSourceName,const Reference< css::uno::XComponentContext >& _xContext)
695 {
696     Reference< XDatabaseContext > xDataBaseContext = DatabaseContext::create(_xContext);
697     bool bRet = xDataBaseContext->hasByName(_sDataSourceName);
698     if ( !bRet )
699     { // try if this one is a URL
700         try
701         {
702             bRet = xDataBaseContext->getByName(_sDataSourceName).hasValue();
703         }
704         catch(const Exception&)
705         {
706         }
707     }
708     return bRet;
709 }
710 
711 sal_Int32 mapTextAllign(const SvxCellHorJustify& _eAlignment)
712 {
713     sal_Int32 nAlignment = css::awt::TextAlign::LEFT;
714     switch (_eAlignment)
715     {
716         case SvxCellHorJustify::Standard:
717         case SvxCellHorJustify::Left:      nAlignment = css::awt::TextAlign::LEFT;    break;
718         case SvxCellHorJustify::Center:    nAlignment = css::awt::TextAlign::CENTER;  break;
719         case SvxCellHorJustify::Right:     nAlignment = css::awt::TextAlign::RIGHT;   break;
720         default:
721             SAL_WARN("dbaccess.ui", "Invalid TextAlign!");
722     }
723     return nAlignment;
724 }
725 
726 SvxCellHorJustify mapTextJustify(sal_Int32 _nAlignment)
727 {
728     SvxCellHorJustify eJustify = SvxCellHorJustify::Left;
729     switch (_nAlignment)
730     {
731         case css::awt::TextAlign::LEFT     : eJustify = SvxCellHorJustify::Left; break;
732         case css::awt::TextAlign::CENTER   : eJustify = SvxCellHorJustify::Center; break;
733         case css::awt::TextAlign::RIGHT    : eJustify = SvxCellHorJustify::Right; break;
734         default:
735             SAL_WARN("dbaccess.ui", "Invalid TextAlign!");
736     }
737     return eJustify;
738 }
739 
740 void callColumnFormatDialog(const Reference<XPropertySet>& xAffectedCol,
741                             const Reference<XPropertySet>& xField,
742                             SvNumberFormatter* _pFormatter,
743                             const vcl::Window* _pParent)
744 {
745     if (xAffectedCol.is() && xField.is())
746     {
747         try
748         {
749             Reference< XPropertySetInfo >  xInfo = xAffectedCol->getPropertySetInfo();
750             bool bHasFormat = xInfo->hasPropertyByName(PROPERTY_FORMATKEY);
751             sal_Int32 nDataType = ::comphelper::getINT32(xField->getPropertyValue(PROPERTY_TYPE));
752 
753             SvxCellHorJustify eJustify(SvxCellHorJustify::Standard);
754             Any aAlignment = xAffectedCol->getPropertyValue(PROPERTY_ALIGN);
755             if (aAlignment.hasValue())
756                 eJustify = dbaui::mapTextJustify(::comphelper::getINT16(aAlignment));
757             sal_Int32  nFormatKey = 0;
758             if ( bHasFormat )
759                 nFormatKey = ::comphelper::getINT32(xAffectedCol->getPropertyValue(PROPERTY_FORMATKEY));
760 
761             if(callColumnFormatDialog(_pParent,_pFormatter,nDataType,nFormatKey,eJustify,bHasFormat))
762             {
763                 xAffectedCol->setPropertyValue(PROPERTY_ALIGN, makeAny(static_cast<sal_Int16>(dbaui::mapTextAllign(eJustify))));
764                 if (bHasFormat)
765                     xAffectedCol->setPropertyValue(PROPERTY_FORMATKEY, makeAny(nFormatKey));
766 
767             }
768         }
769         catch( const Exception& )
770         {
771             DBG_UNHANDLED_EXCEPTION("dbaccess");
772         }
773     }
774 }
775 
776 bool callColumnFormatDialog(const vcl::Window* _pParent,
777                                 SvNumberFormatter* _pFormatter,
778                                 sal_Int32 _nDataType,
779                                 sal_Int32& _nFormatKey,
780                                 SvxCellHorJustify& _eJustify,
781                                 bool  _bHasFormat)
782 {
783     bool bRet = false;
784 
785     // UNO->ItemSet
786     static SfxItemInfo aItemInfos[] =
787     {
788         { 0, false },
789         { SID_ATTR_NUMBERFORMAT_VALUE,      true },
790         { SID_ATTR_ALIGN_HOR_JUSTIFY,       true },
791         { SID_ATTR_NUMBERFORMAT_ONE_AREA,   true },
792         { SID_ATTR_NUMBERFORMAT_INFO,       true }
793     };
794     static const sal_uInt16 aAttrMap[] =
795     {
796         SBA_DEF_RANGEFORMAT, SBA_ATTR_ALIGN_HOR_JUSTIFY,
797         SID_ATTR_NUMBERFORMAT_ONE_AREA, SID_ATTR_NUMBERFORMAT_ONE_AREA,
798         SID_ATTR_NUMBERFORMAT_INFO, SID_ATTR_NUMBERFORMAT_INFO,
799         0
800     };
801 
802     std::vector<SfxPoolItem*> pDefaults
803     {
804         new SfxRangeItem(SBA_DEF_RANGEFORMAT, SBA_DEF_FMTVALUE, SBA_ATTR_ALIGN_HOR_JUSTIFY),
805         new SfxUInt32Item(SBA_DEF_FMTVALUE),
806         new SvxHorJustifyItem(SvxCellHorJustify::Standard, SBA_ATTR_ALIGN_HOR_JUSTIFY),
807         new SfxBoolItem(SID_ATTR_NUMBERFORMAT_ONE_AREA, false),
808         new SvxNumberInfoItem(SID_ATTR_NUMBERFORMAT_INFO)
809     };
810 
811     SfxItemPool* pPool = new SfxItemPool("GridBrowserProperties", SBA_DEF_RANGEFORMAT, SBA_ATTR_ALIGN_HOR_JUSTIFY, aItemInfos, &pDefaults);
812     pPool->SetDefaultMetric( MapUnit::MapTwip );    // ripped, don't understand why
813     pPool->FreezeIdRanges();                        // the same
814 
815     std::unique_ptr<SfxItemSet> pFormatDescriptor(new SfxItemSet(*pPool, aAttrMap));
816     // fill it
817     pFormatDescriptor->Put(SvxHorJustifyItem(_eJustify, SBA_ATTR_ALIGN_HOR_JUSTIFY));
818     bool bText = false;
819     if (_bHasFormat)
820     {
821         // if the col is bound to a text field we have to disallow all non-text formats
822         if ((DataType::CHAR == _nDataType) || (DataType::VARCHAR == _nDataType) || (DataType::LONGVARCHAR == _nDataType) || (DataType::CLOB == _nDataType))
823         {
824             bText = true;
825             pFormatDescriptor->Put(SfxBoolItem(SID_ATTR_NUMBERFORMAT_ONE_AREA, true));
826             if (!_pFormatter->IsTextFormat(_nFormatKey))
827                 // text fields can only have text formats
828                 _nFormatKey = _pFormatter->GetStandardFormat(SvNumFormatType::TEXT,_pParent->GetSettings().GetLanguageTag().getLanguageType());
829         }
830 
831         pFormatDescriptor->Put(SfxUInt32Item(SBA_DEF_FMTVALUE, _nFormatKey));
832     }
833 
834     if (!bText)
835     {
836         SvxNumberInfoItem aFormatter(_pFormatter, 1234.56789, SID_ATTR_NUMBERFORMAT_INFO);
837         pFormatDescriptor->Put(aFormatter);
838     }
839 
840     {   // want the dialog to be destroyed before our set
841         SbaSbAttrDlg aDlg(_pParent->GetFrameWeld(), pFormatDescriptor.get(), _pFormatter, _bHasFormat);
842         if (RET_OK == aDlg.run())
843         {
844             // ItemSet->UNO
845             // UNO-properties
846             const SfxItemSet* pSet = aDlg.GetExampleSet();
847             // (of course we could put the modified items directly into the column, but then the UNO-model
848             // won't reflect these changes, and why do we have a model, then ?)
849 
850             // horizontal justify
851             const SvxHorJustifyItem* pHorJustify = pSet->GetItem<SvxHorJustifyItem>(SBA_ATTR_ALIGN_HOR_JUSTIFY);
852 
853             _eJustify = pHorJustify->GetValue();
854 
855             // format key
856             if (_bHasFormat)
857             {
858                 const SfxUInt32Item* pFormat = pSet->GetItem<SfxUInt32Item>(SBA_DEF_FMTVALUE);
859                 _nFormatKey = static_cast<sal_Int32>(pFormat->GetValue());
860             }
861             bRet = true;
862         }
863             // deleted formats
864         const SfxItemSet* pResult = aDlg.GetOutputItemSet();
865         if (pResult)
866         {
867             const SfxPoolItem* pItem = pResult->GetItem( SID_ATTR_NUMBERFORMAT_INFO );
868             const SvxNumberInfoItem* pInfoItem = static_cast<const SvxNumberInfoItem*>(pItem);
869             if (pInfoItem)
870             {
871                 for (sal_uInt32 key : pInfoItem->GetDelFormats())
872                     _pFormatter->DeleteEntry(key);
873             }
874         }
875     }
876 
877     pFormatDescriptor.reset();
878     SfxItemPool::Free(pPool);
879     for (SfxPoolItem* pDefault : pDefaults)
880         delete pDefault;
881 
882     return bRet;
883 }
884 
885 std::shared_ptr<const SfxFilter> getStandardDatabaseFilter()
886 {
887     std::shared_ptr<const SfxFilter> pFilter = SfxFilter::GetFilterByName("StarOffice XML (Base)");
888     OSL_ENSURE(pFilter,"Filter: StarOffice XML (Base) could not be found!");
889     return pFilter;
890 }
891 
892 bool appendToFilter(const Reference<XConnection>& _xConnection,
893                     const OUString& _sName,
894                     const Reference< XComponentContext >& _rxContext,
895                     weld::Window* pParent)
896 {
897     bool bRet = false;
898     Reference< XChild> xChild(_xConnection,UNO_QUERY);
899     if(xChild.is())
900     {
901         Reference< XPropertySet> xProp(xChild->getParent(),UNO_QUERY);
902         if(xProp.is())
903         {
904             Sequence< OUString > aFilter;
905             xProp->getPropertyValue(PROPERTY_TABLEFILTER) >>= aFilter;
906             // first check if we have something like SCHEMA.%
907             bool bHasToInsert = true;
908             for (const OUString& rItem : std::as_const(aFilter))
909             {
910                 if(rItem.indexOf('%') != -1)
911                 {
912                     sal_Int32 nLen;
913                     if((nLen = rItem.lastIndexOf('.')) != -1 && !rItem.compareTo(_sName,nLen))
914                         bHasToInsert = false;
915                     else if(rItem.getLength() == 1)
916                         bHasToInsert = false;
917                 }
918             }
919 
920             bRet = true;
921             if(bHasToInsert)
922             {
923                 if(! ::dbaui::checkDataSourceAvailable(::comphelper::getString(xProp->getPropertyValue(PROPERTY_NAME)),_rxContext))
924                 {
925                     OUString aMessage(DBA_RES(STR_TABLEDESIGN_DATASOURCE_DELETED));
926                     OSQLWarningBox aWarning(pParent, aMessage);
927                     aWarning.run();
928                     bRet = false;
929                 }
930                 else
931                 {
932                     aFilter.realloc(aFilter.getLength()+1);
933                     aFilter.getArray()[aFilter.getLength()-1] = _sName;
934                     xProp->setPropertyValue(PROPERTY_TABLEFILTER,makeAny(aFilter));
935                 }
936             }
937         }
938     }
939     return bRet;
940 }
941 
942 void notifySystemWindow(vcl::Window const * _pWindow, vcl::Window* _pToRegister, const ::comphelper::mem_fun1_t<TaskPaneList,vcl::Window*>& _rMemFunc)
943 {
944     OSL_ENSURE(_pWindow,"Window can not be null!");
945     SystemWindow* pSystemWindow = _pWindow ? _pWindow->GetSystemWindow() : nullptr;
946     if ( pSystemWindow )
947     {
948         _rMemFunc( pSystemWindow->GetTaskPaneList(), _pToRegister );
949     }
950 }
951 
952 void adjustBrowseBoxColumnWidth( ::svt::EditBrowseBox* _pBox, sal_uInt16 _nColId )
953 {
954     sal_Int32 nColSize = -1;
955     sal_uInt32 nDefaultWidth = _pBox->GetDefaultColumnWidth( _pBox->GetColumnTitle( _nColId ) );
956     if ( nDefaultWidth != _pBox->GetColumnWidth( _nColId ) )
957     {
958         Size aSizeMM = _pBox->PixelToLogic( Size( _pBox->GetColumnWidth( _nColId ), 0 ), MapMode( MapUnit::MapMM ) );
959         nColSize = aSizeMM.Width() * 10;
960     }
961 
962     Size aDefaultMM = _pBox->PixelToLogic( Size( nDefaultWidth, 0 ), MapMode( MapUnit::MapMM ) );
963 
964     DlgSize aColumnSizeDlg(_pBox->GetFrameWeld(), nColSize, false, aDefaultMM.Width() * 10);
965     if (aColumnSizeDlg.run() == RET_OK)
966     {
967         sal_Int32 nValue = aColumnSizeDlg.GetValue();
968         if ( -1 == nValue )
969         {   // default width
970             nValue = _pBox->GetDefaultColumnWidth( _pBox->GetColumnTitle( _nColId ) );
971         }
972         else
973         {
974             Size aSizeMM( nValue / 10, 0 );
975             nValue = _pBox->LogicToPixel( aSizeMM, MapMode( MapUnit::MapMM ) ).Width();
976         }
977         _pBox->SetColumnWidth( _nColId, nValue );
978     }
979 }
980 
981 // check if SQL92 name checking is enabled
982 bool isSQL92CheckEnabled(const Reference<XConnection>& _xConnection)
983 {
984     return ::dbtools::getBooleanDataSourceSetting( _xConnection, PROPERTY_ENABLESQL92CHECK );
985 }
986 
987 bool isAppendTableAliasEnabled(const Reference<XConnection>& _xConnection)
988 {
989     return ::dbtools::getBooleanDataSourceSetting( _xConnection, INFO_APPEND_TABLE_ALIAS );
990 }
991 
992 bool generateAsBeforeTableAlias(const Reference<XConnection>& _xConnection)
993 {
994     return ::dbtools::getBooleanDataSourceSetting( _xConnection, INFO_AS_BEFORE_CORRELATION_NAME );
995 }
996 
997 void fillAutoIncrementValue(const Reference<XPropertySet>& _xDatasource,
998                             bool& _rAutoIncrementValueEnabled,
999                             OUString& _rsAutoIncrementValue)
1000 {
1001     if ( _xDatasource.is() )
1002     {
1003         OSL_ENSURE(_xDatasource->getPropertySetInfo()->hasPropertyByName(PROPERTY_INFO),"NO datasource supplied!");
1004         Sequence<PropertyValue> aInfo;
1005         _xDatasource->getPropertyValue(PROPERTY_INFO) >>= aInfo;
1006 
1007         // search the right propertyvalue
1008         const PropertyValue* pValue =std::find_if(aInfo.begin(), aInfo.end(),
1009                                             [](const PropertyValue& lhs)
1010                                             {return lhs.Name == PROPERTY_AUTOINCREMENTCREATION;} );
1011 
1012         if ( pValue != aInfo.end() )
1013             pValue->Value >>= _rsAutoIncrementValue;
1014         pValue =std::find_if(aInfo.begin(), aInfo.end(),
1015                              [](const PropertyValue& lhs)
1016                              {return lhs.Name == "IsAutoRetrievingEnabled";} );
1017 
1018         if ( pValue != aInfo.end() )
1019             pValue->Value >>= _rAutoIncrementValueEnabled;
1020     }
1021 }
1022 
1023 void fillAutoIncrementValue(const Reference<XConnection>& _xConnection,
1024                             bool& _rAutoIncrementValueEnabled,
1025                             OUString& _rsAutoIncrementValue)
1026 {
1027     Reference< XChild> xChild(_xConnection,UNO_QUERY);
1028     if(xChild.is())
1029     {
1030         Reference< XPropertySet> xProp(xChild->getParent(),UNO_QUERY);
1031         fillAutoIncrementValue(xProp,_rAutoIncrementValueEnabled,_rsAutoIncrementValue);
1032     }
1033 }
1034 
1035 OUString getStrippedDatabaseName(const Reference<XPropertySet>& _xDataSource,OUString& _rsDatabaseName)
1036 {
1037     if ( _rsDatabaseName.isEmpty() && _xDataSource.is() )
1038     {
1039         try
1040         {
1041             _xDataSource->getPropertyValue(PROPERTY_NAME) >>= _rsDatabaseName;
1042         }
1043         catch(const Exception& )
1044         {
1045             DBG_UNHANDLED_EXCEPTION("dbaccess");
1046         }
1047     }
1048     OUString sName = _rsDatabaseName;
1049     INetURLObject aURL(sName);
1050     if ( aURL.GetProtocol() != INetProtocol::NotValid )
1051         sName = aURL.getBase(INetURLObject::LAST_SEGMENT,true,INetURLObject::DecodeMechanism::Unambiguous);
1052     return sName;
1053 }
1054 
1055 void setEvalDateFormatForFormatter(Reference< css::util::XNumberFormatter > const & _rxFormatter)
1056 {
1057     OSL_ENSURE( _rxFormatter.is(),"setEvalDateFormatForFormatter: Formatter is NULL!");
1058     if ( _rxFormatter.is() )
1059     {
1060         Reference< css::util::XNumberFormatsSupplier >  xSupplier = _rxFormatter->getNumberFormatsSupplier();
1061 
1062         auto pSupplierImpl = comphelper::getUnoTunnelImplementation<SvNumberFormatsSupplierObj>(xSupplier);
1063         OSL_ENSURE(pSupplierImpl,"No Supplier!");
1064 
1065         if ( pSupplierImpl )
1066         {
1067             SvNumberFormatter* pFormatter = pSupplierImpl->GetNumberFormatter();
1068             pFormatter->SetEvalDateFormat(NF_EVALDATEFORMAT_FORMAT);
1069         }
1070     }
1071 }
1072 
1073 TOTypeInfoSP queryPrimaryKeyType(const OTypeInfoMap& _rTypeInfo)
1074 {
1075     TOTypeInfoSP pTypeInfo;
1076     // first we search for a type which supports autoIncrement
1077     for (auto const& elem : _rTypeInfo)
1078     {
1079         // OJ: we don't want to set an autoincrement column to be key
1080         // because we don't have the possibility to know how to create
1081         // such auto increment column later on
1082         // so until we know how to do it, we create a column without autoincrement
1083         // therefore we have searched
1084         if ( elem.second->nType == DataType::INTEGER )
1085         {
1086             pTypeInfo = elem.second; // alternative
1087             break;
1088         }
1089         else if ( !pTypeInfo.get() && elem.second->nType == DataType::DOUBLE )
1090             pTypeInfo = elem.second; // alternative
1091         else if ( !pTypeInfo.get() && elem.second->nType == DataType::REAL )
1092             pTypeInfo = elem.second; // alternative
1093     }
1094     if ( !pTypeInfo.get() ) // just a fallback
1095         pTypeInfo = queryTypeInfoByType(DataType::VARCHAR,_rTypeInfo);
1096 
1097     OSL_ENSURE(pTypeInfo.get(),"checkColumns: can't find a type which is usable as a key!");
1098     return pTypeInfo;
1099 }
1100 
1101 TOTypeInfoSP queryTypeInfoByType(sal_Int32 _nDataType,const OTypeInfoMap& _rTypeInfo)
1102 {
1103     OTypeInfoMap::const_iterator aIter = _rTypeInfo.find(_nDataType);
1104     if(aIter != _rTypeInfo.end())
1105         return aIter->second;
1106     // fall back if the type is unknown
1107     TOTypeInfoSP pTypeInfo;
1108     switch(_nDataType)
1109     {
1110         case DataType::TINYINT:
1111             if( (pTypeInfo = queryTypeInfoByType(DataType::SMALLINT,_rTypeInfo) ) )
1112                 break;
1113             [[fallthrough]];
1114         case DataType::SMALLINT:
1115             if( (pTypeInfo = queryTypeInfoByType(DataType::INTEGER,_rTypeInfo) ) )
1116                 break;
1117             [[fallthrough]];
1118         case DataType::INTEGER:
1119             if( (pTypeInfo = queryTypeInfoByType(DataType::FLOAT,_rTypeInfo) ) )
1120                 break;
1121             [[fallthrough]];
1122         case DataType::FLOAT:
1123             if( (pTypeInfo = queryTypeInfoByType(DataType::REAL,_rTypeInfo) ) )
1124                 break;
1125             [[fallthrough]];
1126         case DataType::DATE:
1127         case DataType::TIME:
1128             if( DataType::DATE == _nDataType || DataType::TIME == _nDataType )
1129             {
1130                 if( (pTypeInfo = queryTypeInfoByType(DataType::TIMESTAMP,_rTypeInfo) ) )
1131                     break;
1132             }
1133             [[fallthrough]];
1134         case DataType::TIMESTAMP:
1135         case DataType::REAL:
1136         case DataType::BIGINT:
1137             if (  (pTypeInfo = queryTypeInfoByType(DataType::DOUBLE,_rTypeInfo) ) )
1138                 break;
1139             [[fallthrough]];
1140         case DataType::DOUBLE:
1141             if (  (pTypeInfo = queryTypeInfoByType(DataType::NUMERIC,_rTypeInfo) ) )
1142                 break;
1143             [[fallthrough]];
1144         case DataType::NUMERIC:
1145              pTypeInfo = queryTypeInfoByType(DataType::DECIMAL,_rTypeInfo);
1146             break;
1147         case DataType::DECIMAL:
1148             if (  (pTypeInfo = queryTypeInfoByType(DataType::NUMERIC,_rTypeInfo) ) )
1149                 break;
1150             if (  (pTypeInfo = queryTypeInfoByType(DataType::DOUBLE,_rTypeInfo) ) )
1151                 break;
1152             break;
1153         case DataType::VARCHAR:
1154             if (  (pTypeInfo = queryTypeInfoByType(DataType::LONGVARCHAR,_rTypeInfo) ) )
1155                 break;
1156             break;
1157         case DataType::LONGVARCHAR:
1158             if (  (pTypeInfo = queryTypeInfoByType(DataType::CLOB,_rTypeInfo) ) )
1159                 break;
1160             break;
1161         default:
1162             ;
1163     }
1164     if ( !pTypeInfo )
1165     {
1166         bool bForce = true;
1167         pTypeInfo = ::dbaui::getTypeInfoFromType(_rTypeInfo,DataType::VARCHAR,OUString(),"x",50,0,false,bForce);
1168     }
1169     OSL_ENSURE(pTypeInfo,"Wrong DataType supplied!");
1170     return pTypeInfo;
1171 }
1172 
1173 sal_Int32 askForUserAction(weld::Window* pParent, const char* pTitle, const char* pText, bool _bAll, const OUString& _sName)
1174 {
1175     SolarMutexGuard aGuard;
1176     OUString aMsg = DBA_RES(pText);
1177     aMsg = aMsg.replaceFirst("%1", _sName);
1178     OSQLMessageBox aAsk(pParent, DBA_RES(pTitle), aMsg, MessBoxStyle::YesNo | MessBoxStyle::DefaultYes, MessageType::Query);
1179     if ( _bAll )
1180     {
1181         aAsk.add_button(DBA_RES(STR_BUTTON_TEXT_ALL), RET_ALL, HID_CONFIRM_DROP_BUTTON_ALL);
1182     }
1183     return aAsk.run();
1184 }
1185 
1186 namespace
1187 {
1188     OUString lcl_createSDBCLevelStatement( const OUString& _rStatement, const Reference< XConnection >& _rxConnection )
1189     {
1190         OUString sSDBCLevelStatement( _rStatement );
1191         try
1192         {
1193             Reference< XMultiServiceFactory > xAnalyzerFactory( _rxConnection, UNO_QUERY_THROW );
1194             Reference< XSingleSelectQueryAnalyzer > xAnalyzer( xAnalyzerFactory->createInstance( SERVICE_NAME_SINGLESELECTQUERYCOMPOSER ), UNO_QUERY_THROW );
1195             xAnalyzer->setQuery( _rStatement );
1196             sSDBCLevelStatement = xAnalyzer->getQueryWithSubstitution();
1197         }
1198         catch( const Exception& )
1199         {
1200             DBG_UNHANDLED_EXCEPTION("dbaccess");
1201         }
1202         return sSDBCLevelStatement;
1203     }
1204 }
1205 
1206 Reference< XPropertySet > createView( const OUString& _rName, const Reference< XConnection >& _rxConnection,
1207                                     const OUString& _rCommand )
1208 {
1209     Reference<XViewsSupplier> xSup(_rxConnection,UNO_QUERY);
1210     Reference< XNameAccess > xViews;
1211     if(xSup.is())
1212         xViews = xSup->getViews();
1213     Reference<XDataDescriptorFactory> xFact(xViews,UNO_QUERY);
1214     OSL_ENSURE(xFact.is(),"No XDataDescriptorFactory available!");
1215     if(!xFact.is())
1216         return nullptr;
1217 
1218     Reference<XPropertySet> xView = xFact->createDataDescriptor();
1219     if ( !xView.is() )
1220         return nullptr;
1221 
1222     OUString sCatalog,sSchema,sTable;
1223     ::dbtools::qualifiedNameComponents(_rxConnection->getMetaData(),
1224                                         _rName,
1225                                         sCatalog,
1226                                         sSchema,
1227                                         sTable,
1228                                         ::dbtools::EComposeRule::InDataManipulation);
1229 
1230     xView->setPropertyValue(PROPERTY_CATALOGNAME,makeAny(sCatalog));
1231     xView->setPropertyValue(PROPERTY_SCHEMANAME,makeAny(sSchema));
1232     xView->setPropertyValue(PROPERTY_NAME,makeAny(sTable));
1233 
1234     xView->setPropertyValue( PROPERTY_COMMAND, makeAny( _rCommand ) );
1235 
1236     Reference<XAppend> xAppend(xViews,UNO_QUERY);
1237     if(xAppend.is())
1238         xAppend->appendByDescriptor(xView);
1239 
1240     xView = nullptr;
1241     // we need to reget the view because after appending it, it is no longer valid
1242     // but this time it isn't a view object it is a table object with type "VIEW"
1243     Reference<XTablesSupplier> xTabSup(_rxConnection,UNO_QUERY);
1244     Reference< XNameAccess > xTables;
1245     if ( xTabSup.is() )
1246     {
1247         xTables = xTabSup->getTables();
1248         if ( xTables.is() && xTables->hasByName( _rName ) )
1249             xTables->getByName( _rName ) >>= xView;
1250     }
1251 
1252     return xView;
1253 }
1254 
1255 Reference<XPropertySet> createView( const OUString& _rName, const Reference< XConnection >& _rxConnection
1256                                    ,const Reference<XPropertySet>& _rxSourceObject)
1257 {
1258     OUString sCommand;
1259     Reference< XPropertySetInfo > xPSI( _rxSourceObject->getPropertySetInfo(), UNO_SET_THROW );
1260     if ( xPSI->hasPropertyByName( PROPERTY_COMMAND ) )
1261     {
1262         _rxSourceObject->getPropertyValue( PROPERTY_COMMAND ) >>= sCommand;
1263 
1264         bool bEscapeProcessing( false );
1265         OSL_VERIFY( _rxSourceObject->getPropertyValue( PROPERTY_ESCAPE_PROCESSING ) >>= bEscapeProcessing );
1266         if ( bEscapeProcessing )
1267             sCommand = lcl_createSDBCLevelStatement( sCommand, _rxConnection );
1268     }
1269     else
1270     {
1271         sCommand =  "SELECT * FROM " + composeTableNameForSelect( _rxConnection, _rxSourceObject );
1272     }
1273     return createView( _rName, _rxConnection, sCommand );
1274 }
1275 
1276 bool insertHierachyElement(weld::Window* pParent, const Reference< XComponentContext >& _rxContext,
1277                            const Reference<XHierarchicalNameContainer>& _xNames,
1278                            const OUString& _sParentFolder,
1279                            bool _bForm,
1280                            bool _bCollection,
1281                            const Reference<XContent>& _xContent,
1282                            bool _bMove)
1283 {
1284     OSL_ENSURE( _xNames.is(), "insertHierachyElement: illegal name container!" );
1285     if ( !_xNames.is() )
1286         return false;
1287 
1288     Reference<XNameAccess> xNameAccess( _xNames, UNO_QUERY );
1289     if ( _xNames->hasByHierarchicalName(_sParentFolder) )
1290     {
1291         Reference<XChild> xChild(_xNames->getByHierarchicalName(_sParentFolder),UNO_QUERY);
1292         xNameAccess.set(xChild,UNO_QUERY);
1293         if ( !xNameAccess.is() && xChild.is() )
1294             xNameAccess.set(xChild->getParent(),UNO_QUERY);
1295     }
1296 
1297     OSL_ENSURE( xNameAccess.is(), "insertHierachyElement: could not find the proper name container!" );
1298     if ( !xNameAccess.is() )
1299         return false;
1300 
1301     OUString sNewName;
1302     Reference<XPropertySet> xProp(_xContent,UNO_QUERY);
1303     if ( xProp.is() )
1304         xProp->getPropertyValue(PROPERTY_NAME) >>= sNewName;
1305 
1306     if ( !_bMove || sNewName.isEmpty() )
1307     {
1308         OUString sTargetName,sLabel;
1309         if ( sNewName.isEmpty() || xNameAccess->hasByName(sNewName) )
1310         {
1311             if ( !sNewName.isEmpty() )
1312                 sTargetName = sNewName;
1313             else
1314                 sTargetName = DBA_RES( _bCollection ? STR_NEW_FOLDER : ((_bForm) ? RID_STR_FORM : RID_STR_REPORT));
1315             sLabel = DBA_RES( _bCollection ? STR_FOLDER_LABEL  : ((_bForm) ? STR_FRM_LABEL : STR_RPT_LABEL));
1316             sTargetName = ::dbtools::createUniqueName(xNameAccess,sTargetName);
1317 
1318             // here we have everything needed to create a new query object ...
1319             HierarchicalNameCheck aNameChecker( _xNames.get(), _sParentFolder );
1320             // ... ehm, except a new name
1321             OSaveAsDlg aAskForName(pParent,
1322                                    _rxContext,
1323                                    sTargetName,
1324                                    sLabel,
1325                                    aNameChecker,
1326                                    SADFlags::AdditionalDescription | SADFlags::TitlePasteAs);
1327             if ( RET_OK != aAskForName.run() )
1328                 // cancelled by the user
1329                 return false;
1330 
1331             sNewName = aAskForName.getName();
1332         }
1333     }
1334     else if ( xNameAccess->hasByName(sNewName) )
1335     {
1336         OUString sError(DBA_RES(STR_NAME_ALREADY_EXISTS));
1337         sError = sError.replaceFirst("#",sNewName);
1338         throw SQLException(sError,nullptr,"S1000",0,Any());
1339     }
1340 
1341     try
1342     {
1343         Reference<XMultiServiceFactory> xORB( xNameAccess, UNO_QUERY_THROW );
1344         uno::Sequence<uno::Any> aArguments(comphelper::InitAnyPropertySequence(
1345         {
1346             {"Name", uno::Any(sNewName)}, // set as folder
1347             {"Parent", uno::Any(xNameAccess)},
1348             {PROPERTY_EMBEDDEDOBJECT, uno::Any(_xContent)},
1349         }));
1350         OUString sServiceName(_bCollection ? (_bForm ? OUString(SERVICE_NAME_FORM_COLLECTION) : OUString(SERVICE_NAME_REPORT_COLLECTION)) : OUString(SERVICE_SDB_DOCUMENTDEFINITION));
1351 
1352         Reference<XContent > xNew( xORB->createInstanceWithArguments( sServiceName, aArguments ), UNO_QUERY_THROW );
1353         Reference< XNameContainer > xNameContainer( xNameAccess, UNO_QUERY_THROW );
1354         xNameContainer->insertByName( sNewName, makeAny( xNew ) );
1355     }
1356     catch( const IllegalArgumentException& e )
1357     {
1358         ::dbtools::throwGenericSQLException( e.Message, e.Context );
1359     }
1360     catch( const Exception& )
1361     {
1362         DBG_UNHANDLED_EXCEPTION("dbaccess");
1363         return false;
1364     }
1365 
1366     return true;
1367 }
1368 
1369 Reference< XNumberFormatter > getNumberFormatter(const Reference< XConnection >& _rxConnection, const Reference< css::uno::XComponentContext >& _rxContext )
1370 {
1371     // create a formatter working with the connections format supplier
1372     Reference< XNumberFormatter > xFormatter;
1373 
1374     try
1375     {
1376         Reference< css::util::XNumberFormatsSupplier >  xSupplier(::dbtools::getNumberFormats(_rxConnection, true, _rxContext));
1377 
1378         if ( xSupplier.is() )
1379         {
1380             // create a new formatter
1381             xFormatter.set(util::NumberFormatter::create( _rxContext ), UNO_QUERY_THROW);
1382             xFormatter->attachNumberFormatsSupplier(xSupplier);
1383         }
1384     }
1385     catch(const Exception&)
1386     {
1387         DBG_UNHANDLED_EXCEPTION("dbaccess");
1388     }
1389     return xFormatter;
1390 }
1391 
1392 } // dbaui
1393 
1394 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1395