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