Coverage Report

Created: 2026-02-14 09:37

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