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