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