Use correct object
[LibreOffice.git] / connectivity / source / commontools / dbtools.cxx
blobf9d54236e4b4b5cecf3f7d141a1f8866a43da627
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <connectivity/CommonTools.hxx>
21 #include <TConnection.hxx>
22 #include <ParameterCont.hxx>
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>
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>
87 #include <algorithm>
88 #include <iterator>
89 #include <set>
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;
107 namespace dbtools
110 namespace
112 typedef sal_Bool (SAL_CALL XDatabaseMetaData::*FMetaDataSupport)();
115 sal_Int32 getDefaultNumberFormat(const Reference< XPropertySet >& _xColumn,
116 const Reference< XNumberFormatTypes >& _xTypes,
117 const Locale& _rLocale)
119 OSL_ENSURE(_xTypes.is() && _xColumn.is(), "dbtools::getDefaultNumberFormat: invalid arg !");
120 if (!_xTypes.is() || !_xColumn.is())
121 return NumberFormat::UNDEFINED;
123 sal_Int32 nDataType = 0;
124 sal_Int32 nScale = 0;
127 // determine the datatype of the column
128 _xColumn->getPropertyValue(u"Type"_ustr) >>= nDataType;
130 if (DataType::NUMERIC == nDataType || DataType::DECIMAL == nDataType)
131 _xColumn->getPropertyValue(u"Scale"_ustr) >>= nScale;
133 catch (Exception&)
135 return NumberFormat::UNDEFINED;
137 return getDefaultNumberFormat(nDataType,
138 nScale,
139 ::cppu::any2bool(_xColumn->getPropertyValue(u"IsCurrency"_ustr)),
140 _xTypes,
141 _rLocale);
144 sal_Int32 getDefaultNumberFormat(sal_Int32 _nDataType,
145 sal_Int32 _nScale,
146 bool _bIsCurrency,
147 const Reference< XNumberFormatTypes >& _xTypes,
148 const Locale& _rLocale)
150 OSL_ENSURE(_xTypes.is() , "dbtools::getDefaultNumberFormat: invalid arg !");
151 if (!_xTypes.is())
152 return NumberFormat::UNDEFINED;
154 sal_Int32 nFormat = 0;
155 sal_Int32 nNumberType = _bIsCurrency ? NumberFormat::CURRENCY : NumberFormat::NUMBER;
156 switch (_nDataType)
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:
174 nFormat = _xTypes->getStandardFormat(static_cast<sal_Int16>(nNumberType), _rLocale);
175 if(_nScale > 0)
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);
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);
187 catch (Exception&)
189 nFormat = _xTypes->getStandardFormat(static_cast<sal_Int16>(nNumberType), _rLocale);
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);
221 return nFormat;
224 static Reference< XConnection> findConnection(const Reference< XInterface >& xParent)
226 Reference< XConnection> xConnection(xParent, UNO_QUERY);
227 if (!xConnection.is())
229 Reference< XChild> xChild(xParent, UNO_QUERY);
230 if (xChild.is())
231 xConnection = findConnection(xChild->getParent());
233 return xConnection;
236 static Reference< XDataSource> getDataSource_allowException(
237 const OUString& _rsTitleOrPath,
238 const Reference< XComponentContext >& _rxContext )
240 ENSURE_OR_RETURN( !_rsTitleOrPath.isEmpty(), "getDataSource_allowException: invalid arg !", nullptr );
242 Reference< XDatabaseContext> xDatabaseContext = DatabaseContext::create(_rxContext);
244 return Reference< XDataSource >( xDatabaseContext->getByName( _rsTitleOrPath ), UNO_QUERY );
247 Reference< XDataSource > getDataSource(
248 const OUString& _rsTitleOrPath,
249 const Reference< XComponentContext >& _rxContext )
251 Reference< XDataSource > xDS;
254 xDS = getDataSource_allowException( _rsTitleOrPath, _rxContext );
256 catch( const Exception& )
258 DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
261 return xDS;
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)
271 Reference< XDataSource> xDataSource( getDataSource_allowException(_rsTitleOrPath, _rxContext) );
272 Reference<XConnection> xConnection;
273 if (xDataSource.is())
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())
281 Sequence< Any > aArgs{ Any(NamedValue( u"ParentWindow"_ustr, Any(_rxParent) )) };
282 xIni->initialize(aArgs);
285 // do it with interaction handler
286 if(_rsUser.isEmpty() || _rsPwd.isEmpty())
288 Reference<XPropertySet> xProp(xDataSource,UNO_QUERY);
289 OUString sPwd, sUser;
290 bool bPwdReq = false;
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;
297 catch(Exception&)
299 OSL_FAIL("dbtools::getConnection: error while retrieving data source properties!");
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);
311 else
312 xConnection = xDataSource->getConnection(sUser, sPwd);
314 if(!xConnection.is()) // try to get one if not already have one, just to make sure
315 xConnection = xDataSource->getConnection(_rsUser, _rsPwd);
317 if (xIni.is())
319 Sequence< Any > aArgs{ Any(NamedValue( u"ParentWindow"_ustr, Any(Reference<XWindow>()) )) };
320 xIni->initialize(aArgs);
324 return xConnection;
327 Reference< XConnection> getConnection_withFeedback(const OUString& _rDataSourceName,
328 const OUString& _rUser, const OUString& _rPwd, const Reference< XComponentContext>& _rxContext,
329 const Reference< XWindow >& _rxParent)
331 Reference< XConnection > xReturn;
334 xReturn = getConnection_allowException(_rDataSourceName, _rUser, _rPwd, _rxContext, _rxParent);
336 catch(SQLException&)
338 // allowed to pass
339 throw;
341 catch(Exception&)
343 TOOLS_WARN_EXCEPTION( "connectivity.commontools", "::dbtools::getConnection_withFeedback: unexpected (non-SQL) exception caught!");
345 return xReturn;
348 Reference< XConnection> getConnection(const Reference< XRowSet>& _rxRowSet)
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;
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)
360 static SharedConnection lcl_connectRowSet(const Reference< XRowSet>& _rxRowSet, const Reference< XComponentContext >& _rxContext,
361 bool _bAttachAutoDisposer, const Reference< XWindow >& _rxParent)
363 SharedConnection xConnection;
367 Reference< XPropertySet> xRowSetProps(_rxRowSet, UNO_QUERY);
368 if ( !xRowSetProps.is() )
369 break;
371 // 1. already connected?
372 Reference< XConnection > xExistingConn(
373 xRowSetProps->getPropertyValue(u"ActiveConnection"_ustr),
374 UNO_QUERY );
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()
383 xRowSetProps->setPropertyValue(u"ActiveConnection"_ustr, Any( xExistingConn ) );
384 // no auto disposer needed, since we did not create the connection
386 xConnection.reset( xExistingConn, SharedConnection::NoTakeOwnership );
387 break;
390 // build a connection with its current settings (4. data source name, or 5. URL)
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;
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;
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;
409 xPureConnection = getConnection_allowException( sDataSourceName, sUser, sPwd, _rxContext, _rxParent );
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())
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 );
433 else
434 // just use the url
435 xPureConnection = xDriverManager->getConnection( sURL );
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 */
444 // now if we created a connection, forward it to the row set
445 if ( xConnection.is() )
449 if ( _bAttachAutoDisposer )
451 new OAutoConnectionDisposer( _rxRowSet, xConnection );
453 else
454 xRowSetProps->setPropertyValue(
455 u"ActiveConnection"_ustr,
456 Any( xConnection.getTyped() )
459 catch(Exception&)
461 TOOLS_WARN_EXCEPTION( "connectivity.commontools", "EXception when we set the new active connection!");
465 while ( false );
467 return xConnection;
470 Reference< XConnection> connectRowset(const Reference< XRowSet>& _rxRowSet, const Reference< XComponentContext >& _rxContext, const Reference< XWindow >& _rxParent)
472 SharedConnection xConnection = lcl_connectRowSet( _rxRowSet, _rxContext, true, _rxParent );
473 return xConnection.getTyped();
476 SharedConnection ensureRowSetConnection(const Reference< XRowSet>& _rxRowSet, const Reference< XComponentContext>& _rxContext, const Reference< XWindow >& _rxParent)
478 return lcl_connectRowSet( _rxRowSet, _rxContext, false/*bUseAutoConnectionDisposer*/, _rxParent );
481 Reference< XNameAccess> getTableFields(const Reference< XConnection>& _rxConn,const OUString& _rName)
483 Reference< XComponent > xDummy;
484 return getFieldsByCommandDescriptor( _rxConn, CommandType::TABLE, _rName, xDummy );
487 Reference< XNameAccess> getPrimaryKeyColumns_throw(const Any& i_aTable)
489 const Reference< XPropertySet > xTable(i_aTable,UNO_QUERY_THROW);
490 return getPrimaryKeyColumns_throw(xTable);
493 Reference< XNameAccess> getPrimaryKeyColumns_throw(const Reference< XPropertySet >& i_xTable)
495 Reference<XNameAccess> xKeyColumns;
496 const Reference<XKeysSupplier> xKeySup(i_xTable,UNO_QUERY);
497 if ( xKeySup.is() )
499 const Reference<XIndexAccess> xKeys = xKeySup->getKeys();
500 if ( xKeys.is() )
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)
508 xProp.set(xKeys->getByIndex(i),UNO_QUERY_THROW);
509 sal_Int32 nKeyType = 0;
510 xProp->getPropertyValue(sPropName) >>= nKeyType;
511 if(KeyType::PRIMARY == nKeyType)
513 const Reference<XColumnsSupplier> xKeyColsSup(xProp,UNO_QUERY_THROW);
514 xKeyColumns = xKeyColsSup->getColumns();
515 break;
521 return xKeyColumns;
524 namespace
526 enum FieldLookupState
528 HANDLE_TABLE, HANDLE_QUERY, HANDLE_SQL, RETRIEVE_OBJECT, RETRIEVE_COLUMNS, DONE, FAILED
532 Reference< XNameAccess > getFieldsByCommandDescriptor( const Reference< XConnection >& _rxConnection,
533 const sal_Int32 _nCommandType, const OUString& _rCommand,
534 Reference< XComponent >& _rxKeepFieldsAlive, SQLExceptionInfo* _pErrorInfo )
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)!" );
541 Reference< XNameAccess > xFields;
543 // reset the error
544 if ( _pErrorInfo )
545 *_pErrorInfo = SQLExceptionInfo();
546 // reset the ownership holder
547 _rxKeepFieldsAlive.clear();
549 // go for the fields
552 // some kind of state machine to ease the sharing of code
553 FieldLookupState eState = FAILED;
554 switch ( _nCommandType )
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;
567 // needed in various states:
568 Reference< XNameAccess > xObjectCollection;
569 Reference< XColumnsSupplier > xSupplyColumns;
571 // go!
572 while ( ( DONE != eState ) && ( FAILED != eState ) )
574 switch ( eState )
576 case HANDLE_TABLE:
578 // initial state for handling the tables
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
586 // next state: get the object
587 eState = RETRIEVE_OBJECT;
589 break;
591 case HANDLE_QUERY:
593 // initial state for handling the tables
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
601 // next state: get the object
602 eState = RETRIEVE_OBJECT;
604 break;
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
610 // next state: default to FAILED
611 eState = FAILED;
613 OSL_ENSURE( xObjectCollection.is(), "::dbtools::getFieldsByCommandDescriptor: invalid connection (no sdb.Connection, or no Tables-/QueriesSupplier)!");
614 if ( xObjectCollection.is() && xObjectCollection->hasByName( _rCommand ) )
616 xObjectCollection->getByName( _rCommand ) >>= xSupplyColumns;
617 // (xSupplyColumns being NULL will be handled in the next state)
619 // next: go for the columns
620 eState = RETRIEVE_COLUMNS;
622 break;
624 case RETRIEVE_COLUMNS:
625 OSL_ENSURE( xSupplyColumns.is(), "::dbtools::getFieldsByCommandDescriptor: could not retrieve the columns supplier!" );
627 // next state: default to FAILED
628 eState = FAILED;
630 if ( xSupplyColumns.is() )
632 xFields = xSupplyColumns->getColumns();
633 // that's it
634 eState = DONE;
636 break;
638 case HANDLE_SQL:
640 OUString sStatementToExecute( _rCommand );
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.
652 Reference< XMultiServiceFactory > xComposerFac( _rxConnection, UNO_QUERY );
654 if ( xComposerFac.is() )
656 Reference< XSingleSelectQueryComposer > xComposer(xComposerFac->createInstance(u"com.sun.star.sdb.SingleSelectQueryComposer"_ustr),UNO_QUERY);
657 if ( xComposer.is() )
659 xComposer->setQuery( sStatementToExecute );
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( );
668 catch( const Exception& )
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
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);
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 );
685 if ( xStatementProps.is() )
686 xStatementProps->setPropertyValue( u"MaxRows"_ustr, Any( sal_Int32( 0 ) ) );
688 catch( const Exception& )
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
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
699 // so the next state is to get the columns
700 eState = RETRIEVE_COLUMNS;
702 break;
704 default:
705 OSL_FAIL( "::dbtools::getFieldsByCommandDescriptor: oops! unhandled state here!" );
706 eState = FAILED;
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& )
715 TOOLS_WARN_EXCEPTION( "connectivity.commontools", "::dbtools::getFieldsByCommandDescriptor: caught an exception while retrieving the fields!" );
718 return xFields;
721 Sequence< OUString > getFieldNamesByCommandDescriptor( const Reference< XConnection >& _rxConnection,
722 const sal_Int32 _nCommandType, const OUString& _rCommand,
723 SQLExceptionInfo* _pErrorInfo )
725 // get the container for the fields
726 Reference< XComponent > xKeepFieldsAlive;
727 Reference< XNameAccess > xFieldContainer = getFieldsByCommandDescriptor( _rxConnection, _nCommandType, _rCommand, xKeepFieldsAlive, _pErrorInfo );
729 // get the names of the fields
730 Sequence< OUString > aNames;
731 if ( xFieldContainer.is() )
732 aNames = xFieldContainer->getElementNames();
734 // clean up any temporary objects which have been created
735 disposeComponent( xKeepFieldsAlive );
737 // outta here
738 return aNames;
741 SQLException prependErrorInfo( const SQLException& _rChainedException, const Reference< XInterface >& _rxContext,
742 const OUString& _rAdditionalError, const StandardSQLState _eSQLState )
744 return SQLException( _rAdditionalError, _rxContext,
745 _eSQLState == StandardSQLState::ERROR_UNSPECIFIED ? OUString() : getStandardSQLState( _eSQLState ),
746 0, Any( _rChainedException ) );
749 namespace
751 struct NameComponentSupport
753 const bool bCatalogs;
754 const bool bSchemas;
756 NameComponentSupport( const bool _bCatalogs, const bool _bSchemas )
757 :bCatalogs( _bCatalogs )
758 ,bSchemas( _bSchemas )
763 NameComponentSupport lcl_getNameComponentSupport( const Reference< XDatabaseMetaData >& _rxMetaData, EComposeRule _eComposeRule )
765 OSL_PRECOND( _rxMetaData.is(), "lcl_getNameComponentSupport: invalid meta data!" );
767 FMetaDataSupport pCatalogCall = &XDatabaseMetaData::supportsCatalogsInDataManipulation;
768 FMetaDataSupport pSchemaCall = &XDatabaseMetaData::supportsSchemasInDataManipulation;
769 bool bIgnoreMetaData = false;
771 switch ( _eComposeRule )
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;
796 return NameComponentSupport(
797 bIgnoreMetaData || (_rxMetaData.get()->*pCatalogCall)(),
798 bIgnoreMetaData || (_rxMetaData.get()->*pSchemaCall)()
803 static OUString impl_doComposeTableName( const Reference< XDatabaseMetaData >& _rxMetaData,
804 const OUString& _rCatalog, const OUString& _rSchema, const OUString& _rName,
805 bool _bQuote, EComposeRule _eComposeRule )
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 !");
812 const OUString sQuoteString = _rxMetaData->getIdentifierQuoteString();
813 const NameComponentSupport aNameComps( lcl_getNameComponentSupport( _rxMetaData, _eComposeRule ) );
815 OUStringBuffer aComposedName;
817 OUString sCatalogSep;
818 bool bCatalogAtStart = true;
819 if ( !_rCatalog.isEmpty() && aNameComps.bCatalogs )
821 sCatalogSep = _rxMetaData->getCatalogSeparator();
822 bCatalogAtStart = _rxMetaData->isCatalogAtStart();
824 if ( bCatalogAtStart && !sCatalogSep.isEmpty())
826 aComposedName.append( _bQuote ? quoteName( sQuoteString, _rCatalog ) : _rCatalog );
827 aComposedName.append( sCatalogSep );
831 if ( !_rSchema.isEmpty() && aNameComps.bSchemas )
833 aComposedName.append(
834 (_bQuote ? quoteName( sQuoteString, _rSchema ) : _rSchema )
835 + "." );
838 aComposedName.append( _bQuote ? quoteName( sQuoteString, _rName ) : _rName );
840 if ( !_rCatalog.isEmpty()
841 && !bCatalogAtStart
842 && !sCatalogSep.isEmpty()
843 && aNameComps.bCatalogs
846 aComposedName.append( sCatalogSep );
847 aComposedName.append( _bQuote ? quoteName( sQuoteString, _rCatalog ) : _rCatalog );
850 return aComposedName.makeStringAndClear();
853 OUString quoteTableName(const Reference< XDatabaseMetaData>& _rxMeta
854 , const OUString& _rName
855 , EComposeRule _eComposeRule)
857 OUString sCatalog, sSchema, sTable;
858 qualifiedNameComponents(_rxMeta,_rName,sCatalog,sSchema,sTable,_eComposeRule);
859 return impl_doComposeTableName( _rxMeta, sCatalog, sSchema, sTable, true, _eComposeRule );
862 void qualifiedNameComponents(const Reference< XDatabaseMetaData >& _rxConnMetaData, const OUString& _rQualifiedName, OUString& _rCatalog, OUString& _rSchema, OUString& _rName,EComposeRule _eComposeRule)
864 OSL_ENSURE(_rxConnMetaData.is(), "QualifiedNameComponents : invalid meta data!");
866 NameComponentSupport aNameComps( lcl_getNameComponentSupport( _rxConnMetaData, _eComposeRule ) );
868 OUString sSeparator = _rxConnMetaData->getCatalogSeparator();
870 OUString sName(_rQualifiedName);
871 // do we have catalogs?
872 if ( aNameComps.bCatalogs )
874 if (_rxConnMetaData->isCatalogAtStart())
876 // search for the catalog name at the beginning
877 sal_Int32 nIndex = sName.indexOf(sSeparator);
878 if (-1 != nIndex)
880 _rCatalog = sName.copy(0, nIndex);
881 sName = sName.copy(nIndex + 1);
884 else
886 // Catalog name at the end
887 sal_Int32 nIndex = sName.lastIndexOf(sSeparator);
888 if (-1 != nIndex)
890 _rCatalog = sName.copy(nIndex + 1);
891 sName = sName.copy(0, nIndex);
896 if ( aNameComps.bSchemas )
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);
905 _rName = sName;
908 Reference< XNumberFormatsSupplier> getNumberFormats(
909 const Reference< XConnection>& _rxConn,
910 bool _bAlloweDefault,
911 const Reference< XComponentContext>& _rxContext)
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())
919 Reference< XPropertySet> xConnParentProps(xConnAsChild->getParent(), UNO_QUERY);
920 if (xConnParentProps.is() && hasProperty(sPropFormatsSupplier, xConnParentProps))
921 xConnParentProps->getPropertyValue(sPropFormatsSupplier) >>= xReturn;
923 else if(_bAlloweDefault && _rxContext.is())
925 xReturn = NumberFormatsSupplier::createWithDefaultLocale( _rxContext );
927 return xReturn;
930 void TransferFormComponentProperties(
931 const Reference< XPropertySet>& xOldProps,
932 const Reference< XPropertySet>& xNewProps,
933 const Locale& _rLocale)
937 OSL_ENSURE( xOldProps.is() && xNewProps.is(), "TransferFormComponentProperties: invalid source/dest!" );
938 if ( !xOldProps.is() || !xNewProps.is() )
939 return;
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());
945 const Sequence< Property> aOldProperties = xOldInfo->getProperties();
946 const Sequence< Property> aNewProperties = xNewInfo->getProperties();
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 );
963 for (const Property& rOldProp : aOldProperties)
965 if ( rOldProp.Name != "DefaultControl" && rOldProp.Name != "LabelControl" )
967 // binary search
968 const Property* pResult = std::lower_bound(
969 aNewProperties.begin(), aNewProperties.end(), rOldProp, ::comphelper::PropertyCompareByName());
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
978 xNewProps->setPropertyValue(pResult->Name, xOldProps->getPropertyValue(pResult->Name));
980 catch(IllegalArgumentException const &)
982 TOOLS_WARN_EXCEPTION( "connectivity.commontools", "TransferFormComponentProperties : could not transfer the value for property \""
983 << pResult->Name << "\"");
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 );
995 if (!bOldIsFormatted && !bNewIsFormatted)
996 return; // nothing to do
998 if (bOldIsFormatted && bNewIsFormatted)
999 // if both fields are formatted we do no conversions
1000 return;
1002 if (bOldIsFormatted)
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())
1008 Reference< XNumberFormatsSupplier> xSupplier;
1009 xOldProps->getPropertyValue(sPropFormatsSupplier) >>= xSupplier;
1010 if (xSupplier.is())
1012 Reference< XNumberFormats> xFormats(xSupplier->getNumberFormats());
1013 Reference< XPropertySet> xFormat(xFormats->getByKey(getINT32(aFormatKey)));
1014 if (hasProperty(sPropCurrencySymbol, xFormat))
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);
1022 if (hasProperty(sPropDecimals, xFormat) && hasProperty(sPropDecimals, xNewProps))
1023 xNewProps->setPropertyValue(sPropDecimals, xFormat->getPropertyValue(sPropDecimals));
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))
1033 OSL_ENSURE(aEffectiveMin.getValueTypeClass() == TypeClass_DOUBLE,
1034 "TransferFormComponentProperties : invalid property type !");
1035 xNewProps->setPropertyValue(sPropValueMin, aEffectiveMin);
1038 Any aEffectiveMax( xOldProps->getPropertyValue(sPropEffectiveMax) );
1039 if (aEffectiveMax.hasValue())
1040 { // analog
1041 if (hasProperty(sPropValueMax, xNewProps))
1043 OSL_ENSURE(aEffectiveMax.getValueTypeClass() == TypeClass_DOUBLE,
1044 "TransferFormComponentProperties : invalid property type !");
1045 xNewProps->setPropertyValue(sPropValueMax, aEffectiveMax);
1049 // then we can still convert and copy the default values
1050 Any aEffectiveDefault( xOldProps->getPropertyValue(sPropEffectiveDefault) );
1051 if (aEffectiveDefault.hasValue())
1053 bool bIsString = aEffectiveDefault.getValueTypeClass() == TypeClass_STRING;
1054 OSL_ENSURE(bIsString || aEffectiveDefault.getValueTypeClass() == TypeClass_DOUBLE,
1055 "TransferFormComponentProperties : invalid property type !");
1056 // The Effective-Properties should always be void or string or double...
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));
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));
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);
1076 if (hasProperty(sPropDefaultText, xNewProps) && bIsString)
1077 { // and here the OUString
1078 xNewProps->setPropertyValue(sPropDefaultText, aEffectiveDefault);
1081 // nyi: The translation between doubles and OUString would offer more alternatives
1085 // The other direction: the new Control shall be formatted
1086 if (bNewIsFormatted)
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())
1094 Reference< XNumberFormats> xFormats(xSupplier->getNumberFormats());
1096 // Set number of decimals
1097 sal_Int16 nDecimals = 2;
1098 if (hasProperty(sPropDecimalAccuracy, xOldProps))
1099 xOldProps->getPropertyValue(sPropDecimalAccuracy) >>= nDecimals;
1101 // base format (depending on the ClassId of the old Set)
1102 sal_Int32 nBaseKey = 0;
1103 if (hasProperty(sPropClassId, xOldProps))
1105 Reference< XNumberFormatTypes> xTypeList(xFormats, UNO_QUERY);
1106 if (xTypeList.is())
1108 sal_Int16 nClassId = 0;
1109 xOldProps->getPropertyValue(sPropClassId) >>= nClassId;
1110 switch (nClassId)
1112 case FormComponentType::DATEFIELD :
1113 nBaseKey = xTypeList->getStandardFormat(NumberFormat::DATE, _rLocale);
1114 break;
1116 case FormComponentType::TIMEFIELD :
1117 nBaseKey = xTypeList->getStandardFormat(NumberFormat::TIME, _rLocale);
1118 break;
1120 case FormComponentType::CURRENCYFIELD :
1121 nBaseKey = xTypeList->getStandardFormat(NumberFormat::CURRENCY, _rLocale);
1122 break;
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
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);
1138 xNewProps->setPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FORMATKEY), Any(nKey));
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);
1150 // Default-Value
1151 Any aNewDefault;
1152 if (hasProperty(sPropDefaultDate, xOldProps))
1154 Any aDate( xOldProps->getPropertyValue(sPropDefaultDate) );
1155 if (aDate.hasValue())
1156 aNewDefault <<= DBTypeConversion::toDouble(*o3tl::doAccess<Date>(aDate));
1159 if (hasProperty(sPropDefaultTime, xOldProps))
1161 Any aTime( xOldProps->getPropertyValue(sPropDefaultTime) );
1162 if (aTime.hasValue())
1163 aNewDefault <<= DBTypeConversion::toDouble(*o3tl::doAccess<Time>(aTime));
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);
1172 if (aNewDefault.hasValue())
1173 xNewProps->setPropertyValue(sPropEffectiveDefault, aNewDefault);
1176 catch(const Exception&)
1178 TOOLS_WARN_EXCEPTION( "connectivity.commontools", "TransferFormComponentProperties" );
1182 bool canInsert(const Reference< XPropertySet>& _rxCursorSet)
1184 return (_rxCursorSet.is() && (getINT32(_rxCursorSet->getPropertyValue(u"Privileges"_ustr)) & Privilege::INSERT) != 0);
1187 bool canUpdate(const Reference< XPropertySet>& _rxCursorSet)
1189 return (_rxCursorSet.is() && (getINT32(_rxCursorSet->getPropertyValue(u"Privileges"_ustr)) & Privilege::UPDATE) != 0);
1192 bool canDelete(const Reference< XPropertySet>& _rxCursorSet)
1194 return (_rxCursorSet.is() && (getINT32(_rxCursorSet->getPropertyValue(u"Privileges"_ustr)) & Privilege::DELETE) != 0);
1197 Reference< XDataSource> findDataSource(const Reference< XInterface >& _xParent)
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())
1207 Reference< XChild> xChild(_xParent, UNO_QUERY);
1208 if ( xChild.is() )
1209 xDataSource = findDataSource(xChild->getParent());
1211 return xDataSource;
1214 static Reference< XSingleSelectQueryComposer > getComposedRowSetStatement( const Reference< XPropertySet >& _rxRowSet, const Reference< XComponentContext >& _rxContext, const Reference< XWindow >& _rxParent )
1216 Reference< XSingleSelectQueryComposer > xComposer;
1219 Reference< XConnection> xConn = connectRowset( Reference< XRowSet >( _rxRowSet, UNO_QUERY ), _rxContext, _rxParent );
1220 if ( xConn.is() ) // implies _rxRowSet.is()
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)
1225 sal_Int32 nCommandType = CommandType::COMMAND;
1226 OUString sCommand;
1227 bool bEscapeProcessing = false;
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 );
1233 StatementComposer aComposer( xConn, sCommand, nCommandType, bEscapeProcessing );
1234 // append sort
1235 aComposer.setOrder( getString( _rxRowSet->getPropertyValue(u"Order"_ustr) ) );
1237 // append filter
1238 bool bApplyFilter = true;
1239 _rxRowSet->getPropertyValue(u"ApplyFilter"_ustr) >>= bApplyFilter;
1240 if ( bApplyFilter )
1242 aComposer.setFilter( getString( _rxRowSet->getPropertyValue(u"Filter"_ustr) ) );
1243 aComposer.setHavingClause( getString( _rxRowSet->getPropertyValue(u"HavingClause"_ustr) ) );
1246 aComposer.getQuery();
1248 xComposer = aComposer.getComposer();
1249 aComposer.setDisposeComposer( false );
1252 catch( const SQLException& )
1254 throw;
1256 catch( const Exception& )
1258 DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
1261 return xComposer;
1264 Reference< XSingleSelectQueryComposer > getCurrentSettingsComposer(
1265 const Reference< XPropertySet>& _rxRowSetProps,
1266 const Reference< XComponentContext>& _rxContext,
1267 const Reference< XWindow >& _rxParent)
1269 Reference< XSingleSelectQueryComposer > xReturn;
1272 xReturn = getComposedRowSetStatement( _rxRowSetProps, _rxContext, _rxParent );
1274 catch( const SQLException& )
1276 throw;
1278 catch( const Exception& )
1280 TOOLS_WARN_EXCEPTION( "connectivity.commontools", "::getCurrentSettingsComposer : caught an exception !" );
1283 return xReturn;
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)
1293 return impl_doComposeTableName( _rxMetaData, _rCatalog, _rSchema, _rName, _bQuote, _eComposeRule );
1296 OUString composeTableNameForSelect( const Reference< XConnection >& _rxConnection,
1297 const OUString& _rCatalog, const OUString& _rSchema, const OUString& _rName )
1299 bool bUseCatalogInSelect = isDataSourcePropertyEnabled( _rxConnection, u"UseCatalogInSelect"_ustr, true );
1300 bool bUseSchemaInSelect = isDataSourcePropertyEnabled( _rxConnection, u"UseSchemaInSelect"_ustr, true );
1302 return impl_doComposeTableName(
1303 _rxConnection->getMetaData(),
1304 bUseCatalogInSelect ? _rCatalog : OUString(),
1305 bUseSchemaInSelect ? _rSchema : OUString(),
1306 _rName,
1307 true,
1308 EComposeRule::InDataManipulation
1312 namespace
1314 void lcl_getTableNameComponents( const Reference<XPropertySet>& _xTable,
1315 OUString& _out_rCatalog, OUString& _out_rSchema, OUString& _out_rName )
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)) )
1324 if ( xInfo->hasPropertyByName(rPropMap.getNameByIndex(PROPERTY_ID_CATALOGNAME))
1325 && xInfo->hasPropertyByName(rPropMap.getNameByIndex(PROPERTY_ID_SCHEMANAME)) )
1327 _xTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_CATALOGNAME)) >>= _out_rCatalog;
1328 _xTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_SCHEMANAME)) >>= _out_rSchema;
1330 _xTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME)) >>= _out_rName;
1332 else
1333 OSL_FAIL( "::dbtools::lcl_getTableNameComponents: this is no table object!" );
1337 OUString composeTableNameForSelect( const Reference< XConnection >& _rxConnection, const Reference<XPropertySet>& _xTable )
1339 OUString sCatalog, sSchema, sName;
1340 lcl_getTableNameComponents( _xTable, sCatalog, sSchema, sName );
1342 return composeTableNameForSelect( _rxConnection, sCatalog, sSchema, sName );
1345 OUString composeTableName(const Reference<XDatabaseMetaData>& _xMetaData,
1346 const Reference<XPropertySet>& _xTable,
1347 EComposeRule _eComposeRule,
1348 bool _bQuote )
1350 OUString sCatalog, sSchema, sName;
1351 lcl_getTableNameComponents( _xTable, sCatalog, sSchema, sName );
1353 return impl_doComposeTableName(
1354 _xMetaData,
1355 sCatalog,
1356 sSchema,
1357 sName,
1358 _bQuote,
1359 _eComposeRule
1363 sal_Int32 getSearchColumnFlag( const Reference< XConnection>& _rxConn,sal_Int32 _nDataType)
1365 sal_Int32 nSearchFlag = 0;
1366 Reference<XResultSet> xSet = _rxConn->getMetaData()->getTypeInfo();
1367 if(xSet.is())
1369 Reference<XRow> xRow(xSet,UNO_QUERY);
1370 while(xSet->next())
1372 if(xRow->getInt(2) == _nDataType)
1374 nSearchFlag = xRow->getInt(9);
1375 break;
1379 return nSearchFlag;
1382 OUString createUniqueName( const Sequence< OUString >& _rNames, const OUString& _rBaseName, bool _bStartWithNumber )
1384 std::set< OUString > aUsedNames(_rNames.begin(), _rNames.end());
1386 OUString sName( _rBaseName );
1387 sal_Int32 nPos = 1;
1388 if ( _bStartWithNumber )
1389 sName += OUString::number( nPos );
1391 while ( aUsedNames.find( sName ) != aUsedNames.end() )
1393 sName = _rBaseName + OUString::number( ++nPos );
1395 return sName;
1398 OUString createUniqueName(const Reference<XNameAccess>& _rxContainer,const OUString& _rBaseName, bool _bStartWithNumber)
1400 Sequence< OUString > aElementNames;
1402 OSL_ENSURE( _rxContainer.is(), "createUniqueName: invalid container!" );
1403 if ( _rxContainer.is() )
1404 aElementNames = _rxContainer->getElementNames();
1406 return createUniqueName( aElementNames, _rBaseName, _bStartWithNumber );
1409 void showError(const SQLExceptionInfo& _rInfo,
1410 const Reference< XWindow>& _xParent,
1411 const Reference< XComponentContext >& _rxContext)
1413 if (_rInfo.isValid())
1417 Reference< XExecutableDialog > xErrorDialog = ErrorMessageDialog::create( _rxContext, u""_ustr, _xParent, _rInfo.get() );
1418 xErrorDialog->execute();
1420 catch(const Exception&)
1422 OSL_FAIL("showError: could not display the error message!");
1427 bool implUpdateObject(const Reference< XRowUpdate >& _rxUpdatedObject,
1428 const sal_Int32 _nColumnIndex, const Any& _rValue)
1430 bool bSuccessfullyReRouted = true;
1431 switch (_rValue.getValueTypeClass())
1433 case TypeClass_ANY:
1435 bSuccessfullyReRouted = implUpdateObject(_rxUpdatedObject, _nColumnIndex, _rValue);
1437 break;
1439 case TypeClass_VOID:
1440 _rxUpdatedObject->updateNull(_nColumnIndex);
1441 break;
1443 case TypeClass_STRING:
1444 _rxUpdatedObject->updateString(_nColumnIndex, *o3tl::forceAccess<OUString>(_rValue));
1445 break;
1447 case TypeClass_BOOLEAN:
1448 _rxUpdatedObject->updateBoolean(_nColumnIndex, *o3tl::forceAccess<bool>(_rValue));
1449 break;
1451 case TypeClass_BYTE:
1452 _rxUpdatedObject->updateByte(_nColumnIndex, *o3tl::forceAccess<sal_Int8>(_rValue));
1453 break;
1455 case TypeClass_UNSIGNED_SHORT:
1456 case TypeClass_SHORT:
1457 _rxUpdatedObject->updateShort(_nColumnIndex, *o3tl::forceAccess<sal_Int16>(_rValue));
1458 break;
1460 case TypeClass_CHAR:
1461 _rxUpdatedObject->updateString(_nColumnIndex,OUString(*o3tl::forceAccess<sal_Unicode>(_rValue)));
1462 break;
1464 case TypeClass_UNSIGNED_LONG:
1465 case TypeClass_LONG:
1466 _rxUpdatedObject->updateInt(_nColumnIndex, *o3tl::forceAccess<sal_Int32>(_rValue));
1467 break;
1469 case TypeClass_HYPER:
1471 sal_Int64 nValue = 0;
1472 OSL_VERIFY( _rValue >>= nValue );
1473 _rxUpdatedObject->updateLong( _nColumnIndex, nValue );
1475 break;
1477 case TypeClass_FLOAT:
1478 _rxUpdatedObject->updateFloat(_nColumnIndex, *o3tl::forceAccess<float>(_rValue));
1479 break;
1481 case TypeClass_DOUBLE:
1482 _rxUpdatedObject->updateDouble(_nColumnIndex, *o3tl::forceAccess<double>(_rValue));
1483 break;
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;
1502 case TypeClass_INTERFACE:
1503 if (auto xStream = o3tl::tryAccess<Reference<XInputStream>>(_rValue))
1505 _rxUpdatedObject->updateBinaryStream(_nColumnIndex, *xStream, (*xStream)->available());
1506 break;
1508 [[fallthrough]];
1509 default:
1510 bSuccessfullyReRouted = false;
1513 return bSuccessfullyReRouted;
1516 bool implSetObject( const Reference< XParameters >& _rxParameters,
1517 const sal_Int32 _nColumnIndex, const Any& _rValue)
1519 bool bSuccessfullyReRouted = true;
1520 switch (_rValue.getValueTypeClass())
1522 case TypeClass_UNSIGNED_HYPER:
1524 sal_uInt64 nValue = 0;
1525 OSL_VERIFY( _rValue >>= nValue );
1526 _rxParameters->setString(_nColumnIndex, OUString::number(nValue));
1528 break;
1530 case TypeClass_UNSIGNED_LONG:
1531 case TypeClass_HYPER:
1533 sal_Int64 nValue = 0;
1534 OSL_VERIFY( _rValue >>= nValue );
1535 _rxParameters->setLong( _nColumnIndex, nValue );
1537 break;
1539 case TypeClass_ANY:
1541 bSuccessfullyReRouted = implSetObject(_rxParameters, _nColumnIndex, _rValue);
1543 break;
1545 case TypeClass_VOID:
1546 _rxParameters->setNull(_nColumnIndex,DataType::VARCHAR);
1547 break;
1549 case TypeClass_STRING:
1550 _rxParameters->setString(_nColumnIndex, *o3tl::forceAccess<OUString>(_rValue));
1551 break;
1553 case TypeClass_BOOLEAN:
1554 _rxParameters->setBoolean(_nColumnIndex, *o3tl::forceAccess<bool>(_rValue));
1555 break;
1557 case TypeClass_BYTE:
1558 _rxParameters->setByte(_nColumnIndex, *o3tl::forceAccess<sal_Int8>(_rValue));
1559 break;
1561 case TypeClass_SHORT:
1562 _rxParameters->setShort(_nColumnIndex, *o3tl::forceAccess<sal_Int16>(_rValue));
1563 break;
1565 case TypeClass_CHAR:
1566 _rxParameters->setString(_nColumnIndex, OUString(*o3tl::forceAccess<sal_Unicode>(_rValue)));
1567 break;
1569 case TypeClass_UNSIGNED_SHORT:
1570 case TypeClass_LONG:
1572 sal_Int32 nValue = 0;
1573 OSL_VERIFY( _rValue >>= nValue );
1574 _rxParameters->setInt(_nColumnIndex, nValue);
1575 break;
1578 case TypeClass_FLOAT:
1579 _rxParameters->setFloat(_nColumnIndex, *o3tl::forceAccess<float>(_rValue));
1580 break;
1582 case TypeClass_DOUBLE:
1583 _rxParameters->setDouble(_nColumnIndex, *o3tl::forceAccess<double>(_rValue));
1584 break;
1586 case TypeClass_SEQUENCE:
1587 if (auto s = o3tl::tryAccess<Sequence< sal_Int8 >>(_rValue))
1589 _rxParameters->setBytes(_nColumnIndex, *s);
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;
1605 case TypeClass_INTERFACE:
1606 if (Reference<XInputStream> xStream; _rValue >>= xStream)
1608 _rxParameters->setBinaryStream(_nColumnIndex, xStream, xStream->available());
1609 break;
1611 [[fallthrough]];
1612 default:
1613 bSuccessfullyReRouted = false;
1617 return bSuccessfullyReRouted;
1620 namespace
1622 class OParameterWrapper : public ::cppu::WeakImplHelper< XIndexAccess >
1624 std::vector<bool, std::allocator<bool> > m_aSet;
1625 Reference<XIndexAccess> m_xSource;
1626 public:
1627 OParameterWrapper(std::vector<bool, std::allocator<bool> >&& _aSet,const Reference<XIndexAccess>& _xSource)
1628 : m_aSet(std::move(_aSet)), m_xSource(_xSource) {}
1629 private:
1630 // css::container::XElementAccess
1631 virtual Type SAL_CALL getElementType() override
1633 return m_xSource->getElementType();
1635 virtual sal_Bool SAL_CALL hasElements( ) override
1637 if ( m_aSet.empty() )
1638 return m_xSource->hasElements();
1639 return std::count(m_aSet.begin(),m_aSet.end(),false) != 0;
1641 // css::container::XIndexAccess
1642 virtual sal_Int32 SAL_CALL getCount( ) override
1644 if ( m_aSet.empty() )
1645 return m_xSource->getCount();
1646 return std::count(m_aSet.begin(),m_aSet.end(),false);
1648 virtual Any SAL_CALL getByIndex( sal_Int32 Index ) override
1650 if ( m_aSet.empty() )
1651 return m_xSource->getByIndex(Index);
1652 if ( Index < 0 || m_aSet.size() < o3tl::make_unsigned(Index) )
1653 throw IndexOutOfBoundsException();
1655 std::vector<bool, std::allocator<bool> >::const_iterator aIter = m_aSet.begin();
1656 std::vector<bool, std::allocator<bool> >::const_iterator aEnd = m_aSet.end();
1657 sal_Int32 i = 0;
1658 for(; aIter != aEnd && i <= Index; ++aIter)
1660 if ( !*aIter )
1662 ++i;
1665 auto nParamPos = static_cast<sal_Int32>(std::distance(m_aSet.cbegin(), aIter)) - 1;
1666 return m_xSource->getByIndex(nParamPos);
1671 void askForParameters(const Reference< XSingleSelectQueryComposer >& _xComposer,
1672 const Reference<XParameters>& _xParameters,
1673 const Reference< XConnection>& _xConnection,
1674 const Reference< XInteractionHandler >& _rxHandler,
1675 const std::vector<bool, std::allocator<bool> >& _aParametersSet)
1677 OSL_ENSURE(_xComposer.is(),"dbtools::askForParameters XSQLQueryComposer is null!");
1678 OSL_ENSURE(_xParameters.is(),"dbtools::askForParameters XParameters is null!");
1679 OSL_ENSURE(_xConnection.is(),"dbtools::askForParameters XConnection is null!");
1680 OSL_ENSURE(_rxHandler.is(),"dbtools::askForParameters XInteractionHandler is null!");
1682 // we have to set this here again because getCurrentSettingsComposer can force a setpropertyvalue
1683 Reference<XParametersSupplier> xParameters(_xComposer, UNO_QUERY);
1685 Reference<XIndexAccess> xParamsAsIndicies = xParameters.is() ? xParameters->getParameters() : Reference<XIndexAccess>();
1686 sal_Int32 nParamCount = xParamsAsIndicies.is() ? xParamsAsIndicies->getCount() : 0;
1687 std::vector<bool, std::allocator<bool> > aNewParameterSet( _aParametersSet );
1688 if ( !(nParamCount && std::count(aNewParameterSet.begin(),aNewParameterSet.end(),true) != nParamCount) )
1689 return;
1691 static const OUString PROPERTY_NAME(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME));
1692 aNewParameterSet.resize(nParamCount ,false);
1693 typedef std::map< OUString, std::vector<sal_Int32> > TParameterPositions;
1694 TParameterPositions aParameterNames;
1695 for(sal_Int32 i = 0; i < nParamCount; ++i)
1697 Reference<XPropertySet> xParam(xParamsAsIndicies->getByIndex(i),UNO_QUERY);
1698 OUString sName;
1699 xParam->getPropertyValue(PROPERTY_NAME) >>= sName;
1701 TParameterPositions::const_iterator aFind = aParameterNames.find(sName);
1702 if ( aFind != aParameterNames.end() )
1703 aNewParameterSet[i] = true;
1704 aParameterNames[sName].push_back(i+1);
1706 // build an interaction request
1707 // two continuations (Ok and Cancel)
1708 rtl::Reference<OInteractionAbort> pAbort = new OInteractionAbort;
1709 rtl::Reference<OParameterContinuation> pParams = new OParameterContinuation;
1710 // the request
1711 ParametersRequest aRequest;
1712 Reference<XIndexAccess> xWrappedParameters = new OParameterWrapper(std::move(aNewParameterSet),xParamsAsIndicies);
1713 aRequest.Parameters = xWrappedParameters;
1714 aRequest.Connection = _xConnection;
1715 rtl::Reference<OInteractionRequest> pRequest = new OInteractionRequest(Any(aRequest));
1716 // some knittings
1717 pRequest->addContinuation(pAbort);
1718 pRequest->addContinuation(pParams);
1720 // execute the request
1721 _rxHandler->handle(pRequest);
1723 if (!pParams->wasSelected())
1725 // canceled by the user (i.e. (s)he canceled the dialog)
1726 RowSetVetoException e;
1727 e.ErrorCode = ParameterInteractionCancelled;
1728 throw e;
1731 // now transfer the values from the continuation object to the parameter columns
1732 Sequence< PropertyValue > aFinalValues = pParams->getValues();
1733 for (sal_Int32 i = 0; i < aFinalValues.getLength(); ++i)
1735 Reference< XPropertySet > xParamColumn(xWrappedParameters->getByIndex(i),UNO_QUERY);
1736 if (xParamColumn.is())
1738 OUString sName;
1739 xParamColumn->getPropertyValue(PROPERTY_NAME) >>= sName;
1740 OSL_ENSURE(sName == aFinalValues[i].Name, "::dbaui::askForParameters: inconsistent parameter names!");
1742 // determine the field type and ...
1743 sal_Int32 nParamType = 0;
1744 xParamColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE)) >>= nParamType;
1745 // ... the scale of the parameter column
1746 sal_Int32 nScale = 0;
1747 if (hasProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE), xParamColumn))
1748 xParamColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE)) >>= nScale;
1749 // (the index of the parameters is one-based)
1750 TParameterPositions::const_iterator aFind = aParameterNames.find(aFinalValues[i].Name);
1751 for(const auto& rItem : aFind->second)
1753 if ( _aParametersSet.empty() || !_aParametersSet[rItem-1] )
1755 _xParameters->setObjectWithInfo(rItem, aFinalValues[i].Value, nParamType, nScale);
1762 void setObjectWithInfo(const Reference<XParameters>& _xParams,
1763 sal_Int32 parameterIndex,
1764 const Any& x,
1765 sal_Int32 sqlType,
1766 sal_Int32 scale)
1768 ORowSetValue aVal;
1769 aVal.fill(x);
1770 setObjectWithInfo(_xParams,parameterIndex,aVal,sqlType,scale);
1773 void setObjectWithInfo(const Reference<XParameters>& _xParams,
1774 sal_Int32 parameterIndex,
1775 const ::connectivity::ORowSetValue& _rValue,
1776 sal_Int32 sqlType,
1777 sal_Int32 scale)
1779 if ( _rValue.isNull() )
1780 _xParams->setNull(parameterIndex,sqlType);
1781 else
1783 switch(sqlType)
1785 case DataType::DECIMAL:
1786 case DataType::NUMERIC:
1787 _xParams->setObjectWithInfo(parameterIndex,_rValue.makeAny(),sqlType,scale);
1788 break;
1789 case DataType::CHAR:
1790 case DataType::VARCHAR:
1791 case DataType::LONGVARCHAR:
1792 _xParams->setString(parameterIndex,_rValue.getString());
1793 break;
1794 case DataType::CLOB:
1796 Any x(_rValue.makeAny());
1797 OUString sValue;
1798 if ( x >>= sValue )
1799 _xParams->setString(parameterIndex,sValue);
1800 else
1802 Reference< XClob > xClob;
1803 if(x >>= xClob)
1804 _xParams->setClob(parameterIndex,xClob);
1805 else
1807 Reference< css::io::XInputStream > xStream;
1808 if(x >>= xStream)
1809 _xParams->setCharacterStream(parameterIndex,xStream,xStream->available());
1813 break;
1814 case DataType::BIGINT:
1815 if ( _rValue.isSigned() )
1816 _xParams->setLong(parameterIndex,_rValue.getLong());
1817 else
1818 _xParams->setString(parameterIndex,_rValue.getString());
1819 break;
1821 case DataType::FLOAT:
1822 _xParams->setFloat(parameterIndex,_rValue.getFloat());
1823 break;
1824 case DataType::REAL:
1825 case DataType::DOUBLE:
1826 _xParams->setDouble(parameterIndex,_rValue.getDouble());
1827 break;
1828 case DataType::DATE:
1829 _xParams->setDate(parameterIndex,_rValue.getDate());
1830 break;
1831 case DataType::TIME:
1832 _xParams->setTime(parameterIndex,_rValue.getTime());
1833 break;
1834 case DataType::TIMESTAMP:
1835 _xParams->setTimestamp(parameterIndex,_rValue.getDateTime());
1836 break;
1837 case DataType::BINARY:
1838 case DataType::VARBINARY:
1839 case DataType::LONGVARBINARY:
1840 case DataType::BLOB:
1842 Any x(_rValue.makeAny());
1843 Sequence< sal_Int8> aBytes;
1844 if(x >>= aBytes)
1845 _xParams->setBytes(parameterIndex,aBytes);
1846 else
1848 Reference< XBlob > xBlob;
1849 if(x >>= xBlob)
1850 _xParams->setBlob(parameterIndex,xBlob);
1851 else
1853 Reference< XClob > xClob;
1854 if(x >>= xClob)
1855 _xParams->setClob(parameterIndex,xClob);
1856 else
1858 Reference< css::io::XInputStream > xBinStream;
1859 if(x >>= xBinStream)
1860 _xParams->setBinaryStream(parameterIndex,xBinStream,xBinStream->available());
1865 break;
1866 case DataType::BIT:
1867 case DataType::BOOLEAN:
1868 _xParams->setBoolean(parameterIndex,_rValue.getBool());
1869 break;
1870 case DataType::TINYINT:
1871 if ( _rValue.isSigned() )
1872 _xParams->setByte(parameterIndex,_rValue.getInt8());
1873 else
1874 _xParams->setShort(parameterIndex,_rValue.getInt16());
1875 break;
1876 case DataType::SMALLINT:
1877 if ( _rValue.isSigned() )
1878 _xParams->setShort(parameterIndex,_rValue.getInt16());
1879 else
1880 _xParams->setInt(parameterIndex,_rValue.getInt32());
1881 break;
1882 case DataType::INTEGER:
1883 if ( _rValue.isSigned() )
1884 _xParams->setInt(parameterIndex,_rValue.getULong());
1885 else
1886 _xParams->setLong(parameterIndex,_rValue.getLong());
1887 break;
1888 default:
1890 ::connectivity::SharedResources aResources;
1891 const OUString sError( aResources.getResourceStringWithSubstitution(
1892 STR_UNKNOWN_PARA_TYPE,
1893 "$position$", OUString::number(parameterIndex)
1894 ) );
1895 ::dbtools::throwGenericSQLException(sError,nullptr);
1901 void getBooleanComparisonPredicate( std::u16string_view _rExpression, const bool _bValue, const sal_Int32 _nBooleanComparisonMode,
1902 OUStringBuffer& _out_rSQLPredicate )
1904 switch ( _nBooleanComparisonMode )
1906 case BooleanComparisonMode::IS_LITERAL:
1907 _out_rSQLPredicate.append( _rExpression );
1908 if ( _bValue )
1909 _out_rSQLPredicate.append( " IS TRUE" );
1910 else
1911 _out_rSQLPredicate.append( " IS FALSE" );
1912 break;
1914 case BooleanComparisonMode::EQUAL_LITERAL:
1915 _out_rSQLPredicate.append( _rExpression );
1916 _out_rSQLPredicate.appendAscii( _bValue ? " = TRUE" : " = FALSE" );
1917 break;
1919 case BooleanComparisonMode::ACCESS_COMPAT:
1920 if ( _bValue )
1922 _out_rSQLPredicate.append( " NOT ( ( " );
1923 _out_rSQLPredicate.append( _rExpression );
1924 _out_rSQLPredicate.append( " = 0 ) OR ( " );
1925 _out_rSQLPredicate.append( _rExpression );
1926 _out_rSQLPredicate.append( " IS NULL ) )" );
1928 else
1930 _out_rSQLPredicate.append( _rExpression );
1931 _out_rSQLPredicate.append( " = 0" );
1933 break;
1935 case BooleanComparisonMode::EQUAL_INTEGER:
1936 // fall through
1937 default:
1938 _out_rSQLPredicate.append( _rExpression );
1939 _out_rSQLPredicate.appendAscii( _bValue ? " = 1" : " = 0" );
1940 break;
1944 } // namespace dbtools
1946 namespace connectivity
1948 void checkDisposed(bool _bThrow)
1950 if (_bThrow)
1951 throw DisposedException();
1955 OSQLColumns::const_iterator find(const OSQLColumns::const_iterator& first,
1956 const OSQLColumns::const_iterator& last,
1957 std::u16string_view _rVal,
1958 const ::comphelper::UStringMixEqual& _rCase)
1960 OUString sName = OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME);
1961 return find(first,last,sName,_rVal,_rCase);
1964 OSQLColumns::const_iterator findRealName(const OSQLColumns::const_iterator& first,
1965 const OSQLColumns::const_iterator& last,
1966 std::u16string_view _rVal,
1967 const ::comphelper::UStringMixEqual& _rCase)
1969 OUString sRealName = OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_REALNAME);
1970 return find(first,last,sRealName,_rVal,_rCase);
1973 OSQLColumns::const_iterator find(OSQLColumns::const_iterator first,
1974 const OSQLColumns::const_iterator& last,
1975 const OUString& _rProp,
1976 std::u16string_view _rVal,
1977 const ::comphelper::UStringMixEqual& _rCase)
1979 while (first != last && !_rCase(getString((*first)->getPropertyValue(_rProp)),_rVal))
1980 ++first;
1981 return first;
1984 namespace dbase
1986 bool dbfDecodeCharset(rtl_TextEncoding &_out_encoding, sal_uInt8 nType, sal_uInt8 nCodepage)
1988 switch (nType)
1990 // dBaseIII header doesn't contain language driver ID
1991 // See http://dbase.free.fr/tlcharge/structure%20tables.pdf
1992 case dBaseIII:
1993 case dBaseIIIMemo:
1994 break;
1995 case dBaseIV:
1996 case dBaseV:
1997 case VisualFoxPro:
1998 case VisualFoxProAuto:
1999 case dBaseFS:
2000 case dBaseFSMemo:
2001 case dBaseIVMemoSQL:
2002 case FoxProMemo:
2004 if (nCodepage != 0x00)
2006 auto eEncoding(RTL_TEXTENCODING_DONTKNOW);
2007 switch(nCodepage)
2009 case 0x01: eEncoding = RTL_TEXTENCODING_IBM_437; break; // DOS USA code page 437
2010 case 0x02: eEncoding = RTL_TEXTENCODING_IBM_850; break; // DOS Multilingual code page 850
2011 case 0x03: eEncoding = RTL_TEXTENCODING_MS_1252; break; // Windows ANSI code page 1252
2012 case 0x04: eEncoding = RTL_TEXTENCODING_APPLE_ROMAN; break; // Standard Macintosh
2013 case 0x64: eEncoding = RTL_TEXTENCODING_IBM_852; break; // EE MS-DOS code page 852
2014 case 0x65: eEncoding = RTL_TEXTENCODING_IBM_866; break; // Russian MS-DOS code page 866
2015 case 0x66: eEncoding = RTL_TEXTENCODING_IBM_865; break; // Nordic MS-DOS code page 865
2016 case 0x67: eEncoding = RTL_TEXTENCODING_IBM_861; break; // Icelandic MS-DOS
2017 case 0x68: eEncoding = RTL_TEXTENCODING_KAMENICKY; break; // Kamenicky (Czech) MS-DOS
2018 case 0x69: eEncoding = RTL_TEXTENCODING_MAZOVIA; break; // Mazovia (Polish) MS-DOS
2019 case 0x6A: eEncoding = RTL_TEXTENCODING_IBM_737; break; // Greek MS-DOS (437G)
2020 case 0x6B: eEncoding = RTL_TEXTENCODING_IBM_857; break; // Turkish MS-DOS
2021 case 0x6C: eEncoding = RTL_TEXTENCODING_IBM_863; break; // MS-DOS, Canada
2022 case 0x78: eEncoding = RTL_TEXTENCODING_MS_950; break; // Windows, Traditional Chinese
2023 case 0x79: eEncoding = RTL_TEXTENCODING_MS_949; break; // Windows, Korean (Hangul)
2024 case 0x7A: eEncoding = RTL_TEXTENCODING_MS_936; break; // Windows, Simplified Chinese
2025 case 0x7B: eEncoding = RTL_TEXTENCODING_MS_932; break; // Windows, Japanese (Shift-jis)
2026 case 0x7C: eEncoding = RTL_TEXTENCODING_MS_874; break; // Windows, Thai
2027 case 0x7D: eEncoding = RTL_TEXTENCODING_MS_1255; break; // Windows, Hebrew
2028 case 0x7E: eEncoding = RTL_TEXTENCODING_MS_1256; break; // Windows, Arabic
2029 case 0x96: eEncoding = RTL_TEXTENCODING_APPLE_CYRILLIC; break; // Russian Macintosh
2030 case 0x97: eEncoding = RTL_TEXTENCODING_APPLE_CENTEURO; break; // Eastern European Macintosh
2031 case 0x98: eEncoding = RTL_TEXTENCODING_APPLE_GREEK; break; // Greek Macintosh
2032 case 0xC8: eEncoding = RTL_TEXTENCODING_MS_1250; break; // Windows EE code page 1250
2033 case 0xC9: eEncoding = RTL_TEXTENCODING_MS_1251; break; // Russian Windows
2034 case 0xCA: eEncoding = RTL_TEXTENCODING_MS_1254; break; // Turkish Windows
2035 case 0xCB: eEncoding = RTL_TEXTENCODING_MS_1253; break; // Greek Windows
2036 case 0xCC: eEncoding = RTL_TEXTENCODING_MS_1257; break; // Windows, Baltic
2038 if(eEncoding != RTL_TEXTENCODING_DONTKNOW)
2040 _out_encoding = eEncoding;
2041 return true;
2046 return false;
2049 bool dbfReadCharset(rtl_TextEncoding &nCharSet, SvStream* dbf_Stream)
2051 sal_uInt8 nType=0;
2052 dbf_Stream->ReadUChar( nType );
2054 dbf_Stream->Seek(STREAM_SEEK_TO_BEGIN + 29);
2055 if (dbf_Stream->eof())
2057 return false;
2059 else
2061 sal_uInt8 nEncoding=0;
2062 dbf_Stream->ReadUChar( nEncoding );
2063 return dbfDecodeCharset(nCharSet, nType, nEncoding);
2069 } //namespace connectivity
2071 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */