1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_dbaccess.hxx" 26 27 #include "OptimisticSet.hxx" 28 #include "core_resource.hxx" 29 #include "core_resource.hrc" 30 #include <com/sun/star/beans/XPropertySet.hpp> 31 #include <com/sun/star/sdbc/XDatabaseMetaData.hpp> 32 #include <com/sun/star/sdbc/ColumnValue.hpp> 33 #include <com/sun/star/sdbc/XPreparedStatement.hpp> 34 #include <com/sun/star/sdbc/XParameters.hpp> 35 #include <com/sun/star/sdbc/XGeneratedResultSet.hpp> 36 #include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp> 37 #include <com/sun/star/sdb/SQLFilterOperator.hpp> 38 #include <com/sun/star/sdbc/XColumnLocate.hpp> 39 #include <com/sun/star/container/XIndexAccess.hpp> 40 #include "dbastrings.hrc" 41 #include "apitools.hxx" 42 #include <com/sun/star/sdbcx/XKeysSupplier.hpp> 43 #include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp> 44 #include <com/sun/star/sdbcx/XIndexesSupplier.hpp> 45 #include <cppuhelper/typeprovider.hxx> 46 #include <comphelper/types.hxx> 47 #include <com/sun/star/sdbcx/KeyType.hpp> 48 #include <connectivity/dbtools.hxx> 49 #include <connectivity/dbexception.hxx> 50 #include <list> 51 #include <algorithm> 52 #include <string.h> 53 #include <com/sun/star/io/XInputStream.hpp> 54 #include <com/sun/star/sdbcx/XTablesSupplier.hpp> 55 #include "querycomposer.hxx" 56 #include "composertools.hxx" 57 #include <tools/debug.hxx> 58 #include <string.h> 59 #include <rtl/logfile.hxx> 60 61 using namespace dbaccess; 62 using namespace ::connectivity; 63 using namespace ::dbtools; 64 using namespace ::com::sun::star::uno; 65 using namespace ::com::sun::star::beans; 66 using namespace ::com::sun::star::sdbc; 67 using namespace ::com::sun::star::sdb; 68 using namespace ::com::sun::star::sdbcx; 69 using namespace ::com::sun::star::container; 70 using namespace ::com::sun::star::lang; 71 using namespace ::com::sun::star::util; 72 using namespace ::com::sun::star::io; 73 using namespace ::com::sun::star; 74 using namespace ::cppu; 75 using namespace ::osl; 76 77 DECLARE_STL_USTRINGACCESS_MAP(::rtl::OUStringBuffer,TSQLStatements); 78 namespace 79 { 80 void lcl_fillKeyCondition(const ::rtl::OUString& i_sTableName,const ::rtl::OUString& i_sQuotedColumnName,const ORowSetValue& i_aValue,TSQLStatements& io_aKeyConditions) 81 { 82 ::rtl::OUStringBuffer& rKeyCondition = io_aKeyConditions[i_sTableName]; 83 if ( rKeyCondition.getLength() ) 84 rKeyCondition.appendAscii(" AND "); 85 rKeyCondition.append(i_sQuotedColumnName); 86 if ( i_aValue.isNull() ) 87 rKeyCondition.appendAscii(" IS NULL"); 88 else 89 rKeyCondition.appendAscii(" = ?"); 90 } 91 } 92 93 DBG_NAME(OptimisticSet) 94 // ------------------------------------------------------------------------- 95 OptimisticSet::OptimisticSet(const ::comphelper::ComponentContext& _rContext, 96 const Reference< XConnection>& i_xConnection, 97 const Reference< XSingleSelectQueryAnalyzer >& _xComposer, 98 const ORowSetValueVector& _aParameterValueForCache, 99 sal_Int32 i_nMaxRows, 100 sal_Int32& o_nRowCount) 101 :OKeySet(NULL,NULL,::rtl::OUString(),_xComposer,_aParameterValueForCache,i_nMaxRows,o_nRowCount) 102 ,m_aSqlParser( _rContext.getLegacyServiceFactory() ) 103 ,m_aSqlIterator( i_xConnection, Reference<XTablesSupplier>(_xComposer,UNO_QUERY)->getTables(), m_aSqlParser, NULL ) 104 ,m_bResultSetChanged(false) 105 { 106 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::OptimisticSet" ); 107 DBG_CTOR(OptimisticSet,NULL); 108 } 109 // ----------------------------------------------------------------------------- 110 OptimisticSet::~OptimisticSet() 111 { 112 DBG_DTOR(OptimisticSet,NULL); 113 } 114 // ----------------------------------------------------------------------------- 115 void OptimisticSet::construct(const Reference< XResultSet>& _xDriverSet,const ::rtl::OUString& i_sRowSetFilter) 116 { 117 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::construct" ); 118 OCacheSet::construct(_xDriverSet,i_sRowSetFilter); 119 initColumns(); 120 121 Reference<XDatabaseMetaData> xMeta = m_xConnection->getMetaData(); 122 bool bCase = (xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers()) ? true : false; 123 Reference<XColumnsSupplier> xQueryColSup(m_xComposer,UNO_QUERY); 124 const Reference<XNameAccess> xQueryColumns = xQueryColSup->getColumns(); 125 const Reference<XTablesSupplier> xTabSup(m_xComposer,UNO_QUERY); 126 const Reference<XNameAccess> xTables = xTabSup->getTables(); 127 const Sequence< ::rtl::OUString> aTableNames = xTables->getElementNames(); 128 const ::rtl::OUString* pTableNameIter = aTableNames.getConstArray(); 129 const ::rtl::OUString* pTableNameEnd = pTableNameIter + aTableNames.getLength(); 130 for( ; pTableNameIter != pTableNameEnd ; ++pTableNameIter) 131 { 132 ::std::auto_ptr<SelectColumnsMetaData> pKeyColumNames(new SelectColumnsMetaData(bCase)); 133 findTableColumnsMatching_throw(xTables->getByName(*pTableNameIter),*pTableNameIter,xMeta,xQueryColumns,pKeyColumNames); 134 m_pKeyColumnNames->insert(pKeyColumNames->begin(),pKeyColumNames->end()); 135 } 136 137 // the first row is empty because it's now easier for us to distinguish when we are beforefirst or first 138 // without extra variable to be set 139 m_aKeyMap.insert(OKeySetMatrix::value_type(0,OKeySetValue(NULL,::std::pair<sal_Int32,Reference<XRow> >(0,NULL)))); 140 m_aKeyIter = m_aKeyMap.begin(); 141 142 ::rtl::OUStringBuffer aFilter = createKeyFilter(); 143 144 Reference< XSingleSelectQueryComposer> xSourceComposer(m_xComposer,UNO_QUERY); 145 Reference< XMultiServiceFactory > xFactory(m_xConnection, UNO_QUERY_THROW); 146 Reference<XSingleSelectQueryComposer> xAnalyzer(xFactory->createInstance(SERVICE_NAME_SINGLESELECTQUERYCOMPOSER),UNO_QUERY); 147 ::rtl::OUString sQuery = xSourceComposer->getQuery(); 148 xAnalyzer->setElementaryQuery(xSourceComposer->getElementaryQuery()); 149 // check for joins 150 ::rtl::OUString aErrorMsg; 151 ::std::auto_ptr<OSQLParseNode> pStatementNode( m_aSqlParser.parseTree( aErrorMsg, sQuery ) ); 152 m_aSqlIterator.setParseTree( pStatementNode.get() ); 153 m_aSqlIterator.traverseAll(); 154 fillJoinedColumns_throw(m_aSqlIterator.getJoinConditions()); 155 156 const ::rtl::OUString sComposerFilter = m_xComposer->getFilter(); 157 if ( i_sRowSetFilter.getLength() || (sComposerFilter.getLength() && sComposerFilter != i_sRowSetFilter) ) 158 { 159 FilterCreator aFilterCreator; 160 if ( sComposerFilter.getLength() && sComposerFilter != i_sRowSetFilter ) 161 aFilterCreator.append( sComposerFilter ); 162 aFilterCreator.append( i_sRowSetFilter ); 163 aFilterCreator.append( aFilter.makeStringAndClear() ); 164 aFilter = aFilterCreator.getComposedAndClear(); 165 } 166 xAnalyzer->setFilter(aFilter.makeStringAndClear()); 167 m_xStatement = m_xConnection->prepareStatement(xAnalyzer->getQueryWithSubstitution()); 168 ::comphelper::disposeComponent(xAnalyzer); 169 } 170 // ------------------------------------------------------------------------- 171 // ::com::sun::star::sdbcx::XDeleteRows 172 Sequence< sal_Int32 > SAL_CALL OptimisticSet::deleteRows( const Sequence< Any >& /*rows*/ ,const connectivity::OSQLTable& /*_xTable*/) throw(SQLException, RuntimeException) 173 { 174 Sequence< sal_Int32 > aRet; 175 return aRet; 176 } 177 // ------------------------------------------------------------------------- 178 void SAL_CALL OptimisticSet::updateRow(const ORowSetRow& _rInsertRow ,const ORowSetRow& _rOrginalRow,const connectivity::OSQLTable& /*_xTable*/ ) throw(SQLException, RuntimeException) 179 { 180 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::updateRow" ); 181 if ( m_aJoinedKeyColumns.empty() ) 182 throw SQLException(); 183 // list all cloumns that should be set 184 static ::rtl::OUString s_sPara = ::rtl::OUString::createFromAscii(" = ?"); 185 ::rtl::OUString aQuote = getIdentifierQuoteString(); 186 static ::rtl::OUString aAnd = ::rtl::OUString::createFromAscii(" AND "); 187 ::rtl::OUString sIsNull(RTL_CONSTASCII_USTRINGPARAM(" IS NULL")); 188 ::rtl::OUString sParam(RTL_CONSTASCII_USTRINGPARAM(" = ?")); 189 190 ::rtl::OUString aColumnName; 191 ::rtl::OUStringBuffer sKeyCondition; 192 ::std::map< ::rtl::OUString,bool > aResultSetChanged; 193 TSQLStatements aKeyConditions; 194 TSQLStatements aIndexConditions; 195 TSQLStatements aSql; 196 197 // sal_Int32 i = 1; 198 // here we build the condition part for the update statement 199 SelectColumnsMetaData::const_iterator aIter = m_pColumnNames->begin(); 200 SelectColumnsMetaData::const_iterator aEnd = m_pColumnNames->end(); 201 for(;aIter != aEnd;++aIter) 202 { 203 if ( aResultSetChanged.find( aIter->second.sTableName ) == aResultSetChanged.end() ) 204 aResultSetChanged[aIter->second.sTableName] = false; 205 const ::rtl::OUString sQuotedColumnName = ::dbtools::quoteName( aQuote,aIter->second.sRealName); 206 if ( m_pKeyColumnNames->find(aIter->first) != m_pKeyColumnNames->end() ) 207 { 208 aResultSetChanged[aIter->second.sTableName] = m_aJoinedKeyColumns.find(aIter->second.nPosition) != m_aJoinedKeyColumns.end(); 209 lcl_fillKeyCondition(aIter->second.sTableName,sQuotedColumnName,(_rOrginalRow->get())[aIter->second.nPosition],aKeyConditions); 210 } 211 if((_rInsertRow->get())[aIter->second.nPosition].isModified()) 212 { 213 if ( m_aJoinedKeyColumns.find(aIter->second.nPosition) != m_aJoinedKeyColumns.end() ) 214 throw SQLException(); 215 216 ::std::map<sal_Int32,sal_Int32>::const_iterator aJoinIter = m_aJoinedColumns.find(aIter->second.nPosition); 217 if ( aJoinIter != m_aJoinedColumns.end() ) 218 { 219 (_rInsertRow->get())[aJoinIter->second] = (_rInsertRow->get())[aIter->second.nPosition]; 220 } 221 ::rtl::OUStringBuffer& rPart = aSql[aIter->second.sTableName]; 222 if ( rPart.getLength() ) 223 rPart.appendAscii(", "); 224 rPart.append(sQuotedColumnName); 225 rPart.append(s_sPara); 226 } 227 } 228 229 if( aSql.empty() ) 230 ::dbtools::throwSQLException( DBACORE_RESSTRING( RID_STR_NO_VALUE_CHANGED ), SQL_GENERAL_ERROR, m_xConnection ); 231 232 if( aKeyConditions.empty() ) 233 ::dbtools::throwSQLException( DBACORE_RESSTRING( RID_STR_NO_CONDITION_FOR_PK ), SQL_GENERAL_ERROR, m_xConnection ); 234 235 static const ::rtl::OUString s_sUPDATE(RTL_CONSTASCII_USTRINGPARAM("UPDATE ")); 236 static const ::rtl::OUString s_sSET(RTL_CONSTASCII_USTRINGPARAM(" SET ")); 237 238 Reference<XDatabaseMetaData> xMetaData = m_xConnection->getMetaData(); 239 240 TSQLStatements::iterator aSqlIter = aSql.begin(); 241 TSQLStatements::iterator aSqlEnd = aSql.end(); 242 for(;aSqlIter != aSqlEnd ; ++aSqlIter) 243 { 244 if ( aSqlIter->second.getLength() ) 245 { 246 m_bResultSetChanged = m_bResultSetChanged || aResultSetChanged[aSqlIter->first]; 247 ::rtl::OUStringBuffer sSql(s_sUPDATE); 248 ::rtl::OUString sCatalog,sSchema,sTable; 249 ::dbtools::qualifiedNameComponents(xMetaData,aSqlIter->first,sCatalog,sSchema,sTable,::dbtools::eInDataManipulation); 250 sSql.append( ::dbtools::composeTableNameForSelect( m_xConnection, sCatalog, sSchema, sTable ) ); 251 sSql.append(s_sSET); 252 sSql.append(aSqlIter->second); 253 ::rtl::OUStringBuffer& rCondition = aKeyConditions[aSqlIter->first]; 254 bool bAddWhere = true; 255 if ( rCondition.getLength() ) 256 { 257 bAddWhere = false; 258 sSql.appendAscii(" WHERE "); 259 sSql.append( rCondition ); 260 } 261 executeUpdate(_rInsertRow ,_rOrginalRow,sSql.makeStringAndClear(),aSqlIter->first); 262 } 263 } 264 } 265 // ------------------------------------------------------------------------- 266 void SAL_CALL OptimisticSet::insertRow( const ORowSetRow& _rInsertRow,const connectivity::OSQLTable& /*_xTable*/ ) throw(SQLException, RuntimeException) 267 { 268 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::insertRow" ); 269 TSQLStatements aSql; 270 TSQLStatements aParameter; 271 TSQLStatements aKeyConditions; 272 ::std::map< ::rtl::OUString,bool > aResultSetChanged; 273 ::rtl::OUString aQuote = getIdentifierQuoteString(); 274 static ::rtl::OUString aAnd = ::rtl::OUString::createFromAscii(" AND "); 275 ::rtl::OUString sIsNull(RTL_CONSTASCII_USTRINGPARAM(" IS NULL")); 276 ::rtl::OUString sParam(RTL_CONSTASCII_USTRINGPARAM(" = ?")); 277 278 // here we build the condition part for the update statement 279 SelectColumnsMetaData::const_iterator aIter = m_pColumnNames->begin(); 280 SelectColumnsMetaData::const_iterator aEnd = m_pColumnNames->end(); 281 for(;aIter != aEnd;++aIter) 282 { 283 if ( aResultSetChanged.find( aIter->second.sTableName ) == aResultSetChanged.end() ) 284 aResultSetChanged[aIter->second.sTableName] = false; 285 286 const ::rtl::OUString sQuotedColumnName = ::dbtools::quoteName( aQuote,aIter->second.sRealName); 287 if ( (_rInsertRow->get())[aIter->second.nPosition].isModified() ) 288 { 289 if ( m_aJoinedKeyColumns.find(aIter->second.nPosition) != m_aJoinedKeyColumns.end() ) 290 { 291 lcl_fillKeyCondition(aIter->second.sTableName,sQuotedColumnName,(_rInsertRow->get())[aIter->second.nPosition],aKeyConditions); 292 aResultSetChanged[aIter->second.sTableName] = true; 293 } 294 ::std::map<sal_Int32,sal_Int32>::const_iterator aJoinIter = m_aJoinedColumns.find(aIter->second.nPosition); 295 if ( aJoinIter != m_aJoinedColumns.end() ) 296 { 297 (_rInsertRow->get())[aJoinIter->second] = (_rInsertRow->get())[aIter->second.nPosition]; 298 } 299 ::rtl::OUStringBuffer& rPart = aSql[aIter->second.sTableName]; 300 if ( rPart.getLength() ) 301 rPart.appendAscii(", "); 302 rPart.append(sQuotedColumnName); 303 ::rtl::OUStringBuffer& rParam = aParameter[aIter->second.sTableName]; 304 if ( rParam.getLength() ) 305 rParam.appendAscii(", "); 306 rParam.appendAscii("?"); 307 } 308 } 309 if ( aParameter.empty() ) 310 ::dbtools::throwSQLException( DBACORE_RESSTRING( RID_STR_NO_VALUE_CHANGED ), SQL_GENERAL_ERROR, m_xConnection ); 311 312 Reference<XDatabaseMetaData> xMetaData = m_xConnection->getMetaData(); 313 static const ::rtl::OUString s_sINSERT(RTL_CONSTASCII_USTRINGPARAM("INSERT INTO ")); 314 static const ::rtl::OUString s_sVALUES(RTL_CONSTASCII_USTRINGPARAM(") VALUES ( ")); 315 TSQLStatements::iterator aSqlIter = aSql.begin(); 316 TSQLStatements::iterator aSqlEnd = aSql.end(); 317 for(;aSqlIter != aSqlEnd ; ++aSqlIter) 318 { 319 if ( aSqlIter->second.getLength() ) 320 { 321 m_bResultSetChanged = m_bResultSetChanged || aResultSetChanged[aSqlIter->first]; 322 ::rtl::OUStringBuffer sSql(s_sINSERT); 323 ::rtl::OUString sCatalog,sSchema,sTable; 324 ::dbtools::qualifiedNameComponents(xMetaData,aSqlIter->first,sCatalog,sSchema,sTable,::dbtools::eInDataManipulation); 325 ::rtl::OUString sComposedTableName = ::dbtools::composeTableNameForSelect( m_xConnection, sCatalog, sSchema, sTable ); 326 sSql.append(sComposedTableName); 327 sSql.appendAscii(" ( "); 328 sSql.append(aSqlIter->second); 329 sSql.append(s_sVALUES); 330 sSql.append(aParameter[aSqlIter->first]); 331 sSql.appendAscii(" )"); 332 333 ::rtl::OUStringBuffer& rCondition = aKeyConditions[aSqlIter->first]; 334 if ( rCondition.getLength() ) 335 { 336 ::rtl::OUStringBuffer sQuery; 337 sQuery.appendAscii("SELECT "); 338 sQuery.append(aSqlIter->second); 339 sQuery.appendAscii(" FROM "); 340 sQuery.append(sComposedTableName); 341 sQuery.appendAscii(" WHERE "); 342 sQuery.append(rCondition); 343 344 try 345 { 346 Reference< XPreparedStatement > xPrep(m_xConnection->prepareStatement(sQuery.makeStringAndClear())); 347 Reference< XParameters > xParameter(xPrep,UNO_QUERY); 348 // and then the values of the where condition 349 SelectColumnsMetaData::iterator aKeyCol = m_pKeyColumnNames->begin(); 350 SelectColumnsMetaData::iterator aKeysEnd = m_pKeyColumnNames->end(); 351 sal_Int32 i = 1; 352 for(;aKeyCol != aKeysEnd;++aKeyCol) 353 { 354 if ( aKeyCol->second.sTableName == aSqlIter->first ) 355 { 356 setParameter(i++,xParameter,(_rInsertRow->get())[aKeyCol->second.nPosition],aKeyCol->second.nType,aKeyCol->second.nScale); 357 } 358 } 359 Reference<XResultSet> xRes = xPrep->executeQuery(); 360 Reference<XRow> xRow(xRes,UNO_QUERY); 361 if ( xRow.is() && xRes->next() ) 362 { 363 m_bResultSetChanged = true; 364 continue; 365 } 366 } 367 catch(const SQLException&) 368 { 369 } 370 } 371 372 executeInsert(_rInsertRow,sSql.makeStringAndClear(),aSqlIter->first); 373 } 374 } 375 } 376 // ------------------------------------------------------------------------- 377 void SAL_CALL OptimisticSet::deleteRow(const ORowSetRow& _rDeleteRow,const connectivity::OSQLTable& /*_xTable*/ ) throw(SQLException, RuntimeException) 378 { 379 ::rtl::OUString sParam(RTL_CONSTASCII_USTRINGPARAM(" = ?")); 380 ::rtl::OUString sIsNull(RTL_CONSTASCII_USTRINGPARAM(" IS NULL")); 381 static const ::rtl::OUString s_sAnd(RTL_CONSTASCII_USTRINGPARAM(" AND ")); 382 ::rtl::OUString aQuote = getIdentifierQuoteString(); 383 ::rtl::OUString aColumnName; 384 ::rtl::OUStringBuffer sKeyCondition,sIndexCondition; 385 ::std::vector<sal_Int32> aIndexColumnPositions; 386 TSQLStatements aKeyConditions; 387 TSQLStatements aIndexConditions; 388 TSQLStatements aSql; 389 390 // sal_Int32 i = 1; 391 // here we build the condition part for the update statement 392 SelectColumnsMetaData::const_iterator aIter = m_pColumnNames->begin(); 393 SelectColumnsMetaData::const_iterator aEnd = m_pColumnNames->end(); 394 for(;aIter != aEnd;++aIter) 395 { 396 if ( m_aJoinedKeyColumns.find(aIter->second.nPosition) == m_aJoinedKeyColumns.end() && m_pKeyColumnNames->find(aIter->first) != m_pKeyColumnNames->end() ) 397 { 398 // only delete rows which aren't the key in the join 399 const ::rtl::OUString sQuotedColumnName = ::dbtools::quoteName( aQuote,aIter->second.sRealName); 400 lcl_fillKeyCondition(aIter->second.sTableName,sQuotedColumnName,(_rDeleteRow->get())[aIter->second.nPosition],aKeyConditions); 401 } 402 } 403 Reference<XDatabaseMetaData> xMetaData = m_xConnection->getMetaData(); 404 TSQLStatements::iterator aSqlIter = aKeyConditions.begin(); 405 TSQLStatements::iterator aSqlEnd = aKeyConditions.end(); 406 for(;aSqlIter != aSqlEnd ; ++aSqlIter) 407 { 408 ::rtl::OUStringBuffer& rCondition = aSqlIter->second; 409 if ( rCondition.getLength() ) 410 { 411 ::rtl::OUStringBuffer sSql; 412 sSql.appendAscii("DELETE FROM "); 413 ::rtl::OUString sCatalog,sSchema,sTable; 414 ::dbtools::qualifiedNameComponents(xMetaData,aSqlIter->first,sCatalog,sSchema,sTable,::dbtools::eInDataManipulation); 415 sSql.append( ::dbtools::composeTableNameForSelect( m_xConnection, sCatalog, sSchema, sTable ) ); 416 sSql.appendAscii(" WHERE "); 417 sSql.append( rCondition ); 418 executeDelete(_rDeleteRow,sSql.makeStringAndClear(),aSqlIter->first); 419 } 420 } 421 } 422 // ------------------------------------------------------------------------- 423 void OptimisticSet::executeDelete(const ORowSetRow& _rDeleteRow,const ::rtl::OUString& i_sSQL,const ::rtl::OUString& i_sTableName) 424 { 425 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::executeDelete" ); 426 427 // now create end execute the prepared statement 428 Reference< XPreparedStatement > xPrep(m_xConnection->prepareStatement(i_sSQL)); 429 Reference< XParameters > xParameter(xPrep,UNO_QUERY); 430 431 SelectColumnsMetaData::const_iterator aIter = m_pKeyColumnNames->begin(); 432 SelectColumnsMetaData::const_iterator aEnd = m_pKeyColumnNames->end(); 433 sal_Int32 i = 1; 434 for(;aIter != aEnd;++aIter) 435 { 436 if ( aIter->second.sTableName == i_sTableName ) 437 setParameter(i++,xParameter,(_rDeleteRow->get())[aIter->second.nPosition],aIter->second.nType,aIter->second.nScale); 438 } 439 m_bDeleted = xPrep->executeUpdate() > 0; 440 441 if(m_bDeleted) 442 { 443 sal_Int32 nBookmark = ::comphelper::getINT32((_rDeleteRow->get())[0].getAny()); 444 if(m_aKeyIter == m_aKeyMap.find(nBookmark) && m_aKeyIter != m_aKeyMap.end()) 445 ++m_aKeyIter; 446 m_aKeyMap.erase(nBookmark); 447 m_bDeleted = sal_True; 448 } 449 } 450 // ----------------------------------------------------------------------------- 451 ::rtl::OUString OptimisticSet::getComposedTableName(const ::rtl::OUString& /*_sCatalog*/, 452 const ::rtl::OUString& /*_sSchema*/, 453 const ::rtl::OUString& /*_sTable*/) 454 { 455 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::getComposedTableName" ); 456 ::rtl::OUString aComposedName; 457 /* 458 Reference<XDatabaseMetaData> xMetaData = m_xConnection->getMetaData(); 459 460 if( xMetaData.is() && xMetaData->supportsTableCorrelationNames() ) 461 { 462 aComposedName = ::dbtools::composeTableName( xMetaData, _sCatalog, _sSchema, _sTable, sal_False, ::dbtools::eInDataManipulation ); 463 // first we have to check if the composed tablename is in the select clause or if an alias is used 464 Reference<XTablesSupplier> xTabSup(m_xComposer,UNO_QUERY); 465 Reference<XNameAccess> xSelectTables = xTabSup->getTables(); 466 OSL_ENSURE(xSelectTables.is(),"No Select tables!"); 467 if(xSelectTables.is()) 468 { 469 if(!xSelectTables->hasByName(aComposedName)) 470 { // the composed name isn't used in the select clause so we have to find out which name is used instead 471 ::rtl::OUString sCatalog,sSchema,sTable; 472 ::dbtools::qualifiedNameComponents(xMetaData,m_sUpdateTableName,sCatalog,sSchema,sTable,::dbtools::eInDataManipulation); 473 aComposedName = ::dbtools::composeTableNameForSelect( m_xConnection, sCatalog, sSchema, sTable ); 474 } 475 else 476 aComposedName = ::dbtools::composeTableNameForSelect( m_xConnection, _sCatalog, _sSchema, _sTable ); 477 } 478 } 479 else 480 aComposedName = ::dbtools::composeTableNameForSelect( m_xConnection, _sCatalog, _sSchema, _sTable ); 481 */ 482 return aComposedName; 483 } 484 // ----------------------------------------------------------------------------- 485 void OptimisticSet::fillJoinedColumns_throw(const ::std::vector< TNodePair >& i_aJoinColumns) 486 { 487 ::std::vector< TNodePair >::const_iterator aIter = i_aJoinColumns.begin(); 488 for(;aIter != i_aJoinColumns.end();++aIter) 489 { 490 ::rtl::OUString sColumnName,sTableName; 491 m_aSqlIterator.getColumnRange(aIter->first,sColumnName,sTableName); 492 ::rtl::OUStringBuffer sLeft,sRight; 493 sLeft.append(sTableName); 494 sLeft.appendAscii("."); 495 sLeft.append(sColumnName); 496 m_aSqlIterator.getColumnRange(aIter->second,sColumnName,sTableName); 497 sRight.append(sTableName); 498 sRight.appendAscii("."); 499 sRight.append(sColumnName); 500 fillJoinedColumns_throw(sLeft.makeStringAndClear(),sRight.makeStringAndClear()); 501 } 502 } 503 // ----------------------------------------------------------------------------- 504 void OptimisticSet::fillJoinedColumns_throw(const ::rtl::OUString& i_sLeftColumn,const ::rtl::OUString& i_sRightColumn) 505 { 506 sal_Int32 nLeft = 0,nRight = 0; 507 SelectColumnsMetaData::const_iterator aLeftIter = m_pKeyColumnNames->find(i_sLeftColumn); 508 SelectColumnsMetaData::const_iterator aRightIter = m_pKeyColumnNames->find(i_sRightColumn); 509 510 bool bLeftKey = aLeftIter != m_pKeyColumnNames->end(); 511 if ( bLeftKey ) 512 { 513 nLeft = aLeftIter->second.nPosition; 514 } 515 else 516 { 517 aLeftIter = m_pColumnNames->find(i_sLeftColumn); 518 if ( aLeftIter != m_pColumnNames->end() ) 519 nLeft = aLeftIter->second.nPosition; 520 } 521 522 bool bRightKey = aRightIter != m_pKeyColumnNames->end(); 523 if ( bRightKey ) 524 { 525 nRight = aRightIter->second.nPosition; 526 } 527 else 528 { 529 aRightIter = m_pColumnNames->find(i_sRightColumn); 530 if ( aRightIter != m_pColumnNames->end() ) 531 nRight = aRightIter->second.nPosition; 532 } 533 534 if (bLeftKey) 535 m_aJoinedKeyColumns[nLeft] = nRight; 536 else 537 m_aJoinedColumns[nLeft] = nRight; 538 if (bRightKey) 539 m_aJoinedKeyColumns[nRight] = nLeft; 540 else 541 m_aJoinedColumns[nRight] = nLeft; 542 } 543 // ----------------------------------------------------------------------------- 544 bool OptimisticSet::isResultSetChanged() const 545 { 546 bool bOld = m_bResultSetChanged; 547 m_bResultSetChanged = false; 548 return bOld; 549 } 550 // ----------------------------------------------------------------------------- 551 void OptimisticSet::reset(const Reference< XResultSet>& _xDriverSet) 552 { 553 OCacheSet::construct(_xDriverSet,::rtl::OUString()); 554 m_bRowCountFinal = sal_False; 555 m_aKeyMap.clear(); 556 m_aKeyMap.insert(OKeySetMatrix::value_type(0,OKeySetValue(NULL,::std::pair<sal_Int32,Reference<XRow> >(0,NULL)))); 557 m_aKeyIter = m_aKeyMap.begin(); 558 } 559 // ----------------------------------------------------------------------------- 560 void OptimisticSet::mergeColumnValues(sal_Int32 i_nColumnIndex,ORowSetValueVector::Vector& io_aInsertRow,ORowSetValueVector::Vector& io_aRow,::std::vector<sal_Int32>& o_aChangedColumns) 561 { 562 o_aChangedColumns.push_back(i_nColumnIndex); 563 ::std::map<sal_Int32,sal_Int32>::const_iterator aJoinIter = m_aJoinedColumns.find(i_nColumnIndex); 564 if ( aJoinIter != m_aJoinedColumns.end() ) 565 { 566 io_aRow[aJoinIter->second] = io_aRow[i_nColumnIndex]; 567 io_aInsertRow[aJoinIter->second] = io_aInsertRow[i_nColumnIndex]; 568 io_aRow[aJoinIter->second].setModified(); 569 o_aChangedColumns.push_back(aJoinIter->second); 570 } 571 } 572 namespace 573 { 574 struct PositionFunctor : ::std::unary_function<SelectColumnsMetaData::value_type,bool> 575 { 576 sal_Int32 m_nPos; 577 PositionFunctor(sal_Int32 i_nPos) 578 : m_nPos(i_nPos) 579 { 580 } 581 582 inline bool operator()(const SelectColumnsMetaData::value_type& _aType) 583 { 584 return m_nPos == _aType.second.nPosition; 585 } 586 }; 587 struct TableNameFunctor : ::std::unary_function<SelectColumnsMetaData::value_type,bool> 588 { 589 ::rtl::OUString m_sTableName; 590 TableNameFunctor(const ::rtl::OUString& i_sTableName) 591 : m_sTableName(i_sTableName) 592 { 593 } 594 595 inline bool operator()(const SelectColumnsMetaData::value_type& _aType) 596 { 597 return m_sTableName == _aType.second.sTableName; 598 } 599 }; 600 } 601 // ----------------------------------------------------------------------------- 602 bool OptimisticSet::updateColumnValues(const ORowSetValueVector::Vector& io_aCachedRow,ORowSetValueVector::Vector& io_aRow,const ::std::vector<sal_Int32>& i_aChangedColumns) 603 { 604 bool bRet = false; 605 ::std::vector<sal_Int32>::const_iterator aColIdxIter = i_aChangedColumns.begin(); 606 for(;aColIdxIter != i_aChangedColumns.end();++aColIdxIter) 607 { 608 SelectColumnsMetaData::const_iterator aFind = ::std::find_if(m_pKeyColumnNames->begin(),m_pKeyColumnNames->end(),PositionFunctor(*aColIdxIter)); 609 if ( aFind != m_pKeyColumnNames->end() ) 610 { 611 const ::rtl::OUString sTableName = aFind->second.sTableName; 612 aFind = ::std::find_if(m_pKeyColumnNames->begin(),m_pKeyColumnNames->end(),TableNameFunctor(sTableName)); 613 while( aFind != m_pKeyColumnNames->end() ) 614 { 615 io_aRow[aFind->second.nPosition].setSigned(io_aCachedRow[aFind->second.nPosition].isSigned()); 616 if ( io_aCachedRow[aFind->second.nPosition] != io_aRow[aFind->second.nPosition] ) 617 break; 618 ++aFind; 619 } 620 if ( aFind == m_pKeyColumnNames->end() ) 621 { 622 bRet = true; 623 SelectColumnsMetaData::const_iterator aIter = m_pColumnNames->begin(); 624 SelectColumnsMetaData::const_iterator aEnd = m_pColumnNames->end(); 625 for ( ;aIter != aEnd;++aIter ) 626 { 627 if ( aIter->second.sTableName == sTableName ) 628 { 629 io_aRow[aIter->second.nPosition] = io_aCachedRow[aIter->second.nPosition]; 630 io_aRow[aIter->second.nPosition].setModified(); 631 } 632 } 633 } 634 } 635 } 636 return bRet; 637 } 638 // ----------------------------------------------------------------------------- 639 bool OptimisticSet::columnValuesUpdated(ORowSetValueVector::Vector& o_aCachedRow,const ORowSetValueVector::Vector& i_aRow) 640 { 641 bool bRet = false; 642 SelectColumnsMetaData::const_iterator aIter = m_pColumnNames->begin(); 643 SelectColumnsMetaData::const_iterator aEnd = m_pColumnNames->end(); 644 for(;aIter != aEnd;++aIter) 645 { 646 SelectColumnsMetaData::const_iterator aFind = ::std::find_if(m_pKeyColumnNames->begin(),m_pKeyColumnNames->end(),PositionFunctor(aIter->second.nPosition)); 647 if ( aFind != m_pKeyColumnNames->end() ) 648 { 649 const ::rtl::OUString sTableName = aFind->second.sTableName; 650 aFind = ::std::find_if(m_pKeyColumnNames->begin(),m_pKeyColumnNames->end(),TableNameFunctor(sTableName)); 651 while( aFind != m_pKeyColumnNames->end() ) 652 { 653 o_aCachedRow[aFind->second.nPosition].setSigned(i_aRow[aFind->second.nPosition].isSigned()); 654 if ( o_aCachedRow[aFind->second.nPosition] != i_aRow[aFind->second.nPosition] ) 655 break; 656 ++aFind; 657 } 658 if ( aFind == m_pKeyColumnNames->end() ) 659 { 660 bRet = true; 661 SelectColumnsMetaData::const_iterator aIter2 = m_pColumnNames->begin(); 662 SelectColumnsMetaData::const_iterator aEnd2 = m_pColumnNames->end(); 663 for ( ;aIter2 != aEnd2;++aIter2 ) 664 { 665 if ( aIter2->second.sTableName == sTableName ) 666 { 667 o_aCachedRow[aIter2->second.nPosition] = i_aRow[aIter2->second.nPosition]; 668 o_aCachedRow[aIter2->second.nPosition].setModified(); 669 } 670 } 671 fillMissingValues(o_aCachedRow); 672 } 673 } 674 } 675 return bRet; 676 } 677 // ----------------------------------------------------------------------------- 678 void OptimisticSet::fillMissingValues(ORowSetValueVector::Vector& io_aRow) const 679 { 680 TSQLStatements aSql; 681 TSQLStatements aKeyConditions; 682 ::std::map< ::rtl::OUString,bool > aResultSetChanged; 683 ::rtl::OUString aQuote = getIdentifierQuoteString(); 684 static ::rtl::OUString aAnd = ::rtl::OUString::createFromAscii(" AND "); 685 ::rtl::OUString sIsNull(RTL_CONSTASCII_USTRINGPARAM(" IS NULL")); 686 ::rtl::OUString sParam(RTL_CONSTASCII_USTRINGPARAM(" = ?")); 687 // here we build the condition part for the update statement 688 SelectColumnsMetaData::const_iterator aColIter = m_pColumnNames->begin(); 689 SelectColumnsMetaData::const_iterator aColEnd = m_pColumnNames->end(); 690 for(;aColIter != aColEnd;++aColIter) 691 { 692 const ::rtl::OUString sQuotedColumnName = ::dbtools::quoteName( aQuote,aColIter->second.sRealName); 693 if ( m_aJoinedKeyColumns.find(aColIter->second.nPosition) != m_aJoinedKeyColumns.end() ) 694 { 695 lcl_fillKeyCondition(aColIter->second.sTableName,sQuotedColumnName,io_aRow[aColIter->second.nPosition],aKeyConditions); 696 } 697 ::rtl::OUStringBuffer& rPart = aSql[aColIter->second.sTableName]; 698 if ( rPart.getLength() ) 699 rPart.appendAscii(", "); 700 rPart.append(sQuotedColumnName); 701 } 702 Reference<XDatabaseMetaData> xMetaData = m_xConnection->getMetaData(); 703 TSQLStatements::iterator aSqlIter = aSql.begin(); 704 TSQLStatements::iterator aSqlEnd = aSql.end(); 705 for(;aSqlIter != aSqlEnd ; ++aSqlIter) 706 { 707 if ( aSqlIter->second.getLength() ) 708 { 709 ::rtl::OUStringBuffer& rCondition = aKeyConditions[aSqlIter->first]; 710 if ( rCondition.getLength() ) 711 { 712 ::rtl::OUString sCatalog,sSchema,sTable; 713 ::dbtools::qualifiedNameComponents(xMetaData,aSqlIter->first,sCatalog,sSchema,sTable,::dbtools::eInDataManipulation); 714 ::rtl::OUString sComposedTableName = ::dbtools::composeTableNameForSelect( m_xConnection, sCatalog, sSchema, sTable ); 715 ::rtl::OUStringBuffer sQuery; 716 sQuery.appendAscii("SELECT "); 717 sQuery.append(aSqlIter->second); 718 sQuery.appendAscii(" FROM "); 719 sQuery.append(sComposedTableName); 720 sQuery.appendAscii(" WHERE "); 721 sQuery.append(rCondition.makeStringAndClear()); 722 723 try 724 { 725 Reference< XPreparedStatement > xPrep(m_xConnection->prepareStatement(sQuery.makeStringAndClear())); 726 Reference< XParameters > xParameter(xPrep,UNO_QUERY); 727 // and then the values of the where condition 728 SelectColumnsMetaData::iterator aKeyIter = m_pKeyColumnNames->begin(); 729 SelectColumnsMetaData::iterator aKeyEnd = m_pKeyColumnNames->end(); 730 sal_Int32 i = 1; 731 for(;aKeyIter != aKeyEnd;++aKeyIter) 732 { 733 if ( aKeyIter->second.sTableName == aSqlIter->first ) 734 { 735 setParameter(i++,xParameter,io_aRow[aKeyIter->second.nPosition],aKeyIter->second.nType,aKeyIter->second.nScale); 736 } 737 } 738 Reference<XResultSet> xRes = xPrep->executeQuery(); 739 Reference<XRow> xRow(xRes,UNO_QUERY); 740 if ( xRow.is() && xRes->next() ) 741 { 742 i = 1; 743 aColIter = m_pColumnNames->begin(); 744 for(;aColIter != aColEnd;++aColIter) 745 { 746 if ( aColIter->second.sTableName == aSqlIter->first ) 747 { 748 io_aRow[aColIter->second.nPosition].fill(i++,aColIter->second.nType,aColIter->second.bNullable,xRow); 749 io_aRow[aColIter->second.nPosition].setModified(); 750 } 751 } 752 } 753 } 754 catch(const SQLException&) 755 { 756 } 757 } 758 } 759 } 760 } 761 // ----------------------------------------------------------------------------- 762 763