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 <indexcollection.hxx> 21 #include <tools/diagnose_ex.h> 22 #include <com/sun/star/sdbcx/XAppend.hpp> 23 #include <com/sun/star/beans/XPropertySet.hpp> 24 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp> 25 #include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp> 26 #include <comphelper/extract.hxx> 27 #include <com/sun/star/sdbcx/XDrop.hpp> 28 #include <com/sun/star/container/XNameContainer.hpp> 29 30 namespace dbaui 31 { 32 33 using namespace ::com::sun::star::uno; 34 using namespace ::com::sun::star::container; 35 using namespace ::com::sun::star::beans; 36 using namespace ::com::sun::star::sdbcx; 37 using namespace ::com::sun::star::sdbc; 38 39 // OIndexCollection OIndexCollection()40 OIndexCollection::OIndexCollection() 41 { 42 } 43 OIndexCollection(const OIndexCollection & _rSource)44 OIndexCollection::OIndexCollection(const OIndexCollection& _rSource) 45 { 46 *this = _rSource; 47 } 48 operator =(const OIndexCollection & _rSource)49 OIndexCollection& OIndexCollection::operator=(const OIndexCollection& _rSource) 50 { 51 detach(); 52 m_xIndexes = _rSource.m_xIndexes; 53 m_aIndexes = _rSource.m_aIndexes; 54 return *this; 55 } 56 attach(const Reference<XNameAccess> & _rxIndexes)57 void OIndexCollection::attach(const Reference< XNameAccess >& _rxIndexes) 58 { 59 implConstructFrom(_rxIndexes); 60 } 61 detach()62 void OIndexCollection::detach() 63 { 64 m_xIndexes.clear(); 65 m_aIndexes.clear(); 66 } 67 find(const OUString & _rName) const68 Indexes::const_iterator OIndexCollection::find(const OUString& _rName) const 69 { 70 // loop'n'compare 71 return std::find_if(m_aIndexes.cbegin(), m_aIndexes.cend(), 72 [&_rName](const OIndex& rIndex) { return rIndex.sName == _rName; }); 73 } 74 find(const OUString & _rName)75 Indexes::iterator OIndexCollection::find(const OUString& _rName) 76 { 77 // loop'n'compare 78 return std::find_if(m_aIndexes.begin(), m_aIndexes.end(), 79 [&_rName](const OIndex& rIndex) { return rIndex.sName == _rName; }); 80 } 81 findOriginal(const OUString & _rName) const82 Indexes::const_iterator OIndexCollection::findOriginal(const OUString& _rName) const 83 { 84 // loop'n'compare 85 return std::find_if(m_aIndexes.cbegin(), m_aIndexes.cend(), 86 [&_rName](const OIndex& rIndex) { return rIndex.getOriginalName() == _rName; }); 87 } 88 findOriginal(const OUString & _rName)89 Indexes::iterator OIndexCollection::findOriginal(const OUString& _rName) 90 { 91 // loop'n'compare 92 return std::find_if(m_aIndexes.begin(), m_aIndexes.end(), 93 [&_rName](const OIndex& rIndex) { return rIndex.getOriginalName() == _rName; }); 94 } 95 commitNewIndex(const Indexes::iterator & _rPos)96 void OIndexCollection::commitNewIndex(const Indexes::iterator& _rPos) 97 { 98 OSL_ENSURE(_rPos->isNew(), "OIndexCollection::commitNewIndex: index must be new!"); 99 100 try 101 { 102 Reference< XDataDescriptorFactory > xIndexFactory(m_xIndexes, UNO_QUERY); 103 Reference< XAppend > xAppendIndex(xIndexFactory, UNO_QUERY); 104 if (!xAppendIndex.is()) 105 { 106 OSL_FAIL("OIndexCollection::commitNewIndex: missing an interface of the index container!"); 107 return; 108 } 109 110 Reference< XPropertySet > xIndexDescriptor = xIndexFactory->createDataDescriptor(); 111 Reference< XColumnsSupplier > xColsSupp(xIndexDescriptor, UNO_QUERY); 112 Reference< XNameAccess > xCols; 113 if (xColsSupp.is()) 114 xCols = xColsSupp->getColumns(); 115 116 Reference< XDataDescriptorFactory > xColumnFactory(xCols, UNO_QUERY); 117 Reference< XAppend > xAppendCols(xColumnFactory, UNO_QUERY); 118 if (!xAppendCols.is()) 119 { 120 OSL_FAIL("OIndexCollection::commitNewIndex: invalid index descriptor returned!"); 121 return; 122 } 123 124 // set the properties 125 static const char s_sNamePropertyName[] = "Name"; 126 // the index' own props 127 xIndexDescriptor->setPropertyValue("IsUnique", css::uno::makeAny(_rPos->bUnique)); 128 xIndexDescriptor->setPropertyValue(s_sNamePropertyName, makeAny(_rPos->sName)); 129 130 // the fields 131 for (auto const& field : _rPos->aFields) 132 { 133 OSL_ENSURE(!xCols->hasByName(field.sFieldName), "OIndexCollection::commitNewIndex: double column name (need to prevent this outside)!"); 134 135 Reference< XPropertySet > xColDescriptor = xColumnFactory->createDataDescriptor(); 136 OSL_ENSURE(xColDescriptor.is(), "OIndexCollection::commitNewIndex: invalid column descriptor!"); 137 if (xColDescriptor.is()) 138 { 139 xColDescriptor->setPropertyValue("IsAscending", css::uno::makeAny(field.bSortAscending)); 140 xColDescriptor->setPropertyValue(s_sNamePropertyName, makeAny(field.sFieldName)); 141 xAppendCols->appendByDescriptor(xColDescriptor); 142 } 143 } 144 145 xAppendIndex->appendByDescriptor(xIndexDescriptor); 146 147 _rPos->flagAsCommitted(GrantIndexAccess()); 148 _rPos->clearModified(); 149 } 150 catch(SQLException&) 151 { // allowed to pass 152 throw; 153 } 154 catch( const Exception& ) 155 { 156 DBG_UNHANDLED_EXCEPTION("dbaccess"); 157 } 158 } 159 dropNoRemove(const Indexes::iterator & _rPos)160 bool OIndexCollection::dropNoRemove(const Indexes::iterator& _rPos) 161 { 162 try 163 { 164 OSL_ENSURE(m_xIndexes->hasByName(_rPos->getOriginalName()), "OIndexCollection::drop: invalid name!"); 165 166 Reference< XDrop > xDropIndex(m_xIndexes, UNO_QUERY); 167 if (!xDropIndex.is()) 168 { 169 OSL_FAIL("OIndexCollection::drop: no XDrop interface!"); 170 return false; 171 } 172 173 xDropIndex->dropByName(_rPos->getOriginalName()); 174 } 175 catch(SQLException&) 176 { // allowed to pass 177 throw; 178 } 179 catch( const Exception& ) 180 { 181 DBG_UNHANDLED_EXCEPTION("dbaccess"); 182 return false; 183 } 184 185 // adjust the OIndex structure 186 Indexes::iterator aDropped = findOriginal(_rPos->getOriginalName()); 187 OSL_ENSURE(aDropped != m_aIndexes.end(), "OIndexCollection::drop: invalid original name, but successful commit?!"); 188 aDropped->flagAsNew(GrantIndexAccess()); 189 190 return true; 191 } 192 drop(const Indexes::iterator & _rPos)193 bool OIndexCollection::drop(const Indexes::iterator& _rPos) 194 { 195 OSL_ENSURE((_rPos >= m_aIndexes.begin()) && (_rPos < m_aIndexes.end()), 196 "OIndexCollection::drop: invalid position (fasten your seatbelt... this will crash)!"); 197 198 if (!_rPos->isNew()) 199 if (!dropNoRemove(_rPos)) 200 return false; 201 202 // adjust the index array 203 m_aIndexes.erase(_rPos); 204 return true; 205 } 206 implFillIndexInfo(OIndex & _rIndex)207 void OIndexCollection::implFillIndexInfo(OIndex& _rIndex) 208 { 209 // get the UNO descriptor for the index 210 Reference< XPropertySet > xIndex; 211 m_xIndexes->getByName(_rIndex.getOriginalName()) >>= xIndex; 212 if (!xIndex.is()) 213 { 214 OSL_FAIL("OIndexCollection::implFillIndexInfo: got an invalid index object!"); 215 } 216 else 217 implFillIndexInfo(_rIndex, xIndex); 218 } 219 implFillIndexInfo(OIndex & _rIndex,const Reference<XPropertySet> & _rxDescriptor)220 void OIndexCollection::implFillIndexInfo(OIndex& _rIndex, const Reference< XPropertySet >& _rxDescriptor) 221 { 222 _rIndex.bPrimaryKey = ::cppu::any2bool(_rxDescriptor->getPropertyValue("IsPrimaryKeyIndex")); 223 _rIndex.bUnique = ::cppu::any2bool(_rxDescriptor->getPropertyValue("IsUnique")); 224 _rxDescriptor->getPropertyValue("Catalog") >>= _rIndex.sDescription; 225 226 // the columns 227 Reference< XColumnsSupplier > xSuppCols(_rxDescriptor, UNO_QUERY); 228 Reference< XNameAccess > xCols; 229 if (xSuppCols.is()) 230 xCols = xSuppCols->getColumns(); 231 OSL_ENSURE(xCols.is(), "OIndexCollection::implFillIndexInfo: the index does not have columns!"); 232 if (xCols.is()) 233 { 234 Sequence< OUString > aFieldNames = xCols->getElementNames(); 235 _rIndex.aFields.resize(aFieldNames.getLength()); 236 237 const OUString* pFieldNames = aFieldNames.getConstArray(); 238 const OUString* pFieldNamesEnd = pFieldNames + aFieldNames.getLength(); 239 IndexFields::iterator aCopyTo = _rIndex.aFields.begin(); 240 241 Reference< XPropertySet > xIndexColumn; 242 for (;pFieldNames < pFieldNamesEnd; ++pFieldNames, ++aCopyTo) 243 { 244 // extract the column 245 xIndexColumn.clear(); 246 xCols->getByName(*pFieldNames) >>= xIndexColumn; 247 if (!xIndexColumn.is()) 248 { 249 OSL_FAIL("OIndexCollection::implFillIndexInfo: invalid index column!"); 250 --aCopyTo; 251 continue; 252 } 253 254 // get the relevant properties 255 aCopyTo->sFieldName = *pFieldNames; 256 aCopyTo->bSortAscending = ::cppu::any2bool(xIndexColumn->getPropertyValue("IsAscending")); 257 } 258 259 _rIndex.aFields.resize(aCopyTo - _rIndex.aFields.begin()); 260 // (just in case some fields were invalid ...) 261 } 262 } 263 resetIndex(const Indexes::iterator & _rPos)264 void OIndexCollection::resetIndex(const Indexes::iterator& _rPos) 265 { 266 OSL_ENSURE(_rPos >= m_aIndexes.begin() && _rPos < m_aIndexes.end(), 267 "OIndexCollection::resetIndex: invalid position!"); 268 269 try 270 { 271 _rPos->sName = _rPos->getOriginalName(); 272 implFillIndexInfo(*_rPos); 273 274 _rPos->clearModified(); 275 _rPos->flagAsCommitted(GrantIndexAccess()); 276 } 277 catch(SQLException&) 278 { // allowed to pass 279 throw; 280 } 281 catch( const Exception& ) 282 { 283 DBG_UNHANDLED_EXCEPTION("dbaccess"); 284 } 285 } 286 insert(const OUString & _rName)287 Indexes::iterator OIndexCollection::insert(const OUString& _rName) 288 { 289 OSL_ENSURE(end() == find(_rName), "OIndexCollection::insert: invalid new name!"); 290 OIndex aNewIndex((OUString())); // the empty string indicates the index is a new one 291 aNewIndex.sName = _rName; 292 m_aIndexes.push_back(aNewIndex); 293 return m_aIndexes.end() - 1; // the last element is the new one ... 294 } 295 implConstructFrom(const Reference<XNameAccess> & _rxIndexes)296 void OIndexCollection::implConstructFrom(const Reference< XNameAccess >& _rxIndexes) 297 { 298 detach(); 299 300 m_xIndexes = _rxIndexes; 301 if (m_xIndexes.is()) 302 { 303 // loop through all the indexes 304 Sequence< OUString > aNames = m_xIndexes->getElementNames(); 305 const OUString* pNames = aNames.getConstArray(); 306 const OUString* pEnd = pNames + aNames.getLength(); 307 for (; pNames < pEnd; ++pNames) 308 { 309 // extract the index object 310 Reference< XPropertySet > xIndex; 311 m_xIndexes->getByName(*pNames) >>= xIndex; 312 if (!xIndex.is()) 313 { 314 OSL_FAIL("OIndexCollection::implConstructFrom: got an invalid index object ... ignoring!"); 315 continue; 316 } 317 318 // fill the OIndex structure 319 OIndex aCurrentIndex(*pNames); 320 implFillIndexInfo(aCurrentIndex); 321 m_aIndexes.push_back(aCurrentIndex); 322 } 323 } 324 } 325 326 } // namespace dbaui 327 328 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 329