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