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