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 <connectivity/CommonTools.hxx>
21 #include <TConnection.hxx>
22 #include <ParameterCont.hxx>
23 
24 #include <com/sun/star/awt/XWindow.hpp>
25 #include <com/sun/star/beans/NamedValue.hpp>
26 #include <com/sun/star/beans/PropertyAttribute.hpp>
27 #include <com/sun/star/container/XChild.hpp>
28 #include <com/sun/star/form/FormComponentType.hpp>
29 #include <com/sun/star/io/XInputStream.hpp>
30 #include <com/sun/star/lang/DisposedException.hpp>
31 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
32 #include <com/sun/star/lang/XInitialization.hpp>
33 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
34 #include <com/sun/star/sdb/DatabaseContext.hpp>
35 #include <com/sun/star/sdb/BooleanComparisonMode.hpp>
36 #include <com/sun/star/sdb/CommandType.hpp>
37 #include <com/sun/star/sdb/ErrorMessageDialog.hpp>
38 #include <com/sun/star/sdb/ParametersRequest.hpp>
39 #include <com/sun/star/sdb/RowSetVetoException.hpp>
40 #include <com/sun/star/sdb/SQLContext.hpp>
41 #include <com/sun/star/sdb/XCompletedConnection.hpp>
42 #include <com/sun/star/sdb/XInteractionSupplyParameters.hpp>
43 #include <com/sun/star/sdb/XOfficeDatabaseDocument.hpp>
44 #include <com/sun/star/sdb/XParametersSupplier.hpp>
45 #include <com/sun/star/sdb/XQueriesSupplier.hpp>
46 #include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
47 #include <com/sun/star/sdbc/ConnectionPool.hpp>
48 #include <com/sun/star/sdbc/DataType.hpp>
49 #include <com/sun/star/sdbc/XConnection.hpp>
50 #include <com/sun/star/sdbc/XDataSource.hpp>
51 #include <com/sun/star/sdbc/XParameters.hpp>
52 #include <com/sun/star/sdbc/XRow.hpp>
53 #include <com/sun/star/sdbc/XRowSet.hpp>
54 #include <com/sun/star/sdbc/XRowUpdate.hpp>
55 #include <com/sun/star/sdbcx/KeyType.hpp>
56 #include <com/sun/star/sdbcx/Privilege.hpp>
57 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
58 #include <com/sun/star/sdbcx/XKeysSupplier.hpp>
59 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
60 #include <com/sun/star/task/InteractionHandler.hpp>
61 #include <com/sun/star/task/XInteractionRequest.hpp>
62 #include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
63 #include <com/sun/star/util/NumberFormat.hpp>
64 #include <com/sun/star/util/NumberFormatsSupplier.hpp>
65 #include <com/sun/star/util/XNumberFormatTypes.hpp>
66 
67 #include <comphelper/extract.hxx>
68 #include <comphelper/interaction.hxx>
69 #include <comphelper/property.hxx>
70 #include <comphelper/propertysequence.hxx>
71 #include <comphelper/types.hxx>
72 #include <connectivity/conncleanup.hxx>
73 #include <connectivity/dbconversion.hxx>
74 #include <connectivity/dbexception.hxx>
75 #include <connectivity/dbtools.hxx>
76 #include <connectivity/statementcomposer.hxx>
77 #include <o3tl/any.hxx>
78 #include <o3tl/safeint.hxx>
79 #include <osl/diagnose.h>
80 #include <rtl/ustrbuf.hxx>
81 #include <sal/log.hxx>
82 #include <tools/diagnose_ex.h>
83 #include <tools/stream.hxx>
84 #include <cppuhelper/implbase.hxx>
85 #include <strings.hrc>
86 #include <resource/sharedresources.hxx>
87 
88 #include <algorithm>
89 #include <iterator>
90 #include <set>
91 
92 using namespace ::comphelper;
93 using namespace ::com::sun::star::uno;
94 using namespace ::com::sun::star::io;
95 using namespace ::com::sun::star::awt;
96 using namespace ::com::sun::star::ui::dialogs;
97 using namespace ::com::sun::star::util;
98 using namespace ::com::sun::star::lang;
99 using namespace ::com::sun::star::beans;
100 using namespace ::com::sun::star::container;
101 using namespace ::com::sun::star::sdb;
102 using namespace ::com::sun::star::sdbc;
103 using namespace ::com::sun::star::sdbcx;
104 using namespace ::com::sun::star::task;
105 using namespace ::com::sun::star::form;
106 using namespace connectivity;
107 
108 namespace dbtools
109 {
110 
111 namespace
112 {
113     typedef sal_Bool (SAL_CALL XDatabaseMetaData::*FMetaDataSupport)();
114 }
115 
116 sal_Int32 getDefaultNumberFormat(const Reference< XPropertySet >& _xColumn,
117                                  const Reference< XNumberFormatTypes >& _xTypes,
118                                  const Locale& _rLocale)
119 {
120     OSL_ENSURE(_xTypes.is() && _xColumn.is(), "dbtools::getDefaultNumberFormat: invalid arg !");
121     if (!_xTypes.is() || !_xColumn.is())
122         return NumberFormat::UNDEFINED;
123 
124     sal_Int32 nDataType = 0;
125     sal_Int32 nScale = 0;
126     try
127     {
128         // determine the datatype of the column
129         _xColumn->getPropertyValue("Type") >>= nDataType;
130 
131         if (DataType::NUMERIC == nDataType || DataType::DECIMAL == nDataType)
132             _xColumn->getPropertyValue("Scale") >>= nScale;
133     }
134     catch (Exception&)
135     {
136         return NumberFormat::UNDEFINED;
137     }
138     return getDefaultNumberFormat(nDataType,
139                     nScale,
140                     ::cppu::any2bool(_xColumn->getPropertyValue("IsCurrency")),
141                     _xTypes,
142                     _rLocale);
143 }
144 
145 sal_Int32 getDefaultNumberFormat(sal_Int32 _nDataType,
146                                  sal_Int32 _nScale,
147                                  bool _bIsCurrency,
148                                  const Reference< XNumberFormatTypes >& _xTypes,
149                                  const Locale& _rLocale)
150 {
151     OSL_ENSURE(_xTypes.is() , "dbtools::getDefaultNumberFormat: invalid arg !");
152     if (!_xTypes.is())
153         return NumberFormat::UNDEFINED;
154 
155     sal_Int32 nFormat = 0;
156     sal_Int32 nNumberType   = _bIsCurrency ? NumberFormat::CURRENCY : NumberFormat::NUMBER;
157     switch (_nDataType)
158     {
159         case DataType::BIT:
160         case DataType::BOOLEAN:
161             nFormat = _xTypes->getStandardFormat(NumberFormat::LOGICAL, _rLocale);
162             break;
163         case DataType::TINYINT:
164         case DataType::SMALLINT:
165         case DataType::INTEGER:
166         case DataType::BIGINT:
167         case DataType::FLOAT:
168         case DataType::REAL:
169         case DataType::DOUBLE:
170         case DataType::NUMERIC:
171         case DataType::DECIMAL:
172         {
173             try
174             {
175                 nFormat = _xTypes->getStandardFormat(static_cast<sal_Int16>(nNumberType), _rLocale);
176                 if(_nScale > 0)
177                 {
178                     // generate a new format if necessary
179                     Reference< XNumberFormats > xFormats(_xTypes, UNO_QUERY);
180                     OUString sNewFormat = xFormats->generateFormat( 0, _rLocale, false, false, static_cast<sal_Int16>(_nScale), 1);
181 
182                     // and add it to the formatter if necessary
183                     nFormat = xFormats->queryKey(sNewFormat, _rLocale, false);
184                     if (nFormat == sal_Int32(-1))
185                         nFormat = xFormats->addNew(sNewFormat, _rLocale);
186                 }
187             }
188             catch (Exception&)
189             {
190                 nFormat = _xTypes->getStandardFormat(static_cast<sal_Int16>(nNumberType), _rLocale);
191             }
192         }   break;
193         case DataType::CHAR:
194         case DataType::VARCHAR:
195         case DataType::LONGVARCHAR:
196         case DataType::CLOB:
197             nFormat = _xTypes->getStandardFormat(NumberFormat::TEXT, _rLocale);
198             break;
199         case DataType::DATE:
200             nFormat = _xTypes->getStandardFormat(NumberFormat::DATE, _rLocale);
201             break;
202         case DataType::TIME:
203             nFormat = _xTypes->getStandardFormat(NumberFormat::TIME, _rLocale);
204             break;
205         case DataType::TIMESTAMP:
206             nFormat = _xTypes->getStandardFormat(NumberFormat::DATETIME, _rLocale);
207             break;
208         case DataType::BINARY:
209         case DataType::VARBINARY:
210         case DataType::LONGVARBINARY:
211         case DataType::SQLNULL:
212         case DataType::OTHER:
213         case DataType::OBJECT:
214         case DataType::DISTINCT:
215         case DataType::STRUCT:
216         case DataType::ARRAY:
217         case DataType::BLOB:
218         case DataType::REF:
219         default:
220             nFormat = _xTypes->getStandardFormat(NumberFormat::UNDEFINED, _rLocale);
221     }
222     return nFormat;
223 }
224 
225 static Reference< XConnection> findConnection(const Reference< XInterface >& xParent)
226 {
227     Reference< XConnection> xConnection(xParent, UNO_QUERY);
228     if (!xConnection.is())
229     {
230         Reference< XChild> xChild(xParent, UNO_QUERY);
231         if (xChild.is())
232             xConnection = findConnection(xChild->getParent());
233     }
234     return xConnection;
235 }
236 
237 static Reference< XDataSource> getDataSource_allowException(
238             const OUString& _rsTitleOrPath,
239             const Reference< XComponentContext >& _rxContext )
240 {
241     ENSURE_OR_RETURN( !_rsTitleOrPath.isEmpty(), "getDataSource_allowException: invalid arg !", nullptr );
242 
243     Reference< XDatabaseContext> xDatabaseContext = DatabaseContext::create(_rxContext);
244 
245     return Reference< XDataSource >( xDatabaseContext->getByName( _rsTitleOrPath ), UNO_QUERY );
246 }
247 
248 Reference< XDataSource > getDataSource(
249             const OUString& _rsTitleOrPath,
250             const Reference< XComponentContext >& _rxContext )
251 {
252     Reference< XDataSource > xDS;
253     try
254     {
255         xDS = getDataSource_allowException( _rsTitleOrPath, _rxContext );
256     }
257     catch( const Exception& )
258     {
259         DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
260     }
261 
262     return xDS;
263 }
264 
265 static Reference< XConnection > getConnection_allowException(
266             const OUString& _rsTitleOrPath,
267             const OUString& _rsUser,
268             const OUString& _rsPwd,
269             const Reference< XComponentContext>& _rxContext,
270             const Reference< XWindow >& _rxParent)
271 {
272     Reference< XDataSource> xDataSource( getDataSource_allowException(_rsTitleOrPath, _rxContext) );
273     Reference<XConnection> xConnection;
274     if (xDataSource.is())
275     {
276 
277         //set ParentWindow for dialog, but just for the duration of this
278         //call, undo at end of scope
279         Reference<XInitialization> xIni(xDataSource, UNO_QUERY);
280         if (xIni.is())
281         {
282             Sequence< Any > aArgs(1);
283             NamedValue aParam( "ParentWindow", makeAny(_rxParent) );
284             aArgs[0] <<= aParam;
285             xIni->initialize(aArgs);
286         }
287 
288         // do it with interaction handler
289         if(_rsUser.isEmpty() || _rsPwd.isEmpty())
290         {
291             Reference<XPropertySet> xProp(xDataSource,UNO_QUERY);
292             OUString sPwd, sUser;
293             bool bPwdReq = false;
294             try
295             {
296                 xProp->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PASSWORD)) >>= sPwd;
297                 bPwdReq = ::cppu::any2bool(xProp->getPropertyValue("IsPasswordRequired"));
298                 xProp->getPropertyValue("User") >>= sUser;
299             }
300             catch(Exception&)
301             {
302                 OSL_FAIL("dbtools::getConnection: error while retrieving data source properties!");
303             }
304             if(bPwdReq && sPwd.isEmpty())
305             {   // password required, but empty -> connect using an interaction handler
306                 Reference<XCompletedConnection> xConnectionCompletion(xProp, UNO_QUERY);
307                 if (xConnectionCompletion.is())
308                 {   // instantiate the default SDB interaction handler
309                     Reference< XInteractionHandler > xHandler =
310                         InteractionHandler::createWithParent(_rxContext, _rxParent);
311                     xConnection = xConnectionCompletion->connectWithCompletion(xHandler);
312                 }
313             }
314             else
315                 xConnection = xDataSource->getConnection(sUser, sPwd);
316         }
317         if(!xConnection.is()) // try to get one if not already have one, just to make sure
318             xConnection = xDataSource->getConnection(_rsUser, _rsPwd);
319 
320         if (xIni.is())
321         {
322             Sequence< Any > aArgs(1);
323             NamedValue aParam( "ParentWindow", makeAny(Reference<XWindow>()) );
324             aArgs[0] <<= aParam;
325             xIni->initialize(aArgs);
326         }
327 
328     }
329     return xConnection;
330 }
331 
332 Reference< XConnection> getConnection_withFeedback(const OUString& _rDataSourceName,
333         const OUString& _rUser, const OUString& _rPwd, const Reference< XComponentContext>& _rxContext,
334         const Reference< XWindow >& _rxParent)
335 {
336     Reference< XConnection > xReturn;
337     try
338     {
339         xReturn = getConnection_allowException(_rDataSourceName, _rUser, _rPwd, _rxContext, _rxParent);
340     }
341     catch(SQLException&)
342     {
343         // allowed to pass
344         throw;
345     }
346     catch(Exception&)
347     {
348         TOOLS_WARN_EXCEPTION( "connectivity.commontools", "::dbtools::getConnection_withFeedback: unexpected (non-SQL) exception caught!");
349     }
350     return xReturn;
351 }
352 
353 Reference< XConnection> getConnection(const Reference< XRowSet>& _rxRowSet)
354 {
355     Reference< XConnection> xReturn;
356     Reference< XPropertySet> xRowSetProps(_rxRowSet, UNO_QUERY);
357     if (xRowSetProps.is())
358         xRowSetProps->getPropertyValue("ActiveConnection") >>= xReturn;
359     return xReturn;
360 }
361 
362 // helper function which allows to implement both the connectRowset and the ensureRowSetConnection semantics
363 // if connectRowset (which is deprecated) is removed, this function and one of its parameters are
364 // not needed anymore, the whole implementation can be moved into ensureRowSetConnection then)
365 static SharedConnection lcl_connectRowSet(const Reference< XRowSet>& _rxRowSet, const Reference< XComponentContext >& _rxContext,
366         bool _bAttachAutoDisposer, const Reference< XWindow >& _rxParent)
367 {
368     SharedConnection xConnection;
369 
370     do
371     {
372         Reference< XPropertySet> xRowSetProps(_rxRowSet, UNO_QUERY);
373         if ( !xRowSetProps.is() )
374             break;
375 
376         // 1. already connected?
377         Reference< XConnection > xExistingConn(
378             xRowSetProps->getPropertyValue("ActiveConnection"),
379             UNO_QUERY );
380 
381         if  (   xExistingConn.is()
382             // 2. embedded in a database?
383             ||  isEmbeddedInDatabase( _rxRowSet, xExistingConn )
384             // 3. is there a connection in the parent hierarchy?
385             ||  ( xExistingConn = findConnection( _rxRowSet ) ).is()
386             )
387         {
388             xRowSetProps->setPropertyValue("ActiveConnection", makeAny( xExistingConn ) );
389             // no auto disposer needed, since we did not create the connection
390 
391             xConnection.reset( xExistingConn, SharedConnection::NoTakeOwnership );
392             break;
393         }
394 
395         // build a connection with its current settings (4. data source name, or 5. URL)
396 
397         const OUString sUserProp( "User" );
398         OUString sDataSourceName;
399         xRowSetProps->getPropertyValue("DataSourceName") >>= sDataSourceName;
400         OUString sURL;
401         xRowSetProps->getPropertyValue("URL") >>= sURL;
402 
403         Reference< XConnection > xPureConnection;
404         if (!sDataSourceName.isEmpty())
405         {   // the row set's data source property is set
406             // -> try to connect, get user and pwd setting for that
407             OUString sUser, sPwd;
408 
409             if (hasProperty(sUserProp, xRowSetProps))
410                 xRowSetProps->getPropertyValue(sUserProp) >>= sUser;
411             if (hasProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PASSWORD), xRowSetProps))
412                 xRowSetProps->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PASSWORD)) >>= sPwd;
413 
414             xPureConnection = getConnection_allowException( sDataSourceName, sUser, sPwd, _rxContext, _rxParent );
415         }
416         else if (!sURL.isEmpty())
417         {   // the row set has no data source, but a connection url set
418             // -> try to connection with that url
419             Reference< XConnectionPool > xDriverManager;
420             try {
421                 xDriverManager = ConnectionPool::create( _rxContext );
422             } catch( const Exception& ) {  }
423             if (xDriverManager.is())
424             {
425                 OUString sUser, sPwd;
426                 if (hasProperty(sUserProp, xRowSetProps))
427                     xRowSetProps->getPropertyValue(sUserProp) >>= sUser;
428                 if (hasProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PASSWORD), xRowSetProps))
429                     xRowSetProps->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PASSWORD)) >>= sPwd;
430                 if (!sUser.isEmpty())
431                 {   // use user and pwd together with the url
432                     auto aInfo(::comphelper::InitPropertySequence({
433                         { "user", makeAny(sUser) },
434                         { "password", makeAny(sPwd) }
435                     }));
436                     xPureConnection = xDriverManager->getConnectionWithInfo( sURL, aInfo );
437                 }
438                 else
439                     // just use the url
440                     xPureConnection = xDriverManager->getConnection( sURL );
441             }
442         }
443         xConnection.reset(
444             xPureConnection,
445             _bAttachAutoDisposer ? SharedConnection::NoTakeOwnership : SharedConnection::TakeOwnership
446             /* take ownership if and only if we're *not* going to auto-dispose the connection */
447         );
448 
449         // now if we created a connection, forward it to the row set
450         if ( xConnection.is() )
451         {
452             try
453             {
454                 if ( _bAttachAutoDisposer )
455                 {
456                     new OAutoConnectionDisposer( _rxRowSet, xConnection );
457                 }
458                 else
459                     xRowSetProps->setPropertyValue(
460                         "ActiveConnection",
461                         makeAny( xConnection.getTyped() )
462                     );
463             }
464             catch(Exception&)
465             {
466                 TOOLS_WARN_EXCEPTION( "connectivity.commontools", "EXception when we set the new active connection!");
467             }
468         }
469     }
470     while ( false );
471 
472     return xConnection;
473 }
474 
475 Reference< XConnection> connectRowset(const Reference< XRowSet>& _rxRowSet, const Reference< XComponentContext >& _rxContext, const Reference< XWindow >& _rxParent)
476 {
477     SharedConnection xConnection = lcl_connectRowSet( _rxRowSet, _rxContext, true, _rxParent );
478     return xConnection.getTyped();
479 }
480 
481 SharedConnection ensureRowSetConnection(const Reference< XRowSet>& _rxRowSet, const Reference< XComponentContext>& _rxContext, const Reference< XWindow >& _rxParent)
482 {
483     return lcl_connectRowSet( _rxRowSet, _rxContext, false/*bUseAutoConnectionDisposer*/, _rxParent );
484 }
485 
486 Reference< XNameAccess> getTableFields(const Reference< XConnection>& _rxConn,const OUString& _rName)
487 {
488     Reference< XComponent > xDummy;
489     return getFieldsByCommandDescriptor( _rxConn, CommandType::TABLE, _rName, xDummy );
490 }
491 
492 Reference< XNameAccess> getPrimaryKeyColumns_throw(const Any& i_aTable)
493 {
494     const Reference< XPropertySet > xTable(i_aTable,UNO_QUERY_THROW);
495     return getPrimaryKeyColumns_throw(xTable);
496 }
497 
498 Reference< XNameAccess> getPrimaryKeyColumns_throw(const Reference< XPropertySet >& i_xTable)
499 {
500     Reference<XNameAccess> xKeyColumns;
501     const Reference<XKeysSupplier> xKeySup(i_xTable,UNO_QUERY);
502     if ( xKeySup.is() )
503     {
504         const Reference<XIndexAccess> xKeys = xKeySup->getKeys();
505         if ( xKeys.is() )
506         {
507             ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap();
508             const OUString& sPropName = rPropMap.getNameByIndex(PROPERTY_ID_TYPE);
509             Reference<XPropertySet> xProp;
510             const sal_Int32 nCount = xKeys->getCount();
511             for(sal_Int32 i = 0;i< nCount;++i)
512             {
513                 xProp.set(xKeys->getByIndex(i),UNO_QUERY_THROW);
514                 sal_Int32 nKeyType = 0;
515                 xProp->getPropertyValue(sPropName) >>= nKeyType;
516                 if(KeyType::PRIMARY == nKeyType)
517                 {
518                     const Reference<XColumnsSupplier> xKeyColsSup(xProp,UNO_QUERY_THROW);
519                     xKeyColumns = xKeyColsSup->getColumns();
520                     break;
521                 }
522             }
523         }
524     }
525 
526     return xKeyColumns;
527 }
528 
529 namespace
530 {
531     enum FieldLookupState
532     {
533         HANDLE_TABLE, HANDLE_QUERY, HANDLE_SQL, RETRIEVE_OBJECT, RETRIEVE_COLUMNS, DONE, FAILED
534     };
535 }
536 
537 Reference< XNameAccess > getFieldsByCommandDescriptor( const Reference< XConnection >& _rxConnection,
538     const sal_Int32 _nCommandType, const OUString& _rCommand,
539     Reference< XComponent >& _rxKeepFieldsAlive, SQLExceptionInfo* _pErrorInfo )
540 {
541     OSL_PRECOND( _rxConnection.is(), "::dbtools::getFieldsByCommandDescriptor: invalid connection!" );
542     OSL_PRECOND( ( CommandType::TABLE == _nCommandType ) || ( CommandType::QUERY == _nCommandType ) || ( CommandType::COMMAND == _nCommandType ),
543         "::dbtools::getFieldsByCommandDescriptor: invalid command type!" );
544     OSL_PRECOND( !_rCommand.isEmpty(), "::dbtools::getFieldsByCommandDescriptor: invalid command (empty)!" );
545 
546     Reference< XNameAccess > xFields;
547 
548     // reset the error
549     if ( _pErrorInfo )
550         *_pErrorInfo = SQLExceptionInfo();
551     // reset the ownership holder
552     _rxKeepFieldsAlive.clear();
553 
554     // go for the fields
555     try
556     {
557         // some kind of state machine to ease the sharing of code
558         FieldLookupState eState = FAILED;
559         switch ( _nCommandType )
560         {
561             case CommandType::TABLE:
562                 eState = HANDLE_TABLE;
563                 break;
564             case CommandType::QUERY:
565                 eState = HANDLE_QUERY;
566                 break;
567             case CommandType::COMMAND:
568                 eState = HANDLE_SQL;
569                 break;
570         }
571 
572         // needed in various states:
573         Reference< XNameAccess > xObjectCollection;
574         Reference< XColumnsSupplier > xSupplyColumns;
575 
576         // go!
577         while ( ( DONE != eState ) && ( FAILED != eState ) )
578         {
579             switch ( eState )
580             {
581                 case HANDLE_TABLE:
582                 {
583                     // initial state for handling the tables
584 
585                     // get the table objects
586                     Reference< XTablesSupplier > xSupplyTables( _rxConnection, UNO_QUERY );
587                     if ( xSupplyTables.is() )
588                         xObjectCollection = xSupplyTables->getTables();
589                     // if something went wrong 'til here, then this will be handled in the next state
590 
591                     // next state: get the object
592                     eState = RETRIEVE_OBJECT;
593                 }
594                 break;
595 
596                 case HANDLE_QUERY:
597                 {
598                     // initial state for handling the tables
599 
600                     // get the table objects
601                     Reference< XQueriesSupplier > xSupplyQueries( _rxConnection, UNO_QUERY );
602                     if ( xSupplyQueries.is() )
603                         xObjectCollection = xSupplyQueries->getQueries();
604                     // if something went wrong 'til here, then this will be handled in the next state
605 
606                     // next state: get the object
607                     eState = RETRIEVE_OBJECT;
608                 }
609                 break;
610 
611                 case RETRIEVE_OBJECT:
612                     // here we should have an object (aka query or table) collection, and are going
613                     // to retrieve the desired object
614 
615                     // next state: default to FAILED
616                     eState = FAILED;
617 
618                     OSL_ENSURE( xObjectCollection.is(), "::dbtools::getFieldsByCommandDescriptor: invalid connection (no sdb.Connection, or no Tables-/QueriesSupplier)!");
619                     if ( xObjectCollection.is() && xObjectCollection->hasByName( _rCommand ) )
620                     {
621                         xObjectCollection->getByName( _rCommand ) >>= xSupplyColumns;
622                             // (xSupplyColumns being NULL will be handled in the next state)
623 
624                         // next: go for the columns
625                         eState = RETRIEVE_COLUMNS;
626                     }
627                     break;
628 
629                 case RETRIEVE_COLUMNS:
630                     OSL_ENSURE( xSupplyColumns.is(), "::dbtools::getFieldsByCommandDescriptor: could not retrieve the columns supplier!" );
631 
632                     // next state: default to FAILED
633                     eState = FAILED;
634 
635                     if ( xSupplyColumns.is() )
636                     {
637                         xFields = xSupplyColumns->getColumns();
638                         // that's it
639                         eState = DONE;
640                     }
641                     break;
642 
643                 case HANDLE_SQL:
644                 {
645                     OUString sStatementToExecute( _rCommand );
646 
647                     // well, the main problem here is to handle statements which contain a parameter
648                     // If we would simply execute a parametrized statement, then this will fail because
649                     // we cannot supply any parameter values.
650                     // Thus, we try to analyze the statement, and to append a WHERE 0=1 filter criterion
651                     // This should cause every driver to not really execute the statement, but to return
652                     // an empty result set with the proper structure. We then can use this result set
653                     // to retrieve the columns.
654 
655                     try
656                     {
657                         Reference< XMultiServiceFactory > xComposerFac( _rxConnection, UNO_QUERY );
658 
659                         if ( xComposerFac.is() )
660                         {
661                             Reference< XSingleSelectQueryComposer > xComposer(xComposerFac->createInstance("com.sun.star.sdb.SingleSelectQueryComposer"),UNO_QUERY);
662                             if ( xComposer.is() )
663                             {
664                                 xComposer->setQuery( sStatementToExecute );
665 
666                                 // Now set the filter to a dummy restriction which will result in an empty
667                                 // result set.
668                                 xComposer->setFilter( "0=1" );
669                                 sStatementToExecute = xComposer->getQuery( );
670                             }
671                         }
672                     }
673                     catch( const Exception& )
674                     {
675                         // silent this error, this was just a try. If we're here, we did not change sStatementToExecute,
676                         // so it will still be _rCommand, which then will be executed without being touched
677                     }
678 
679                     // now execute
680                     Reference< XPreparedStatement > xStatement = _rxConnection->prepareStatement( sStatementToExecute );
681                     // transfer ownership of this temporary object to the caller
682                     _rxKeepFieldsAlive.set(xStatement, css::uno::UNO_QUERY);
683 
684                     // set the "MaxRows" to 0. This is just in case our attempt to append a 0=1 filter
685                     // failed - in this case, the MaxRows restriction should at least ensure that there
686                     // is no data returned (which would be potentially expensive)
687                     Reference< XPropertySet > xStatementProps( xStatement,UNO_QUERY );
688                     try
689                     {
690                         if ( xStatementProps.is() )
691                             xStatementProps->setPropertyValue( "MaxRows",  makeAny( sal_Int32( 0 ) ) );
692                     }
693                     catch( const Exception& )
694                     {
695                         OSL_FAIL( "::dbtools::getFieldsByCommandDescriptor: could not set the MaxRows!" );
696                         // oh damn. Not much of a chance to recover, we will no retrieve the complete
697                         // full blown result set
698                     }
699 
700                     xSupplyColumns.set(xStatement->executeQuery(), css::uno::UNO_QUERY);
701                     // this should have given us a result set which does not contain any data, but
702                     // the structural information we need
703 
704                     // so the next state is to get the columns
705                     eState = RETRIEVE_COLUMNS;
706                 }
707                 break;
708 
709                 default:
710                     OSL_FAIL( "::dbtools::getFieldsByCommandDescriptor: oops! unhandled state here!" );
711                     eState = FAILED;
712             }
713         }
714     }
715     catch( const SQLContext& e ) { if ( _pErrorInfo ) *_pErrorInfo = SQLExceptionInfo( e ); }
716     catch( const SQLWarning& e ) { if ( _pErrorInfo ) *_pErrorInfo = SQLExceptionInfo( e ); }
717     catch( const SQLException& e ) { if ( _pErrorInfo ) *_pErrorInfo = SQLExceptionInfo( e ); }
718     catch( const Exception& )
719     {
720         TOOLS_WARN_EXCEPTION( "connectivity.commontools", "::dbtools::getFieldsByCommandDescriptor: caught an exception while retrieving the fields!" );
721     }
722 
723     return xFields;
724 }
725 
726 Sequence< OUString > getFieldNamesByCommandDescriptor( const Reference< XConnection >& _rxConnection,
727     const sal_Int32 _nCommandType, const OUString& _rCommand,
728     SQLExceptionInfo* _pErrorInfo )
729 {
730     // get the container for the fields
731     Reference< XComponent > xKeepFieldsAlive;
732     Reference< XNameAccess > xFieldContainer = getFieldsByCommandDescriptor( _rxConnection, _nCommandType, _rCommand, xKeepFieldsAlive, _pErrorInfo );
733 
734     // get the names of the fields
735     Sequence< OUString > aNames;
736     if ( xFieldContainer.is() )
737         aNames = xFieldContainer->getElementNames();
738 
739     // clean up any temporary objects which have been created
740     disposeComponent( xKeepFieldsAlive );
741 
742     // outta here
743     return aNames;
744 }
745 
746 SQLException prependErrorInfo( const SQLException& _rChainedException, const Reference< XInterface >& _rxContext,
747     const OUString& _rAdditionalError, const StandardSQLState _eSQLState )
748 {
749     return SQLException( _rAdditionalError, _rxContext,
750         _eSQLState == StandardSQLState::ERROR_UNSPECIFIED ? OUString() : getStandardSQLState( _eSQLState ),
751         0, makeAny( _rChainedException ) );
752 }
753 
754 namespace
755 {
756     struct NameComponentSupport
757     {
758         const bool  bCatalogs;
759         const bool  bSchemas;
760 
761         NameComponentSupport( const bool _bCatalogs, const bool _bSchemas )
762             :bCatalogs( _bCatalogs )
763             ,bSchemas( _bSchemas )
764         {
765         }
766     };
767 
768     NameComponentSupport lcl_getNameComponentSupport( const Reference< XDatabaseMetaData >& _rxMetaData, EComposeRule _eComposeRule )
769     {
770         OSL_PRECOND( _rxMetaData.is(), "lcl_getNameComponentSupport: invalid meta data!" );
771 
772         FMetaDataSupport pCatalogCall = &XDatabaseMetaData::supportsCatalogsInDataManipulation;
773         FMetaDataSupport pSchemaCall = &XDatabaseMetaData::supportsSchemasInDataManipulation;
774         bool bIgnoreMetaData = false;
775 
776         switch ( _eComposeRule )
777         {
778             case EComposeRule::InTableDefinitions:
779                 pCatalogCall = &XDatabaseMetaData::supportsCatalogsInTableDefinitions;
780                 pSchemaCall = &XDatabaseMetaData::supportsSchemasInTableDefinitions;
781                 break;
782             case EComposeRule::InIndexDefinitions:
783                 pCatalogCall = &XDatabaseMetaData::supportsCatalogsInIndexDefinitions;
784                 pSchemaCall = &XDatabaseMetaData::supportsSchemasInIndexDefinitions;
785                 break;
786             case EComposeRule::InProcedureCalls:
787                 pCatalogCall = &XDatabaseMetaData::supportsCatalogsInProcedureCalls;
788                 pSchemaCall = &XDatabaseMetaData::supportsSchemasInProcedureCalls;
789                 break;
790             case EComposeRule::InPrivilegeDefinitions:
791                 pCatalogCall = &XDatabaseMetaData::supportsCatalogsInPrivilegeDefinitions;
792                 pSchemaCall = &XDatabaseMetaData::supportsSchemasInPrivilegeDefinitions;
793                 break;
794             case EComposeRule::Complete:
795                 bIgnoreMetaData = true;
796                 break;
797             case EComposeRule::InDataManipulation:
798                 // already properly set above
799                 break;
800         }
801         return NameComponentSupport(
802             bIgnoreMetaData || (_rxMetaData.get()->*pCatalogCall)(),
803             bIgnoreMetaData || (_rxMetaData.get()->*pSchemaCall)()
804         );
805     }
806 }
807 
808 static OUString impl_doComposeTableName( const Reference< XDatabaseMetaData >& _rxMetaData,
809                 const OUString& _rCatalog, const OUString& _rSchema, const OUString& _rName,
810                 bool _bQuote, EComposeRule _eComposeRule )
811 {
812     OSL_ENSURE(_rxMetaData.is(), "impl_doComposeTableName : invalid meta data !");
813     if ( !_rxMetaData.is() )
814         return OUString();
815     OSL_ENSURE(!_rName.isEmpty(), "impl_doComposeTableName : at least the name should be non-empty !");
816 
817     const OUString sQuoteString = _rxMetaData->getIdentifierQuoteString();
818     const NameComponentSupport aNameComps( lcl_getNameComponentSupport( _rxMetaData, _eComposeRule ) );
819 
820     OUStringBuffer aComposedName;
821 
822     OUString sCatalogSep;
823     bool bCatlogAtStart = true;
824     if ( !_rCatalog.isEmpty() && aNameComps.bCatalogs )
825     {
826         sCatalogSep     = _rxMetaData->getCatalogSeparator();
827         bCatlogAtStart  = _rxMetaData->isCatalogAtStart();
828 
829         if ( bCatlogAtStart && !sCatalogSep.isEmpty())
830         {
831             aComposedName.append( _bQuote ? quoteName( sQuoteString, _rCatalog ) : _rCatalog );
832             aComposedName.append( sCatalogSep );
833         }
834     }
835 
836     if ( !_rSchema.isEmpty() && aNameComps.bSchemas )
837     {
838         aComposedName.append( _bQuote ? quoteName( sQuoteString, _rSchema ) : _rSchema );
839         aComposedName.append( "." );
840     }
841 
842     aComposedName.append( _bQuote ? quoteName( sQuoteString, _rName ) : _rName );
843 
844     if  (   !_rCatalog.isEmpty()
845         &&  !bCatlogAtStart
846         &&  !sCatalogSep.isEmpty()
847         &&  aNameComps.bCatalogs
848         )
849     {
850         aComposedName.append( sCatalogSep );
851         aComposedName.append( _bQuote ? quoteName( sQuoteString, _rCatalog ) : _rCatalog );
852     }
853 
854     return aComposedName.makeStringAndClear();
855 }
856 
857 OUString quoteTableName(const Reference< XDatabaseMetaData>& _rxMeta
858                                , const OUString& _rName
859                                , EComposeRule _eComposeRule)
860 {
861     OUString sCatalog, sSchema, sTable;
862     qualifiedNameComponents(_rxMeta,_rName,sCatalog,sSchema,sTable,_eComposeRule);
863     return impl_doComposeTableName( _rxMeta, sCatalog, sSchema, sTable, true, _eComposeRule );
864 }
865 
866 void qualifiedNameComponents(const Reference< XDatabaseMetaData >& _rxConnMetaData, const OUString& _rQualifiedName, OUString& _rCatalog, OUString& _rSchema, OUString& _rName,EComposeRule _eComposeRule)
867 {
868     OSL_ENSURE(_rxConnMetaData.is(), "QualifiedNameComponents : invalid meta data!");
869 
870     NameComponentSupport aNameComps( lcl_getNameComponentSupport( _rxConnMetaData, _eComposeRule ) );
871 
872     OUString sSeparator = _rxConnMetaData->getCatalogSeparator();
873 
874     OUString sName(_rQualifiedName);
875     // do we have catalogs?
876     if ( aNameComps.bCatalogs )
877     {
878         if (_rxConnMetaData->isCatalogAtStart())
879         {
880             // search for the catalog name at the beginning
881             sal_Int32 nIndex = sName.indexOf(sSeparator);
882             if (-1 != nIndex)
883             {
884                 _rCatalog = sName.copy(0, nIndex);
885                 sName = sName.copy(nIndex + 1);
886             }
887         }
888         else
889         {
890             // Catalog name at the end
891             sal_Int32 nIndex = sName.lastIndexOf(sSeparator);
892             if (-1 != nIndex)
893             {
894                 _rCatalog = sName.copy(nIndex + 1);
895                 sName = sName.copy(0, nIndex);
896             }
897         }
898     }
899 
900     if ( aNameComps.bSchemas )
901     {
902         sal_Int32 nIndex = sName.indexOf('.');
903         //  OSL_ENSURE(-1 != nIndex, "QualifiedNameComponents: no schema separator!");
904         if ( nIndex != -1 )
905             _rSchema = sName.copy(0, nIndex);
906         sName = sName.copy(nIndex + 1);
907     }
908 
909     _rName = sName;
910 }
911 
912 Reference< XNumberFormatsSupplier> getNumberFormats(
913             const Reference< XConnection>& _rxConn,
914             bool _bAlloweDefault,
915             const Reference< XComponentContext>& _rxContext)
916 {
917     // ask the parent of the connection (should be a DatabaseAccess)
918     Reference< XNumberFormatsSupplier> xReturn;
919     Reference< XChild> xConnAsChild(_rxConn, UNO_QUERY);
920     static const OUStringLiteral sPropFormatsSupplier( u"NumberFormatsSupplier" );
921     if (xConnAsChild.is())
922     {
923         Reference< XPropertySet> xConnParentProps(xConnAsChild->getParent(), UNO_QUERY);
924         if (xConnParentProps.is() && hasProperty(sPropFormatsSupplier, xConnParentProps))
925             xConnParentProps->getPropertyValue(sPropFormatsSupplier) >>= xReturn;
926     }
927     else if(_bAlloweDefault && _rxContext.is())
928     {
929         xReturn = NumberFormatsSupplier::createWithDefaultLocale( _rxContext );
930     }
931     return xReturn;
932 }
933 
934 void TransferFormComponentProperties(
935             const Reference< XPropertySet>& xOldProps,
936             const Reference< XPropertySet>& xNewProps,
937             const Locale& _rLocale)
938 {
939 try
940 {
941     OSL_ENSURE( xOldProps.is() && xNewProps.is(), "TransferFormComponentProperties: invalid source/dest!" );
942     if ( !xOldProps.is() || !xNewProps.is() )
943         return;
944 
945     // First we copy all the Props, that are available in source and target and have the same description
946     Reference< XPropertySetInfo> xOldInfo( xOldProps->getPropertySetInfo());
947     Reference< XPropertySetInfo> xNewInfo( xNewProps->getPropertySetInfo());
948 
949     const Sequence< Property> aOldProperties = xOldInfo->getProperties();
950     Sequence< Property> aNewProperties = xNewInfo->getProperties();
951     int nNewLen = aNewProperties.getLength();
952 
953     Property* pNewProps = aNewProperties.getArray();
954 
955     static const OUStringLiteral sPropFormatsSupplier(u"FormatsSupplier");
956     static const OUStringLiteral sPropCurrencySymbol(u"CurrencySymbol");
957     static const OUStringLiteral sPropDecimals(u"Decimals");
958     static const OUStringLiteral sPropEffectiveMin(u"EffectiveMin");
959     static const OUStringLiteral sPropEffectiveMax(u"EffectiveMax");
960     static const OUStringLiteral sPropEffectiveDefault(u"EffectiveDefault");
961     static const OUStringLiteral sPropDefaultText(u"DefaultText");
962     static const OUStringLiteral sPropDefaultDate(u"DefaultDate");
963     static const OUStringLiteral sPropDefaultTime(u"DefaultTime");
964     static const OUStringLiteral sPropValueMin(u"ValueMin");
965     static const OUStringLiteral sPropValueMax(u"ValueMax");
966     static const OUStringLiteral sPropDecimalAccuracy(u"DecimalAccuracy");
967     static const OUStringLiteral sPropClassId(u"ClassId");
968     static const OUStringLiteral sFormattedServiceName( u"com.sun.star.form.component.FormattedField" );
969 
970     for (const Property& rOldProp : aOldProperties)
971     {
972         if ( rOldProp.Name != "DefaultControl" && rOldProp.Name != "LabelControl" )
973         {
974             // binary search
975             Property* pResult = std::lower_bound(
976                 pNewProps, pNewProps + nNewLen, rOldProp, ::comphelper::PropertyCompareByName());
977 
978             if (   ( pResult != aNewProperties.end() )
979                 && ( pResult->Name == rOldProp.Name )
980                 && ( (pResult->Attributes & PropertyAttribute::READONLY) == 0 )
981                 && ( pResult->Type.equals(rOldProp.Type)) )
982             {   // Attributes match and the property is not read-only
983                 try
984                 {
985                     xNewProps->setPropertyValue(pResult->Name, xOldProps->getPropertyValue(pResult->Name));
986                 }
987                 catch(IllegalArgumentException const &)
988                 {
989                     TOOLS_WARN_EXCEPTION( "connectivity.commontools", "TransferFormComponentProperties : could not transfer the value for property \""
990                                 << pResult->Name << "\"");
991                 }
992             }
993         }
994     }
995 
996     // for formatted fields (either old or new) we have some special treatments
997     Reference< XServiceInfo > xSI( xOldProps, UNO_QUERY );
998     bool bOldIsFormatted = xSI.is() && xSI->supportsService( sFormattedServiceName );
999     xSI.set( xNewProps, UNO_QUERY );
1000     bool bNewIsFormatted = xSI.is() && xSI->supportsService( sFormattedServiceName );
1001 
1002     if (!bOldIsFormatted && !bNewIsFormatted)
1003         return; // nothing to do
1004 
1005     if (bOldIsFormatted && bNewIsFormatted)
1006         // if both fields are formatted we do no conversions
1007         return;
1008 
1009     if (bOldIsFormatted)
1010     {
1011         // get some properties from the selected format and put them in the new Set
1012         Any aFormatKey( xOldProps->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FORMATKEY)) );
1013         if (aFormatKey.hasValue())
1014         {
1015             Reference< XNumberFormatsSupplier> xSupplier;
1016             xOldProps->getPropertyValue(sPropFormatsSupplier) >>= xSupplier;
1017             if (xSupplier.is())
1018             {
1019                 Reference< XNumberFormats> xFormats(xSupplier->getNumberFormats());
1020                 Reference< XPropertySet> xFormat(xFormats->getByKey(getINT32(aFormatKey)));
1021                 if (hasProperty(sPropCurrencySymbol, xFormat))
1022                 {
1023                     Any aVal( xFormat->getPropertyValue(sPropCurrencySymbol) );
1024                     if (aVal.hasValue() && hasProperty(sPropCurrencySymbol, xNewProps))
1025                         // If the source value hasn't been set then don't copy it
1026                         // so we don't overwrite the default value
1027                         xNewProps->setPropertyValue(sPropCurrencySymbol, aVal);
1028                 }
1029                 if (hasProperty(sPropDecimals, xFormat) && hasProperty(sPropDecimals, xNewProps))
1030                     xNewProps->setPropertyValue(sPropDecimals, xFormat->getPropertyValue(sPropDecimals));
1031             }
1032         }
1033 
1034         // a potential Min-Max-Conversion
1035         Any aEffectiveMin( xOldProps->getPropertyValue(sPropEffectiveMin) );
1036         if (aEffectiveMin.hasValue())
1037         {   // Unlike the ValueMin the EffectiveMin can be void
1038             if (hasProperty(sPropValueMin, xNewProps))
1039             {
1040                 OSL_ENSURE(aEffectiveMin.getValueType().getTypeClass() == TypeClass_DOUBLE,
1041                     "TransferFormComponentProperties : invalid property type !");
1042                 xNewProps->setPropertyValue(sPropValueMin, aEffectiveMin);
1043             }
1044         }
1045         Any aEffectiveMax( xOldProps->getPropertyValue(sPropEffectiveMax) );
1046         if (aEffectiveMax.hasValue())
1047         {   // analog
1048             if (hasProperty(sPropValueMax, xNewProps))
1049             {
1050                 OSL_ENSURE(aEffectiveMax.getValueType().getTypeClass() == TypeClass_DOUBLE,
1051                     "TransferFormComponentProperties : invalid property type !");
1052                 xNewProps->setPropertyValue(sPropValueMax, aEffectiveMax);
1053             }
1054         }
1055 
1056         // then we can still convert and copy the default values
1057         Any aEffectiveDefault( xOldProps->getPropertyValue(sPropEffectiveDefault) );
1058         if (aEffectiveDefault.hasValue())
1059         {
1060             bool bIsString = aEffectiveDefault.getValueType().getTypeClass() == TypeClass_STRING;
1061             OSL_ENSURE(bIsString || aEffectiveDefault.getValueType().getTypeClass() == TypeClass_DOUBLE,
1062                 "TransferFormComponentProperties : invalid property type !");
1063                 // The Effective-Properties should always be void or string or double...
1064 
1065             if (hasProperty(sPropDefaultDate, xNewProps) && !bIsString)
1066             {   // (to convert an OUString into a date will not always succeed, because it might be bound to a text-column,
1067                 // but we can work with a double)
1068                 Date aDate = DBTypeConversion::toDate(getDouble(aEffectiveDefault));
1069                 xNewProps->setPropertyValue(sPropDefaultDate, makeAny(aDate));
1070             }
1071 
1072             if (hasProperty(sPropDefaultTime, xNewProps) && !bIsString)
1073             {   // Completely analogous to time
1074                 css::util::Time aTime = DBTypeConversion::toTime(getDouble(aEffectiveDefault));
1075                 xNewProps->setPropertyValue(sPropDefaultTime, makeAny(aTime));
1076             }
1077 
1078             if (hasProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DEFAULTVALUE), xNewProps) && !bIsString)
1079             {   // Here we can simply pass the double
1080                 xNewProps->setPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DEFAULTVALUE), aEffectiveDefault);
1081             }
1082 
1083             if (hasProperty(sPropDefaultText, xNewProps) && bIsString)
1084             {   // and here the OUString
1085                 xNewProps->setPropertyValue(sPropDefaultText, aEffectiveDefault);
1086             }
1087 
1088             // nyi: The translation between doubles and OUString would offer more alternatives
1089         }
1090     }
1091 
1092     // The other direction: the new Control shall be formatted
1093     if (bNewIsFormatted)
1094     {
1095         // first the formatting
1096         // we can't set a Supplier, so the new Set must bring one in
1097         Reference< XNumberFormatsSupplier> xSupplier;
1098         xNewProps->getPropertyValue(sPropFormatsSupplier) >>= xSupplier;
1099         if (xSupplier.is())
1100         {
1101             Reference< XNumberFormats> xFormats(xSupplier->getNumberFormats());
1102 
1103             // Set number of decimals
1104             sal_Int16 nDecimals = 2;
1105             if (hasProperty(sPropDecimalAccuracy, xOldProps))
1106                 xOldProps->getPropertyValue(sPropDecimalAccuracy) >>= nDecimals;
1107 
1108             // base format (depending on the ClassId of the old Set)
1109             sal_Int32 nBaseKey = 0;
1110             if (hasProperty(sPropClassId, xOldProps))
1111             {
1112                 Reference< XNumberFormatTypes> xTypeList(xFormats, UNO_QUERY);
1113                 if (xTypeList.is())
1114                 {
1115                     sal_Int16 nClassId = 0;
1116                     xOldProps->getPropertyValue(sPropClassId) >>= nClassId;
1117                     switch (nClassId)
1118                     {
1119                         case FormComponentType::DATEFIELD :
1120                             nBaseKey = xTypeList->getStandardFormat(NumberFormat::DATE, _rLocale);
1121                             break;
1122 
1123                         case FormComponentType::TIMEFIELD :
1124                             nBaseKey = xTypeList->getStandardFormat(NumberFormat::TIME, _rLocale);
1125                             break;
1126 
1127                         case FormComponentType::CURRENCYFIELD :
1128                             nBaseKey = xTypeList->getStandardFormat(NumberFormat::CURRENCY, _rLocale);
1129                             break;
1130                     }
1131                 }
1132             }
1133 
1134             // With this we can generate a new format ...
1135             OUString sNewFormat = xFormats->generateFormat(nBaseKey, _rLocale, false, false, nDecimals, 0);
1136             // No thousands separator, negative numbers are not in red, no leading zeros
1137 
1138             // ... and add at FormatsSupplier (if needed)
1139             sal_Int32 nKey = xFormats->queryKey(sNewFormat, _rLocale, false);
1140             if (nKey == sal_Int32(-1))
1141             {   // not added yet in my formatter ...
1142                 nKey = xFormats->addNew(sNewFormat, _rLocale);
1143             }
1144 
1145             xNewProps->setPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FORMATKEY), makeAny(nKey));
1146         }
1147 
1148         // min-/max-Value
1149         Any aNewMin, aNewMax;
1150         if (hasProperty(sPropValueMin, xOldProps))
1151             aNewMin = xOldProps->getPropertyValue(sPropValueMin);
1152         if (hasProperty(sPropValueMax, xOldProps))
1153             aNewMax = xOldProps->getPropertyValue(sPropValueMax);
1154         xNewProps->setPropertyValue(sPropEffectiveMin, aNewMin);
1155         xNewProps->setPropertyValue(sPropEffectiveMax, aNewMax);
1156 
1157         // Default-Value
1158         Any aNewDefault;
1159         if (hasProperty(sPropDefaultDate, xOldProps))
1160         {
1161             Any aDate( xOldProps->getPropertyValue(sPropDefaultDate) );
1162             if (aDate.hasValue())
1163                 aNewDefault <<= DBTypeConversion::toDouble(*o3tl::doAccess<Date>(aDate));
1164         }
1165 
1166         if (hasProperty(sPropDefaultTime, xOldProps))
1167         {
1168             Any aTime( xOldProps->getPropertyValue(sPropDefaultTime) );
1169             if (aTime.hasValue())
1170                 aNewDefault <<= DBTypeConversion::toDouble(*o3tl::doAccess<Time>(aTime));
1171         }
1172 
1173         // double or OUString will be copied directly
1174         if (hasProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DEFAULTVALUE), xOldProps))
1175             aNewDefault = xOldProps->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DEFAULTVALUE));
1176         if (hasProperty(sPropDefaultText, xOldProps))
1177             aNewDefault = xOldProps->getPropertyValue(sPropDefaultText);
1178 
1179         if (aNewDefault.hasValue())
1180             xNewProps->setPropertyValue(sPropEffectiveDefault, aNewDefault);
1181     }
1182 }
1183 catch(const Exception&)
1184 {
1185     TOOLS_WARN_EXCEPTION( "connectivity.commontools", "TransferFormComponentProperties" );
1186 }
1187 }
1188 
1189 bool canInsert(const Reference< XPropertySet>& _rxCursorSet)
1190 {
1191     return (_rxCursorSet.is() && (getINT32(_rxCursorSet->getPropertyValue("Privileges")) & Privilege::INSERT) != 0);
1192 }
1193 
1194 bool canUpdate(const Reference< XPropertySet>& _rxCursorSet)
1195 {
1196     return (_rxCursorSet.is() && (getINT32(_rxCursorSet->getPropertyValue("Privileges")) & Privilege::UPDATE) != 0);
1197 }
1198 
1199 bool canDelete(const Reference< XPropertySet>& _rxCursorSet)
1200 {
1201     return (_rxCursorSet.is() && (getINT32(_rxCursorSet->getPropertyValue("Privileges")) & Privilege::DELETE) != 0);
1202 }
1203 
1204 Reference< XDataSource> findDataSource(const Reference< XInterface >& _xParent)
1205 {
1206     Reference< XOfficeDatabaseDocument> xDatabaseDocument(_xParent, UNO_QUERY);
1207     Reference< XDataSource> xDataSource;
1208     if ( xDatabaseDocument.is() )
1209         xDataSource = xDatabaseDocument->getDataSource();
1210     if ( !xDataSource.is() )
1211         xDataSource.set(_xParent, UNO_QUERY);
1212     if (!xDataSource.is())
1213     {
1214         Reference< XChild> xChild(_xParent, UNO_QUERY);
1215         if ( xChild.is() )
1216             xDataSource = findDataSource(xChild->getParent());
1217     }
1218     return xDataSource;
1219 }
1220 
1221 static Reference< XSingleSelectQueryComposer > getComposedRowSetStatement( const Reference< XPropertySet >& _rxRowSet, const Reference< XComponentContext >& _rxContext, const Reference< XWindow >& _rxParent )
1222 {
1223     Reference< XSingleSelectQueryComposer > xComposer;
1224     try
1225     {
1226         Reference< XConnection> xConn = connectRowset( Reference< XRowSet >( _rxRowSet, UNO_QUERY ), _rxContext, _rxParent );
1227         if ( xConn.is() )       // implies _rxRowSet.is()
1228         {
1229             // build the statement the row set is based on (can't use the ActiveCommand property of the set
1230             // as this reflects the status after the last execute, not the currently set properties)
1231 
1232             sal_Int32 nCommandType = CommandType::COMMAND;
1233             OUString sCommand;
1234             bool bEscapeProcessing = false;
1235 
1236             OSL_VERIFY( _rxRowSet->getPropertyValue("CommandType") >>= nCommandType      );
1237             OSL_VERIFY( _rxRowSet->getPropertyValue("Command") >>= sCommand          );
1238             OSL_VERIFY( _rxRowSet->getPropertyValue("EscapeProcessing") >>= bEscapeProcessing );
1239 
1240             StatementComposer aComposer( xConn, sCommand, nCommandType, bEscapeProcessing );
1241             // append sort
1242             aComposer.setOrder( getString( _rxRowSet->getPropertyValue("Order") ) );
1243 
1244             // append filter
1245             bool bApplyFilter = true;
1246             _rxRowSet->getPropertyValue("ApplyFilter") >>= bApplyFilter;
1247             if ( bApplyFilter )
1248             {
1249                 aComposer.setFilter( getString( _rxRowSet->getPropertyValue("Filter") ) );
1250                 aComposer.setHavingClause( getString( _rxRowSet->getPropertyValue("HavingClause") ) );
1251             }
1252 
1253             aComposer.getQuery();
1254 
1255             xComposer = aComposer.getComposer();
1256             aComposer.setDisposeComposer( false );
1257         }
1258     }
1259     catch( const SQLException& )
1260     {
1261         throw;
1262     }
1263     catch( const Exception& )
1264     {
1265         DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
1266     }
1267 
1268     return xComposer;
1269 }
1270 
1271 Reference< XSingleSelectQueryComposer > getCurrentSettingsComposer(
1272                 const Reference< XPropertySet>& _rxRowSetProps,
1273                 const Reference< XComponentContext>& _rxContext,
1274                 const Reference< XWindow >& _rxParent)
1275 {
1276     Reference< XSingleSelectQueryComposer > xReturn;
1277     try
1278     {
1279         xReturn = getComposedRowSetStatement( _rxRowSetProps, _rxContext, _rxParent );
1280     }
1281     catch( const SQLException& )
1282     {
1283         throw;
1284     }
1285     catch( const Exception& )
1286     {
1287         TOOLS_WARN_EXCEPTION( "connectivity.commontools", "::getCurrentSettingsComposer : caught an exception !" );
1288     }
1289 
1290     return xReturn;
1291 }
1292 
1293 OUString composeTableName( const Reference< XDatabaseMetaData >& _rxMetaData,
1294                         const OUString& _rCatalog,
1295                         const OUString& _rSchema,
1296                         const OUString& _rName,
1297                         bool _bQuote,
1298                         EComposeRule _eComposeRule)
1299 {
1300     return impl_doComposeTableName( _rxMetaData, _rCatalog, _rSchema, _rName, _bQuote, _eComposeRule );
1301 }
1302 
1303 OUString composeTableNameForSelect( const Reference< XConnection >& _rxConnection,
1304     const OUString& _rCatalog, const OUString& _rSchema, const OUString& _rName )
1305 {
1306     bool bUseCatalogInSelect = isDataSourcePropertyEnabled( _rxConnection, "UseCatalogInSelect", true );
1307     bool bUseSchemaInSelect = isDataSourcePropertyEnabled( _rxConnection, "UseSchemaInSelect", true );
1308 
1309     return impl_doComposeTableName(
1310         _rxConnection->getMetaData(),
1311         bUseCatalogInSelect ? _rCatalog : OUString(),
1312         bUseSchemaInSelect ? _rSchema : OUString(),
1313         _rName,
1314         true,
1315         EComposeRule::InDataManipulation
1316     );
1317 }
1318 
1319 namespace
1320 {
1321     void lcl_getTableNameComponents( const Reference<XPropertySet>& _xTable,
1322         OUString& _out_rCatalog, OUString& _out_rSchema, OUString& _out_rName )
1323     {
1324         ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap();
1325         Reference< XPropertySetInfo > xInfo;
1326         if (_xTable.is())
1327             xInfo = _xTable->getPropertySetInfo();
1328         if (    xInfo.is()
1329             &&  xInfo->hasPropertyByName(rPropMap.getNameByIndex(PROPERTY_ID_NAME)) )
1330         {
1331             if (    xInfo->hasPropertyByName(rPropMap.getNameByIndex(PROPERTY_ID_CATALOGNAME))
1332                 &&  xInfo->hasPropertyByName(rPropMap.getNameByIndex(PROPERTY_ID_SCHEMANAME)) )
1333             {
1334                 _xTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_CATALOGNAME)) >>= _out_rCatalog;
1335                 _xTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_SCHEMANAME))  >>= _out_rSchema;
1336             }
1337             _xTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME))        >>= _out_rName;
1338         }
1339         else
1340             OSL_FAIL( "::dbtools::lcl_getTableNameComponents: this is no table object!" );
1341     }
1342 }
1343 
1344 OUString composeTableNameForSelect( const Reference< XConnection >& _rxConnection, const Reference<XPropertySet>& _xTable )
1345 {
1346     OUString sCatalog, sSchema, sName;
1347     lcl_getTableNameComponents( _xTable, sCatalog, sSchema, sName );
1348 
1349     return composeTableNameForSelect( _rxConnection, sCatalog, sSchema, sName );
1350 }
1351 
1352 OUString composeTableName(const Reference<XDatabaseMetaData>& _xMetaData,
1353                                  const Reference<XPropertySet>& _xTable,
1354                                  EComposeRule _eComposeRule,
1355                                  bool _bQuote )
1356 {
1357     OUString sCatalog, sSchema, sName;
1358     lcl_getTableNameComponents( _xTable, sCatalog, sSchema, sName );
1359 
1360     return impl_doComposeTableName(
1361             _xMetaData,
1362             sCatalog,
1363             sSchema,
1364             sName,
1365             _bQuote,
1366             _eComposeRule
1367         );
1368 }
1369 
1370 sal_Int32 getSearchColumnFlag( const Reference< XConnection>& _rxConn,sal_Int32 _nDataType)
1371 {
1372     sal_Int32 nSearchFlag = 0;
1373     Reference<XResultSet> xSet = _rxConn->getMetaData()->getTypeInfo();
1374     if(xSet.is())
1375     {
1376         Reference<XRow> xRow(xSet,UNO_QUERY);
1377         while(xSet->next())
1378         {
1379             if(xRow->getInt(2) == _nDataType)
1380             {
1381                 nSearchFlag = xRow->getInt(9);
1382                 break;
1383             }
1384         }
1385     }
1386     return nSearchFlag;
1387 }
1388 
1389 OUString createUniqueName( const Sequence< OUString >& _rNames, const OUString& _rBaseName, bool _bStartWithNumber )
1390 {
1391     std::set< OUString > aUsedNames(_rNames.begin(), _rNames.end());
1392 
1393     OUString sName( _rBaseName );
1394     sal_Int32 nPos = 1;
1395     if ( _bStartWithNumber )
1396         sName += OUString::number( nPos );
1397 
1398     while ( aUsedNames.find( sName ) != aUsedNames.end() )
1399     {
1400         sName = _rBaseName + OUString::number( ++nPos );
1401     }
1402     return sName;
1403 }
1404 
1405 OUString createUniqueName(const Reference<XNameAccess>& _rxContainer,const OUString& _rBaseName, bool _bStartWithNumber)
1406 {
1407     Sequence< OUString > aElementNames;
1408 
1409     OSL_ENSURE( _rxContainer.is(), "createUniqueName: invalid container!" );
1410     if ( _rxContainer.is() )
1411         aElementNames = _rxContainer->getElementNames();
1412 
1413     return createUniqueName( aElementNames, _rBaseName, _bStartWithNumber );
1414 }
1415 
1416 void showError(const SQLExceptionInfo& _rInfo,
1417                const Reference< XWindow>& _xParent,
1418                const Reference< XComponentContext >& _rxContext)
1419 {
1420     if (_rInfo.isValid())
1421     {
1422         try
1423         {
1424             Reference< XExecutableDialog > xErrorDialog = ErrorMessageDialog::create( _rxContext, "", _xParent, _rInfo.get() );
1425             xErrorDialog->execute();
1426         }
1427         catch(const Exception&)
1428         {
1429             OSL_FAIL("showError: could not display the error message!");
1430         }
1431     }
1432 }
1433 
1434 bool implUpdateObject(const Reference< XRowUpdate >& _rxUpdatedObject,
1435     const sal_Int32 _nColumnIndex, const Any& _rValue)
1436 {
1437     bool bSuccessfullyReRouted = true;
1438     switch (_rValue.getValueTypeClass())
1439     {
1440         case TypeClass_ANY:
1441         {
1442             bSuccessfullyReRouted = implUpdateObject(_rxUpdatedObject, _nColumnIndex, _rValue);
1443         }
1444         break;
1445 
1446         case TypeClass_VOID:
1447             _rxUpdatedObject->updateNull(_nColumnIndex);
1448             break;
1449 
1450         case TypeClass_STRING:
1451             _rxUpdatedObject->updateString(_nColumnIndex, *o3tl::forceAccess<OUString>(_rValue));
1452             break;
1453 
1454         case TypeClass_BOOLEAN:
1455             _rxUpdatedObject->updateBoolean(_nColumnIndex, *o3tl::forceAccess<bool>(_rValue));
1456             break;
1457 
1458         case TypeClass_BYTE:
1459             _rxUpdatedObject->updateByte(_nColumnIndex, *o3tl::forceAccess<sal_Int8>(_rValue));
1460             break;
1461 
1462         case TypeClass_UNSIGNED_SHORT:
1463         case TypeClass_SHORT:
1464             _rxUpdatedObject->updateShort(_nColumnIndex, *o3tl::forceAccess<sal_Int16>(_rValue));
1465             break;
1466 
1467         case TypeClass_CHAR:
1468             _rxUpdatedObject->updateString(_nColumnIndex,OUString(*o3tl::forceAccess<sal_Unicode>(_rValue)));
1469             break;
1470 
1471         case TypeClass_UNSIGNED_LONG:
1472         case TypeClass_LONG:
1473             _rxUpdatedObject->updateInt(_nColumnIndex, *o3tl::forceAccess<sal_Int32>(_rValue));
1474             break;
1475 
1476         case TypeClass_HYPER:
1477         {
1478             sal_Int64 nValue = 0;
1479             OSL_VERIFY( _rValue >>= nValue );
1480             _rxUpdatedObject->updateLong( _nColumnIndex, nValue );
1481         }
1482         break;
1483 
1484         case TypeClass_FLOAT:
1485             _rxUpdatedObject->updateFloat(_nColumnIndex, *o3tl::forceAccess<float>(_rValue));
1486             break;
1487 
1488         case TypeClass_DOUBLE:
1489             _rxUpdatedObject->updateDouble(_nColumnIndex, *o3tl::forceAccess<double>(_rValue));
1490             break;
1491 
1492         case TypeClass_SEQUENCE:
1493             if (auto s = o3tl::tryAccess<Sequence< sal_Int8 >>(_rValue))
1494                 _rxUpdatedObject->updateBytes(_nColumnIndex, *s);
1495             else
1496                 bSuccessfullyReRouted = false;
1497             break;
1498         case TypeClass_STRUCT:
1499             if (auto s1 = o3tl::tryAccess<DateTime>(_rValue))
1500                 _rxUpdatedObject->updateTimestamp(_nColumnIndex, *s1);
1501             else if (auto s2 = o3tl::tryAccess<Date>(_rValue))
1502                 _rxUpdatedObject->updateDate(_nColumnIndex, *s2);
1503             else if (auto s3 = o3tl::tryAccess<Time>(_rValue))
1504                 _rxUpdatedObject->updateTime(_nColumnIndex, *s3);
1505             else
1506                 bSuccessfullyReRouted = false;
1507             break;
1508 
1509         case TypeClass_INTERFACE:
1510             if (auto xStream = o3tl::tryAccess<Reference<XInputStream>>(_rValue))
1511             {
1512                 _rxUpdatedObject->updateBinaryStream(_nColumnIndex, *xStream, (*xStream)->available());
1513                 break;
1514             }
1515             [[fallthrough]];
1516         default:
1517             bSuccessfullyReRouted = false;
1518     }
1519 
1520     return bSuccessfullyReRouted;
1521 }
1522 
1523 bool implSetObject( const Reference< XParameters >& _rxParameters,
1524                         const sal_Int32 _nColumnIndex, const Any& _rValue)
1525 {
1526     bool bSuccessfullyReRouted = true;
1527     switch (_rValue.getValueTypeClass())
1528     {
1529         case TypeClass_UNSIGNED_HYPER:
1530         {
1531             sal_uInt64 nValue = 0;
1532             OSL_VERIFY( _rValue >>= nValue );
1533             _rxParameters->setString(_nColumnIndex, OUString::number(nValue));
1534         }
1535         break;
1536 
1537         case TypeClass_UNSIGNED_LONG:
1538         case TypeClass_HYPER:
1539         {
1540             sal_Int64 nValue = 0;
1541             OSL_VERIFY( _rValue >>= nValue );
1542             _rxParameters->setLong( _nColumnIndex, nValue );
1543         }
1544         break;
1545 
1546         case TypeClass_ANY:
1547         {
1548             bSuccessfullyReRouted = implSetObject(_rxParameters, _nColumnIndex, _rValue);
1549         }
1550         break;
1551 
1552         case TypeClass_VOID:
1553             _rxParameters->setNull(_nColumnIndex,DataType::VARCHAR);
1554             break;
1555 
1556         case TypeClass_STRING:
1557             _rxParameters->setString(_nColumnIndex, *o3tl::forceAccess<OUString>(_rValue));
1558             break;
1559 
1560         case TypeClass_BOOLEAN:
1561             _rxParameters->setBoolean(_nColumnIndex, *o3tl::forceAccess<bool>(_rValue));
1562             break;
1563 
1564         case TypeClass_BYTE:
1565             _rxParameters->setByte(_nColumnIndex, *o3tl::forceAccess<sal_Int8>(_rValue));
1566             break;
1567 
1568         case TypeClass_SHORT:
1569             _rxParameters->setShort(_nColumnIndex, *o3tl::forceAccess<sal_Int16>(_rValue));
1570             break;
1571 
1572         case TypeClass_CHAR:
1573             _rxParameters->setString(_nColumnIndex, OUString(*o3tl::forceAccess<sal_Unicode>(_rValue)));
1574             break;
1575 
1576         case TypeClass_UNSIGNED_SHORT:
1577         case TypeClass_LONG:
1578         {
1579             sal_Int32 nValue = 0;
1580             OSL_VERIFY( _rValue >>= nValue );
1581             _rxParameters->setInt(_nColumnIndex, nValue);
1582             break;
1583         }
1584 
1585         case TypeClass_FLOAT:
1586             _rxParameters->setFloat(_nColumnIndex, *o3tl::forceAccess<float>(_rValue));
1587             break;
1588 
1589         case TypeClass_DOUBLE:
1590             _rxParameters->setDouble(_nColumnIndex, *o3tl::forceAccess<double>(_rValue));
1591             break;
1592 
1593         case TypeClass_SEQUENCE:
1594             if (auto s = o3tl::tryAccess<Sequence< sal_Int8 >>(_rValue))
1595             {
1596                 _rxParameters->setBytes(_nColumnIndex, *s);
1597             }
1598             else
1599                 bSuccessfullyReRouted = false;
1600             break;
1601         case TypeClass_STRUCT:
1602             if (auto s1 = o3tl::tryAccess<DateTime>(_rValue))
1603                 _rxParameters->setTimestamp(_nColumnIndex, *s1);
1604             else if (auto s2 = o3tl::tryAccess<Date>(_rValue))
1605                 _rxParameters->setDate(_nColumnIndex, *s2);
1606             else if (auto s3 = o3tl::tryAccess<Time>(_rValue))
1607                 _rxParameters->setTime(_nColumnIndex, *s3);
1608             else
1609                 bSuccessfullyReRouted = false;
1610             break;
1611 
1612         case TypeClass_INTERFACE:
1613             if (_rValue.getValueType() == cppu::UnoType<XInputStream>::get())
1614             {
1615                 Reference< XInputStream >  xStream;
1616                 _rValue >>= xStream;
1617                 _rxParameters->setBinaryStream(_nColumnIndex, xStream, xStream->available());
1618                 break;
1619             }
1620             [[fallthrough]];
1621         default:
1622             bSuccessfullyReRouted = false;
1623 
1624     }
1625 
1626     return bSuccessfullyReRouted;
1627 }
1628 
1629 namespace
1630 {
1631     class OParameterWrapper : public ::cppu::WeakImplHelper< XIndexAccess >
1632     {
1633         std::vector<bool, std::allocator<bool> >       m_aSet;
1634         Reference<XIndexAccess> m_xSource;
1635     public:
1636         OParameterWrapper(const std::vector<bool, std::allocator<bool> >& _aSet,const Reference<XIndexAccess>& _xSource) : m_aSet(_aSet),m_xSource(_xSource){}
1637     private:
1638         // css::container::XElementAccess
1639         virtual Type SAL_CALL getElementType() override
1640         {
1641             return m_xSource->getElementType();
1642         }
1643         virtual sal_Bool SAL_CALL hasElements(  ) override
1644         {
1645             if ( m_aSet.empty() )
1646                 return m_xSource->hasElements();
1647             return std::count(m_aSet.begin(),m_aSet.end(),false) != 0;
1648         }
1649         // css::container::XIndexAccess
1650         virtual sal_Int32 SAL_CALL getCount(  ) override
1651         {
1652             if ( m_aSet.empty() )
1653                 return m_xSource->getCount();
1654             return std::count(m_aSet.begin(),m_aSet.end(),false);
1655         }
1656         virtual Any SAL_CALL getByIndex( sal_Int32 Index ) override
1657         {
1658             if ( m_aSet.empty() )
1659                 return m_xSource->getByIndex(Index);
1660             if ( Index < 0 || m_aSet.size() < o3tl::make_unsigned(Index) )
1661                 throw IndexOutOfBoundsException();
1662 
1663             std::vector<bool, std::allocator<bool> >::const_iterator aIter = m_aSet.begin();
1664             std::vector<bool, std::allocator<bool> >::const_iterator aEnd = m_aSet.end();
1665             sal_Int32 i = 0;
1666             for(; aIter != aEnd && i <= Index; ++aIter)
1667             {
1668                 if ( !*aIter )
1669                 {
1670                     ++i;
1671                 }
1672             }
1673             auto nParamPos = static_cast<sal_Int32>(std::distance(m_aSet.cbegin(), aIter)) - 1;
1674             return m_xSource->getByIndex(nParamPos);
1675         }
1676     };
1677 }
1678 
1679 void askForParameters(const Reference< XSingleSelectQueryComposer >& _xComposer,
1680                       const Reference<XParameters>& _xParameters,
1681                       const Reference< XConnection>& _xConnection,
1682                       const Reference< XInteractionHandler >& _rxHandler,
1683                       const std::vector<bool, std::allocator<bool> >& _aParametersSet)
1684 {
1685     OSL_ENSURE(_xComposer.is(),"dbtools::askForParameters XSQLQueryComposer is null!");
1686     OSL_ENSURE(_xParameters.is(),"dbtools::askForParameters XParameters is null!");
1687     OSL_ENSURE(_xConnection.is(),"dbtools::askForParameters XConnection is null!");
1688     OSL_ENSURE(_rxHandler.is(),"dbtools::askForParameters XInteractionHandler is null!");
1689 
1690     // we have to set this here again because getCurrentSettingsComposer can force a setpropertyvalue
1691     Reference<XParametersSupplier>  xParameters(_xComposer, UNO_QUERY);
1692 
1693     Reference<XIndexAccess>  xParamsAsIndicies = xParameters.is() ? xParameters->getParameters() : Reference<XIndexAccess>();
1694     sal_Int32 nParamCount = xParamsAsIndicies.is() ? xParamsAsIndicies->getCount() : 0;
1695     std::vector<bool, std::allocator<bool> > aNewParameterSet( _aParametersSet );
1696     if ( !(nParamCount && std::count(aNewParameterSet.begin(),aNewParameterSet.end(),true) != nParamCount) )
1697         return;
1698 
1699     static const OUString PROPERTY_NAME(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME));
1700     aNewParameterSet.resize(nParamCount ,false);
1701     typedef std::map< OUString, std::vector<sal_Int32> > TParameterPositions;
1702     TParameterPositions aParameterNames;
1703     for(sal_Int32 i = 0; i < nParamCount; ++i)
1704     {
1705         Reference<XPropertySet> xParam(xParamsAsIndicies->getByIndex(i),UNO_QUERY);
1706         OUString sName;
1707         xParam->getPropertyValue(PROPERTY_NAME) >>= sName;
1708 
1709         TParameterPositions::const_iterator aFind = aParameterNames.find(sName);
1710         if ( aFind != aParameterNames.end() )
1711             aNewParameterSet[i] = true;
1712         aParameterNames[sName].push_back(i+1);
1713     }
1714     // build an interaction request
1715     // two continuations (Ok and Cancel)
1716     OInteractionAbort* pAbort = new OInteractionAbort;
1717     OParameterContinuation* pParams = new OParameterContinuation;
1718     // the request
1719     ParametersRequest aRequest;
1720     Reference<XIndexAccess> xWrappedParameters = new OParameterWrapper(aNewParameterSet,xParamsAsIndicies);
1721     aRequest.Parameters = xWrappedParameters;
1722     aRequest.Connection = _xConnection;
1723     OInteractionRequest* pRequest = new OInteractionRequest(makeAny(aRequest));
1724     Reference< XInteractionRequest > xRequest(pRequest);
1725     // some knittings
1726     pRequest->addContinuation(pAbort);
1727     pRequest->addContinuation(pParams);
1728 
1729     // execute the request
1730     _rxHandler->handle(xRequest);
1731 
1732     if (!pParams->wasSelected())
1733     {
1734         // canceled by the user (i.e. (s)he canceled the dialog)
1735         RowSetVetoException e;
1736         e.ErrorCode = ParameterInteractionCancelled;
1737         throw e;
1738     }
1739 
1740     // now transfer the values from the continuation object to the parameter columns
1741     Sequence< PropertyValue > aFinalValues = pParams->getValues();
1742     const PropertyValue* pFinalValues = aFinalValues.getConstArray();
1743     for (sal_Int32 i=0; i<aFinalValues.getLength(); ++i, ++pFinalValues)
1744     {
1745         Reference< XPropertySet > xParamColumn(xWrappedParameters->getByIndex(i),UNO_QUERY);
1746         if (xParamColumn.is())
1747         {
1748             OUString sName;
1749             xParamColumn->getPropertyValue(PROPERTY_NAME) >>= sName;
1750             OSL_ENSURE(sName == pFinalValues->Name, "::dbaui::askForParameters: inconsistent parameter names!");
1751 
1752             // determine the field type and ...
1753             sal_Int32 nParamType = 0;
1754             xParamColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE)) >>= nParamType;
1755             // ... the scale of the parameter column
1756             sal_Int32 nScale = 0;
1757             if (hasProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE), xParamColumn))
1758                 xParamColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE)) >>= nScale;
1759                 // (the index of the parameters is one-based)
1760             TParameterPositions::const_iterator aFind = aParameterNames.find(pFinalValues->Name);
1761             for(const auto& rItem : aFind->second)
1762             {
1763                 if ( _aParametersSet.empty() || !_aParametersSet[rItem-1] )
1764                 {
1765                     _xParameters->setObjectWithInfo(rItem, pFinalValues->Value, nParamType, nScale);
1766                 }
1767             }
1768         }
1769     }
1770 }
1771 
1772 void setObjectWithInfo(const Reference<XParameters>& _xParams,
1773                        sal_Int32 parameterIndex,
1774                        const Any& x,
1775                        sal_Int32 sqlType,
1776                        sal_Int32 scale)
1777 {
1778     ORowSetValue aVal;
1779     aVal.fill(x);
1780     setObjectWithInfo(_xParams,parameterIndex,aVal,sqlType,scale);
1781 }
1782 
1783 void setObjectWithInfo(const Reference<XParameters>& _xParams,
1784                        sal_Int32 parameterIndex,
1785                        const ::connectivity::ORowSetValue& _rValue,
1786                        sal_Int32 sqlType,
1787                        sal_Int32 scale)
1788 {
1789     if ( _rValue.isNull() )
1790         _xParams->setNull(parameterIndex,sqlType);
1791     else
1792     {
1793         switch(sqlType)
1794         {
1795             case DataType::DECIMAL:
1796             case DataType::NUMERIC:
1797                 _xParams->setObjectWithInfo(parameterIndex,_rValue.makeAny(),sqlType,scale);
1798                 break;
1799             case DataType::CHAR:
1800             case DataType::VARCHAR:
1801             case DataType::LONGVARCHAR:
1802                 _xParams->setString(parameterIndex,_rValue);
1803                 break;
1804             case DataType::CLOB:
1805                 {
1806                     Any x(_rValue.makeAny());
1807                     OUString sValue;
1808                     if ( x >>= sValue )
1809                         _xParams->setString(parameterIndex,sValue);
1810                     else
1811                     {
1812                         Reference< XClob > xClob;
1813                         if(x >>= xClob)
1814                             _xParams->setClob(parameterIndex,xClob);
1815                         else
1816                         {
1817                             Reference< css::io::XInputStream > xStream;
1818                             if(x >>= xStream)
1819                                 _xParams->setCharacterStream(parameterIndex,xStream,xStream->available());
1820                         }
1821                     }
1822                 }
1823                 break;
1824             case DataType::BIGINT:
1825                 if ( _rValue.isSigned() )
1826                     _xParams->setLong(parameterIndex,_rValue);
1827                 else
1828                     _xParams->setString(parameterIndex,_rValue);
1829                 break;
1830 
1831             case DataType::FLOAT:
1832                 _xParams->setFloat(parameterIndex,_rValue);
1833                 break;
1834             case DataType::REAL:
1835             case DataType::DOUBLE:
1836                 _xParams->setDouble(parameterIndex,_rValue);
1837                 break;
1838             case DataType::DATE:
1839                 _xParams->setDate(parameterIndex,_rValue);
1840                 break;
1841             case DataType::TIME:
1842                 _xParams->setTime(parameterIndex,_rValue);
1843                 break;
1844             case DataType::TIMESTAMP:
1845                 _xParams->setTimestamp(parameterIndex,_rValue);
1846                 break;
1847             case DataType::BINARY:
1848             case DataType::VARBINARY:
1849             case DataType::LONGVARBINARY:
1850             case DataType::BLOB:
1851                 {
1852                     Any x(_rValue.makeAny());
1853                     Sequence< sal_Int8> aBytes;
1854                     if(x >>= aBytes)
1855                         _xParams->setBytes(parameterIndex,aBytes);
1856                     else
1857                     {
1858                         Reference< XBlob > xBlob;
1859                         if(x >>= xBlob)
1860                             _xParams->setBlob(parameterIndex,xBlob);
1861                         else
1862                         {
1863                             Reference< XClob > xClob;
1864                             if(x >>= xClob)
1865                                 _xParams->setClob(parameterIndex,xClob);
1866                             else
1867                             {
1868                                 Reference< css::io::XInputStream > xBinStream;
1869                                 if(x >>= xBinStream)
1870                                     _xParams->setBinaryStream(parameterIndex,xBinStream,xBinStream->available());
1871                             }
1872                         }
1873                     }
1874                 }
1875                 break;
1876             case DataType::BIT:
1877             case DataType::BOOLEAN:
1878                 _xParams->setBoolean(parameterIndex,static_cast<bool>(_rValue));
1879                 break;
1880             case DataType::TINYINT:
1881                 if ( _rValue.isSigned() )
1882                     _xParams->setByte(parameterIndex,_rValue);
1883                 else
1884                     _xParams->setShort(parameterIndex,_rValue);
1885                 break;
1886             case DataType::SMALLINT:
1887                 if ( _rValue.isSigned() )
1888                     _xParams->setShort(parameterIndex,_rValue);
1889                 else
1890                     _xParams->setInt(parameterIndex,_rValue);
1891                 break;
1892             case DataType::INTEGER:
1893                 if ( _rValue.isSigned() )
1894                     _xParams->setInt(parameterIndex,_rValue);
1895                 else
1896                     _xParams->setLong(parameterIndex,_rValue);
1897                 break;
1898             default:
1899                 {
1900                     ::connectivity::SharedResources aResources;
1901                     const OUString sError( aResources.getResourceStringWithSubstitution(
1902                             STR_UNKNOWN_PARA_TYPE,
1903                             "$position$", OUString::number(parameterIndex)
1904                          ) );
1905                     ::dbtools::throwGenericSQLException(sError,nullptr);
1906                 }
1907         }
1908     }
1909 }
1910 
1911 void getBooleanComparisonPredicate( const OUString& _rExpression, const bool _bValue, const sal_Int32 _nBooleanComparisonMode,
1912     OUStringBuffer& _out_rSQLPredicate )
1913 {
1914     switch ( _nBooleanComparisonMode )
1915     {
1916     case BooleanComparisonMode::IS_LITERAL:
1917         _out_rSQLPredicate.append( _rExpression );
1918         if ( _bValue )
1919             _out_rSQLPredicate.append( " IS TRUE" );
1920         else
1921             _out_rSQLPredicate.append( " IS FALSE" );
1922         break;
1923 
1924     case BooleanComparisonMode::EQUAL_LITERAL:
1925         _out_rSQLPredicate.append( _rExpression );
1926         _out_rSQLPredicate.appendAscii( _bValue ? " = TRUE" : " = FALSE" );
1927         break;
1928 
1929     case BooleanComparisonMode::ACCESS_COMPAT:
1930         if ( _bValue )
1931         {
1932             _out_rSQLPredicate.append( " NOT ( ( " );
1933             _out_rSQLPredicate.append( _rExpression );
1934             _out_rSQLPredicate.append( " = 0 ) OR ( " );
1935             _out_rSQLPredicate.append( _rExpression );
1936             _out_rSQLPredicate.append( " IS NULL ) )" );
1937         }
1938         else
1939         {
1940             _out_rSQLPredicate.append( _rExpression );
1941             _out_rSQLPredicate.append( " = 0" );
1942         }
1943         break;
1944 
1945     case BooleanComparisonMode::EQUAL_INTEGER:
1946         // fall through
1947     default:
1948         _out_rSQLPredicate.append( _rExpression );
1949         _out_rSQLPredicate.appendAscii( _bValue ? " = 1" : " = 0" );
1950         break;
1951     }
1952 }
1953 
1954 }   // namespace dbtools
1955 
1956 namespace connectivity
1957 {
1958 void checkDisposed(bool _bThrow)
1959 {
1960     if (_bThrow)
1961         throw DisposedException();
1962 
1963 }
1964 
1965 OSQLColumns::const_iterator find(const OSQLColumns::const_iterator& first,
1966                                         const OSQLColumns::const_iterator& last,
1967                                         const OUString& _rVal,
1968                                         const ::comphelper::UStringMixEqual& _rCase)
1969 {
1970     OUString sName = OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME);
1971     return find(first,last,sName,_rVal,_rCase);
1972 }
1973 
1974 OSQLColumns::const_iterator findRealName(const OSQLColumns::const_iterator& first,
1975                                         const OSQLColumns::const_iterator& last,
1976                                         const OUString& _rVal,
1977                                         const ::comphelper::UStringMixEqual& _rCase)
1978 {
1979     OUString sRealName = OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_REALNAME);
1980     return find(first,last,sRealName,_rVal,_rCase);
1981 }
1982 
1983 OSQLColumns::const_iterator find(OSQLColumns::const_iterator first,
1984                                         const OSQLColumns::const_iterator& last,
1985                                         const OUString& _rProp,
1986                                         const OUString& _rVal,
1987                                         const ::comphelper::UStringMixEqual& _rCase)
1988 {
1989     while (first != last && !_rCase(getString((*first)->getPropertyValue(_rProp)),_rVal))
1990         ++first;
1991     return first;
1992 }
1993 
1994 namespace dbase
1995 {
1996     bool dbfDecodeCharset(rtl_TextEncoding &_out_encoding, sal_uInt8 nType, sal_uInt8 nCodepage)
1997     {
1998         switch (nType)
1999         {
2000         // dBaseIII header doesn't contain language driver ID
2001         // See http://dbase.free.fr/tlcharge/structure%20tables.pdf
2002         case dBaseIII:
2003         case dBaseIIIMemo:
2004             break;
2005         case dBaseIV:
2006         case dBaseV:
2007         case VisualFoxPro:
2008         case VisualFoxProAuto:
2009         case dBaseFS:
2010         case dBaseFSMemo:
2011         case dBaseIVMemoSQL:
2012         case FoxProMemo:
2013         {
2014             if (nCodepage != 0x00)
2015             {
2016                 auto eEncoding(RTL_TEXTENCODING_DONTKNOW);
2017                 switch(nCodepage)
2018                 {
2019                 case 0x01: eEncoding = RTL_TEXTENCODING_IBM_437; break;       // DOS USA  code page 437
2020                 case 0x02: eEncoding = RTL_TEXTENCODING_IBM_850; break;       // DOS Multilingual code page 850
2021                 case 0x03: eEncoding = RTL_TEXTENCODING_MS_1252; break;       // Windows ANSI code page 1252
2022                 case 0x04: eEncoding = RTL_TEXTENCODING_APPLE_ROMAN; break;   // Standard Macintosh
2023                 case 0x64: eEncoding = RTL_TEXTENCODING_IBM_852; break;       // EE MS-DOS    code page 852
2024                 case 0x65: eEncoding = RTL_TEXTENCODING_IBM_866; break;       // Russian MS-DOS   code page 866
2025                 case 0x66: eEncoding = RTL_TEXTENCODING_IBM_865; break;       // Nordic MS-DOS    code page 865
2026                 case 0x67: eEncoding = RTL_TEXTENCODING_IBM_861; break;       // Icelandic MS-DOS
2027                 //case 0x68: eEncoding = ; break;     // Kamenicky (Czech) MS-DOS
2028                 //case 0x69: eEncoding = ; break;     // Mazovia (Polish) MS-DOS
2029                 case 0x6A: eEncoding = RTL_TEXTENCODING_IBM_737; break;       // Greek MS-DOS (437G)
2030                 case 0x6B: eEncoding = RTL_TEXTENCODING_IBM_857; break;       // Turkish MS-DOS
2031                 case 0x6C: eEncoding = RTL_TEXTENCODING_IBM_863; break;       // MS-DOS, Canada
2032                 case 0x78: eEncoding = RTL_TEXTENCODING_MS_950; break;        // Windows, Traditional Chinese
2033                 case 0x79: eEncoding = RTL_TEXTENCODING_MS_949; break;        // Windows, Korean (Hangul)
2034                 case 0x7A: eEncoding = RTL_TEXTENCODING_MS_936; break;        // Windows, Simplified Chinese
2035                 case 0x7B: eEncoding = RTL_TEXTENCODING_MS_932; break;        // Windows, Japanese (Shift-jis)
2036                 case 0x7C: eEncoding = RTL_TEXTENCODING_MS_874; break;        // Windows, Thai
2037                 case 0x7D: eEncoding = RTL_TEXTENCODING_MS_1255; break;       // Windows, Hebrew
2038                 case 0x7E: eEncoding = RTL_TEXTENCODING_MS_1256; break;       // Windows, Arabic
2039                 case 0x96: eEncoding = RTL_TEXTENCODING_APPLE_CYRILLIC; break;    // Russian Macintosh
2040                 case 0x97: eEncoding = RTL_TEXTENCODING_APPLE_CENTEURO; break;    // Eastern European Macintosh
2041                 case 0x98: eEncoding = RTL_TEXTENCODING_APPLE_GREEK; break;   // Greek Macintosh
2042                 case 0xC8: eEncoding = RTL_TEXTENCODING_MS_1250; break;       // Windows EE   code page 1250
2043                 case 0xC9: eEncoding = RTL_TEXTENCODING_MS_1251; break;       // Russian Windows
2044                 case 0xCA: eEncoding = RTL_TEXTENCODING_MS_1254; break;       // Turkish Windows
2045                 case 0xCB: eEncoding = RTL_TEXTENCODING_MS_1253; break;       // Greek Windows
2046                 case 0xCC: eEncoding = RTL_TEXTENCODING_MS_1257; break;       // Windows, Baltic
2047                 }
2048                 if(eEncoding != RTL_TEXTENCODING_DONTKNOW)
2049                 {
2050                     _out_encoding = eEncoding;
2051                     return true;
2052                 }
2053             }
2054         }
2055         }
2056         return false;
2057     }
2058 
2059     bool dbfReadCharset(rtl_TextEncoding &nCharSet, SvStream* dbf_Stream)
2060     {
2061         sal_uInt8 nType=0;
2062         dbf_Stream->ReadUChar( nType );
2063 
2064         dbf_Stream->Seek(STREAM_SEEK_TO_BEGIN + 29);
2065         if (dbf_Stream->eof())
2066         {
2067             return false;
2068         }
2069         else
2070         {
2071             sal_uInt8 nEncoding=0;
2072             dbf_Stream->ReadUChar( nEncoding );
2073             return dbfDecodeCharset(nCharSet, nType, nEncoding);
2074         }
2075     }
2076 
2077 }
2078 
2079 } //namespace connectivity
2080 
2081 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
2082