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