xref: /AOO41X/main/connectivity/source/commontools/TKeys.cxx (revision 9b5730f6ddef7eb82608ca4d31dc0d7678e652cf)
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 
OKeysHelper(OTableHelper * _pTable,::osl::Mutex & _rMutex,const TStringVector & _rVector)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 // -------------------------------------------------------------------------
createObject(const::rtl::OUString & _rName)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 // -------------------------------------------------------------------------
impl_refresh()79 void OKeysHelper::impl_refresh() throw(RuntimeException)
80 {
81     m_pTable->refreshKeys();
82 }
83 // -------------------------------------------------------------------------
createDescriptor()84 Reference< XPropertySet > OKeysHelper::createDescriptor()
85 {
86     return new OTableKeyHelper(m_pTable);
87 }
88 // -----------------------------------------------------------------------------
89 /** returns the keyrule string for the primary key
90 */
getKeyRuleString(sal_Bool _bUpdate,sal_Int32 _nKeyRule)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 // -------------------------------------------------------------------------
cloneDescriptorColumns(const sdbcx::ObjectType & _rSourceDescriptor,const sdbcx::ObjectType & _rDestDescriptor)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
appendObject(const::rtl::OUString & _rForName,const Reference<XPropertySet> & descriptor)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 // -----------------------------------------------------------------------------
getDropForeignKey() const265 ::rtl::OUString OKeysHelper::getDropForeignKey() const
266 {
267     return ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" DROP CONSTRAINT "));
268 }
269 // -------------------------------------------------------------------------
270 // XDrop
dropObject(sal_Int32 _nPos,const::rtl::OUString _sElementName)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