1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_connectivity.hxx" 30 #include "connectivity/TKeys.hxx" 31 #include "connectivity/TKey.hxx" 32 #include <com/sun/star/sdbc/XRow.hpp> 33 #include <com/sun/star/sdbc/XResultSet.hpp> 34 #include <com/sun/star/sdbcx/KeyType.hpp> 35 #include <com/sun/star/sdbc/KeyRule.hpp> 36 #include "connectivity/dbtools.hxx" 37 #include <comphelper/extract.hxx> 38 #include <comphelper/types.hxx> 39 #include <comphelper/property.hxx> 40 #include "TConnection.hxx" 41 42 namespace connectivity 43 { 44 using namespace comphelper; 45 using namespace connectivity::sdbcx; 46 using namespace dbtools; 47 using namespace ::com::sun::star::uno; 48 using namespace ::com::sun::star::beans; 49 using namespace ::com::sun::star::sdbcx; 50 using namespace ::com::sun::star::sdbc; 51 using namespace ::com::sun::star::container; 52 using namespace ::com::sun::star::lang; 53 54 55 56 OKeysHelper::OKeysHelper( OTableHelper* _pTable, 57 ::osl::Mutex& _rMutex, 58 const TStringVector& _rVector 59 ) : OKeys_BASE(*_pTable,sal_True,_rMutex,_rVector,sal_True) 60 ,m_pTable(_pTable) 61 { 62 } 63 // ------------------------------------------------------------------------- 64 sdbcx::ObjectType OKeysHelper::createObject(const ::rtl::OUString& _rName) 65 { 66 sdbcx::ObjectType xRet = NULL; 67 68 if(_rName.getLength()) 69 { 70 OTableKeyHelper* pRet = new OTableKeyHelper(m_pTable,_rName,m_pTable->getKeyProperties(_rName)); 71 xRet = pRet; 72 } 73 74 if(!xRet.is()) // we have a primary key with a system name 75 { 76 OTableKeyHelper* pRet = new OTableKeyHelper(m_pTable,_rName,m_pTable->getKeyProperties(_rName)); 77 xRet = pRet; 78 } 79 80 return xRet; 81 } 82 // ------------------------------------------------------------------------- 83 void OKeysHelper::impl_refresh() throw(RuntimeException) 84 { 85 m_pTable->refreshKeys(); 86 } 87 // ------------------------------------------------------------------------- 88 Reference< XPropertySet > OKeysHelper::createDescriptor() 89 { 90 return new OTableKeyHelper(m_pTable); 91 } 92 // ----------------------------------------------------------------------------- 93 /** returns the keyrule string for the primary key 94 */ 95 ::rtl::OUString getKeyRuleString(sal_Bool _bUpdate,sal_Int32 _nKeyRule) 96 { 97 const char* pKeyRule = NULL; 98 switch ( _nKeyRule ) 99 { 100 case KeyRule::CASCADE: 101 pKeyRule = _bUpdate ? " ON UPDATE CASCADE " : " ON DELETE CASCADE "; 102 break; 103 case KeyRule::RESTRICT: 104 pKeyRule = _bUpdate ? " ON UPDATE RESTRICT " : " ON DELETE RESTRICT "; 105 break; 106 case KeyRule::SET_NULL: 107 pKeyRule = _bUpdate ? " ON UPDATE SET NULL " : " ON DELETE SET NULL "; 108 break; 109 case KeyRule::SET_DEFAULT: 110 pKeyRule = _bUpdate ? " ON UPDATE SET DEFAULT " : " ON DELETE SET DEFAULT "; 111 break; 112 default: 113 ; 114 } 115 ::rtl::OUString sRet; 116 if ( pKeyRule ) 117 sRet = ::rtl::OUString::createFromAscii(pKeyRule); 118 return sRet; 119 } 120 // ------------------------------------------------------------------------- 121 void OKeysHelper::cloneDescriptorColumns( const sdbcx::ObjectType& _rSourceDescriptor, const sdbcx::ObjectType& _rDestDescriptor ) 122 { 123 Reference< XColumnsSupplier > xColSupp( _rSourceDescriptor, UNO_QUERY_THROW ); 124 Reference< XIndexAccess > xSourceCols( xColSupp->getColumns(), UNO_QUERY_THROW ); 125 126 xColSupp.set( _rDestDescriptor, UNO_QUERY_THROW ); 127 Reference< XAppend > xDestAppend( xColSupp->getColumns(), UNO_QUERY_THROW ); 128 129 sal_Int32 nCount = xSourceCols->getCount(); 130 for ( sal_Int32 i=0; i< nCount; ++i ) 131 { 132 Reference< XPropertySet > xColProp( xSourceCols->getByIndex(i), UNO_QUERY ); 133 xDestAppend->appendByDescriptor( xColProp ); 134 } 135 } 136 // ------------------------------------------------------------------------- 137 // XAppend 138 sdbcx::ObjectType OKeysHelper::appendObject( const ::rtl::OUString& _rForName, const Reference< XPropertySet >& descriptor ) 139 { 140 Reference< XConnection> xConnection = m_pTable->getConnection(); 141 if ( !xConnection.is() ) 142 return NULL; 143 if ( m_pTable->isNew() ) 144 { 145 Reference< XPropertySet > xNewDescriptor( cloneDescriptor( descriptor ) ); 146 cloneDescriptorColumns( descriptor, xNewDescriptor ); 147 return xNewDescriptor; 148 } 149 150 const ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap(); 151 sal_Int32 nKeyType = getINT32(descriptor->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_TYPE))); 152 sal_Int32 nUpdateRule = 0, nDeleteRule = 0; 153 ::rtl::OUString sReferencedName; 154 155 if ( nKeyType == KeyType::FOREIGN ) 156 { 157 descriptor->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_REFERENCEDTABLE)) >>= sReferencedName; 158 descriptor->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_UPDATERULE)) >>= nUpdateRule; 159 descriptor->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_DELETERULE)) >>= nDeleteRule; 160 } 161 162 if ( m_pTable->getKeyService().is() ) 163 { 164 m_pTable->getKeyService()->addKey(m_pTable,descriptor); 165 } 166 else 167 { 168 // if we're here, we belong to a table which is not new, i.e. already exists in the database. 169 // In this case, really append the new index. 170 ::rtl::OUStringBuffer aSql; 171 aSql.appendAscii("ALTER TABLE "); 172 ::rtl::OUString aQuote = m_pTable->getConnection()->getMetaData()->getIdentifierQuoteString( ); 173 ::rtl::OUString aDot = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(".")); 174 175 aSql.append(composeTableName( m_pTable->getConnection()->getMetaData(), m_pTable, ::dbtools::eInTableDefinitions, false, false, true )); 176 aSql.appendAscii(" ADD "); 177 178 if ( nKeyType == KeyType::PRIMARY ) 179 { 180 aSql.appendAscii(" PRIMARY KEY ("); 181 } 182 else if ( nKeyType == KeyType::FOREIGN ) 183 { 184 aSql.appendAscii(" FOREIGN KEY ("); 185 } 186 else 187 throw SQLException(); 188 189 Reference<XColumnsSupplier> xColumnSup(descriptor,UNO_QUERY); 190 Reference<XIndexAccess> xColumns(xColumnSup->getColumns(),UNO_QUERY); 191 Reference< XPropertySet > xColProp; 192 for(sal_Int32 i = 0 ; i < xColumns->getCount() ; ++i) 193 { 194 if ( i > 0 ) 195 aSql.appendAscii(","); 196 ::cppu::extractInterface(xColProp,xColumns->getByIndex(i)); 197 aSql.append( ::dbtools::quoteName( aQuote,getString(xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME)))) ); 198 199 } 200 aSql.appendAscii(")"); 201 202 if ( nKeyType == KeyType::FOREIGN ) 203 { 204 aSql.appendAscii(" REFERENCES "); 205 aSql.append(::dbtools::quoteTableName(m_pTable->getConnection()->getMetaData(),sReferencedName,::dbtools::eInTableDefinitions)); 206 aSql.appendAscii(" ("); 207 208 for(sal_Int32 i=0;i<xColumns->getCount();++i) 209 { 210 if ( i > 0 ) 211 aSql.appendAscii(","); 212 xColumns->getByIndex(i) >>= xColProp; 213 aSql.append(::dbtools::quoteName( aQuote,getString(xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_RELATEDCOLUMN))))); 214 215 } 216 aSql.appendAscii(")"); 217 aSql.append(getKeyRuleString(sal_True ,nUpdateRule)); 218 aSql.append(getKeyRuleString(sal_False ,nDeleteRule)); 219 } 220 221 Reference< XStatement > xStmt = m_pTable->getConnection()->createStatement( ); 222 xStmt->execute(aSql.makeStringAndClear()); 223 } 224 // find the name which the database gave the new key 225 ::rtl::OUString sNewName( _rForName ); 226 try 227 { 228 ::rtl::OUString aSchema,aTable; 229 m_pTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_SCHEMANAME)) >>= aSchema; 230 m_pTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME)) >>= aTable; 231 Reference< XResultSet > xResult; 232 sal_Int32 nColumn = 12; 233 if ( nKeyType == KeyType::FOREIGN ) 234 xResult = m_pTable->getMetaData()->getImportedKeys( m_pTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_CATALOGNAME)) 235 ,aSchema 236 ,aTable); 237 else 238 { 239 xResult = m_pTable->getMetaData()->getPrimaryKeys( m_pTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_CATALOGNAME)) 240 ,aSchema 241 ,aTable); 242 nColumn = 6; 243 } 244 if ( xResult.is() ) 245 { 246 Reference< XRow > xRow(xResult,UNO_QUERY); 247 while( xResult->next() ) 248 { 249 ::rtl::OUString sName = xRow->getString(nColumn); 250 if ( !m_pElements->exists(sName) ) // this name wasn't inserted yet so it must be te new one 251 { 252 descriptor->setPropertyValue( rPropMap.getNameByIndex( PROPERTY_ID_NAME ), makeAny( sName ) ); 253 sNewName = sName; 254 break; 255 } 256 } 257 ::comphelper::disposeComponent(xResult); 258 } 259 } 260 catch(const SQLException&) 261 { 262 } 263 264 m_pTable->addKey(sNewName,sdbcx::TKeyProperties(new sdbcx::KeyProperties(sReferencedName,nKeyType,nUpdateRule,nDeleteRule))); 265 266 return createObject( sNewName ); 267 } 268 // ----------------------------------------------------------------------------- 269 ::rtl::OUString OKeysHelper::getDropForeignKey() const 270 { 271 return ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" DROP CONSTRAINT ")); 272 } 273 // ------------------------------------------------------------------------- 274 // XDrop 275 void OKeysHelper::dropObject(sal_Int32 _nPos,const ::rtl::OUString _sElementName) 276 { 277 Reference< XConnection> xConnection = m_pTable->getConnection(); 278 if ( xConnection.is() && !m_pTable->isNew() ) 279 { 280 Reference<XPropertySet> xKey(getObject(_nPos),UNO_QUERY); 281 if ( m_pTable->getKeyService().is() ) 282 { 283 m_pTable->getKeyService()->dropKey(m_pTable,xKey); 284 } 285 else 286 { 287 ::rtl::OUStringBuffer aSql; 288 aSql.appendAscii("ALTER TABLE "); 289 290 aSql.append( composeTableName( m_pTable->getConnection()->getMetaData(), m_pTable,::dbtools::eInTableDefinitions, false, false, true )); 291 292 sal_Int32 nKeyType = KeyType::PRIMARY; 293 if ( xKey.is() ) 294 { 295 ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap(); 296 xKey->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_TYPE)) >>= nKeyType; 297 } 298 if ( KeyType::PRIMARY == nKeyType ) 299 { 300 aSql.appendAscii(" DROP PRIMARY KEY"); 301 } 302 else 303 { 304 aSql.append(getDropForeignKey()); 305 const ::rtl::OUString aQuote = m_pTable->getConnection()->getMetaData()->getIdentifierQuoteString(); 306 aSql.append( ::dbtools::quoteName( aQuote,_sElementName) ); 307 } 308 309 Reference< XStatement > xStmt = m_pTable->getConnection()->createStatement( ); 310 if ( xStmt.is() ) 311 { 312 xStmt->execute(aSql.makeStringAndClear()); 313 ::comphelper::disposeComponent(xStmt); 314 } 315 } 316 } 317 } 318 // ----------------------------------------------------------------------------- 319 } // namespace connectivity 320 // ----------------------------------------------------------------------------- 321