1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <connectivity/TKeys.hxx>
21 #include <connectivity/TKey.hxx>
22 #include <connectivity/TTableHelper.hxx>
23 #include <com/sun/star/sdb/tools/XKeyAlteration.hpp>
24 #include <com/sun/star/sdbc/XRow.hpp>
25 #include <com/sun/star/sdbc/XResultSet.hpp>
26 #include <com/sun/star/sdbcx/KeyType.hpp>
27 #include <com/sun/star/sdbc/KeyRule.hpp>
28 #include <com/sun/star/sdbc/SQLException.hpp>
29 #include <connectivity/dbtools.hxx>
30 #include <comphelper/types.hxx>
31 #include <TConnection.hxx>
33 namespace connectivity
35 using namespace comphelper
;
36 using namespace connectivity::sdbcx
;
37 using namespace dbtools
;
38 using namespace ::com::sun::star::uno
;
39 using namespace ::com::sun::star::beans
;
40 using namespace ::com::sun::star::sdbcx
;
41 using namespace ::com::sun::star::sdbc
;
42 using namespace ::com::sun::star::container
;
43 using namespace ::com::sun::star::lang
;
46 OKeysHelper::OKeysHelper( OTableHelper
* _pTable
,
47 ::osl::Mutex
& _rMutex
,
48 const ::std::vector
< OUString
>& _rVector
49 ) : OKeys_BASE(*_pTable
,true,_rMutex
,_rVector
,true)
54 sdbcx::ObjectType
OKeysHelper::createObject(const OUString
& _rName
)
56 sdbcx::ObjectType xRet
;
60 OTableKeyHelper
* pRet
= new OTableKeyHelper(m_pTable
,_rName
,m_pTable
->getKeyProperties(_rName
));
64 if(!xRet
.is()) // we have a primary key with a system name
66 OTableKeyHelper
* pRet
= new OTableKeyHelper(m_pTable
,_rName
,m_pTable
->getKeyProperties(_rName
));
73 void OKeysHelper::impl_refresh()
75 m_pTable
->refreshKeys();
78 Reference
< XPropertySet
> OKeysHelper::createDescriptor()
80 return new OTableKeyHelper(m_pTable
);
83 /** returns the keyrule string for the primary key
85 static OUString
getKeyRuleString(bool _bUpdate
,sal_Int32 _nKeyRule
)
87 const char* pKeyRule
= nullptr;
90 case KeyRule::CASCADE
:
91 pKeyRule
= _bUpdate
? " ON UPDATE CASCADE " : " ON DELETE CASCADE ";
93 case KeyRule::RESTRICT
:
94 pKeyRule
= _bUpdate
? " ON UPDATE RESTRICT " : " ON DELETE RESTRICT ";
96 case KeyRule::SET_NULL
:
97 pKeyRule
= _bUpdate
? " ON UPDATE SET NULL " : " ON DELETE SET NULL ";
99 case KeyRule::SET_DEFAULT
:
100 pKeyRule
= _bUpdate
? " ON UPDATE SET DEFAULT " : " ON DELETE SET DEFAULT ";
107 sRet
= OUString::createFromAscii(pKeyRule
);
111 void OKeysHelper::cloneDescriptorColumns( const sdbcx::ObjectType
& _rSourceDescriptor
, const sdbcx::ObjectType
& _rDestDescriptor
)
113 Reference
< XColumnsSupplier
> xColSupp( _rSourceDescriptor
, UNO_QUERY_THROW
);
114 Reference
< XIndexAccess
> xSourceCols( xColSupp
->getColumns(), UNO_QUERY_THROW
);
116 xColSupp
.set( _rDestDescriptor
, UNO_QUERY_THROW
);
117 Reference
< XAppend
> xDestAppend( xColSupp
->getColumns(), UNO_QUERY_THROW
);
119 sal_Int32 nCount
= xSourceCols
->getCount();
120 for ( sal_Int32 i
=0; i
< nCount
; ++i
)
122 Reference
< XPropertySet
> xColProp( xSourceCols
->getByIndex(i
), UNO_QUERY
);
123 xDestAppend
->appendByDescriptor( xColProp
);
128 sdbcx::ObjectType
OKeysHelper::appendObject( const OUString
& _rForName
, const Reference
< XPropertySet
>& descriptor
)
130 Reference
< XConnection
> xConnection
= m_pTable
->getConnection();
131 if ( !xConnection
.is() )
133 if ( m_pTable
->isNew() )
135 Reference
< XPropertySet
> xNewDescriptor( cloneDescriptor( descriptor
) );
136 cloneDescriptorColumns( descriptor
, xNewDescriptor
);
137 return xNewDescriptor
;
140 const ::dbtools::OPropertyMap
& rPropMap
= OMetaConnection::getPropMap();
141 sal_Int32 nKeyType
= getINT32(descriptor
->getPropertyValue(rPropMap
.getNameByIndex(PROPERTY_ID_TYPE
)));
142 sal_Int32 nUpdateRule
= 0, nDeleteRule
= 0;
143 OUString sReferencedName
;
145 if ( nKeyType
== KeyType::FOREIGN
)
147 descriptor
->getPropertyValue(rPropMap
.getNameByIndex(PROPERTY_ID_REFERENCEDTABLE
)) >>= sReferencedName
;
148 descriptor
->getPropertyValue(rPropMap
.getNameByIndex(PROPERTY_ID_UPDATERULE
)) >>= nUpdateRule
;
149 descriptor
->getPropertyValue(rPropMap
.getNameByIndex(PROPERTY_ID_DELETERULE
)) >>= nDeleteRule
;
152 if ( m_pTable
->getKeyService().is() )
154 m_pTable
->getKeyService()->addKey(m_pTable
,descriptor
);
158 // if we're here, we belong to a table which is not new, i.e. already exists in the database.
159 // In this case, really append the new index.
161 aSql
.append("ALTER TABLE ");
162 OUString aQuote
= m_pTable
->getConnection()->getMetaData()->getIdentifierQuoteString( );
164 aSql
.append(composeTableName( m_pTable
->getConnection()->getMetaData(), m_pTable
, ::dbtools::EComposeRule::InTableDefinitions
, true ));
165 aSql
.append(" ADD ");
167 if ( nKeyType
== KeyType::PRIMARY
)
169 aSql
.append(" PRIMARY KEY (");
171 else if ( nKeyType
== KeyType::FOREIGN
)
173 aSql
.append(" FOREIGN KEY (");
176 throw SQLException();
178 Reference
<XColumnsSupplier
> xColumnSup(descriptor
,UNO_QUERY
);
179 Reference
<XIndexAccess
> xColumns(xColumnSup
->getColumns(),UNO_QUERY
);
180 Reference
< XPropertySet
> xColProp
;
181 for(sal_Int32 i
= 0 ; i
< xColumns
->getCount() ; ++i
)
185 xColProp
.set(xColumns
->getByIndex(i
), css::uno::UNO_QUERY
);
186 aSql
.append( ::dbtools::quoteName( aQuote
,getString(xColProp
->getPropertyValue(rPropMap
.getNameByIndex(PROPERTY_ID_NAME
)))) );
191 if ( nKeyType
== KeyType::FOREIGN
)
193 aSql
.append(" REFERENCES ");
194 aSql
.append(::dbtools::quoteTableName(m_pTable
->getConnection()->getMetaData(),sReferencedName
,::dbtools::EComposeRule::InTableDefinitions
));
197 for(sal_Int32 i
=0;i
<xColumns
->getCount();++i
)
201 xColumns
->getByIndex(i
) >>= xColProp
;
202 aSql
.append(::dbtools::quoteName( aQuote
,getString(xColProp
->getPropertyValue(rPropMap
.getNameByIndex(PROPERTY_ID_RELATEDCOLUMN
)))));
206 aSql
.append(getKeyRuleString(true ,nUpdateRule
));
207 aSql
.append(getKeyRuleString(false ,nDeleteRule
));
210 Reference
< XStatement
> xStmt
= m_pTable
->getConnection()->createStatement( );
211 xStmt
->execute(aSql
.makeStringAndClear());
213 // find the name which the database gave the new key
214 OUString
sNewName( _rForName
);
217 OUString aSchema
,aTable
;
218 m_pTable
->getPropertyValue(rPropMap
.getNameByIndex(PROPERTY_ID_SCHEMANAME
)) >>= aSchema
;
219 m_pTable
->getPropertyValue(rPropMap
.getNameByIndex(PROPERTY_ID_NAME
)) >>= aTable
;
220 Reference
< XResultSet
> xResult
;
221 sal_Int32 nColumn
= 12;
222 if ( nKeyType
== KeyType::FOREIGN
)
223 xResult
= m_pTable
->getMetaData()->getImportedKeys( m_pTable
->getPropertyValue(rPropMap
.getNameByIndex(PROPERTY_ID_CATALOGNAME
))
228 xResult
= m_pTable
->getMetaData()->getPrimaryKeys( m_pTable
->getPropertyValue(rPropMap
.getNameByIndex(PROPERTY_ID_CATALOGNAME
))
235 Reference
< XRow
> xRow(xResult
,UNO_QUERY
);
236 while( xResult
->next() )
238 OUString sName
= xRow
->getString(nColumn
);
239 if ( !m_pElements
->exists(sName
) ) // this name wasn't inserted yet so it must be the new one
241 descriptor
->setPropertyValue( rPropMap
.getNameByIndex( PROPERTY_ID_NAME
), makeAny( sName
) );
246 ::comphelper::disposeComponent(xResult
);
249 catch(const SQLException
&)
253 m_pTable
->addKey(sNewName
,std::make_shared
<sdbcx::KeyProperties
>(sReferencedName
,nKeyType
,nUpdateRule
,nDeleteRule
));
255 return createObject( sNewName
);
258 OUString
OKeysHelper::getDropForeignKey() const
260 return OUString(" DROP CONSTRAINT ");
264 void OKeysHelper::dropObject(sal_Int32 _nPos
, const OUString
& _sElementName
)
266 Reference
< XConnection
> xConnection
= m_pTable
->getConnection();
267 if ( xConnection
.is() && !m_pTable
->isNew() )
269 Reference
<XPropertySet
> xKey(getObject(_nPos
),UNO_QUERY
);
270 if ( m_pTable
->getKeyService().is() )
272 m_pTable
->getKeyService()->dropKey(m_pTable
,xKey
);
277 aSql
.append("ALTER TABLE ");
279 aSql
.append( composeTableName( m_pTable
->getConnection()->getMetaData(), m_pTable
,::dbtools::EComposeRule::InTableDefinitions
, true ));
281 sal_Int32 nKeyType
= KeyType::PRIMARY
;
284 ::dbtools::OPropertyMap
& rPropMap
= OMetaConnection::getPropMap();
285 xKey
->getPropertyValue(rPropMap
.getNameByIndex(PROPERTY_ID_TYPE
)) >>= nKeyType
;
287 if ( KeyType::PRIMARY
== nKeyType
)
289 aSql
.append(" DROP PRIMARY KEY");
293 aSql
.append(getDropForeignKey());
294 const OUString aQuote
= m_pTable
->getConnection()->getMetaData()->getIdentifierQuoteString();
295 aSql
.append( ::dbtools::quoteName( aQuote
,_sElementName
) );
298 Reference
< XStatement
> xStmt
= m_pTable
->getConnection()->createStatement( );
301 xStmt
->execute(aSql
.makeStringAndClear());
302 ::comphelper::disposeComponent(xStmt
);
308 } // namespace connectivity
311 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */