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 <string.h>
21 : #include "mysql/YTable.hxx"
22 : #include "mysql/YTables.hxx"
23 : #include <com/sun/star/sdbc/XRow.hpp>
24 : #include <com/sun/star/sdbc/XResultSet.hpp>
25 : #include <com/sun/star/sdbcx/KeyType.hpp>
26 : #include <com/sun/star/sdbc/KeyRule.hpp>
27 : #include <cppuhelper/typeprovider.hxx>
28 : #include <com/sun/star/lang/DisposedException.hpp>
29 : #include <com/sun/star/sdbc/ColumnValue.hpp>
30 : #include <com/sun/star/sdbcx/Privilege.hpp>
31 : #include <comphelper/property.hxx>
32 : #include <comphelper/extract.hxx>
33 : #include <comphelper/types.hxx>
34 : #include <connectivity/dbtools.hxx>
35 : #include <connectivity/sdbcx/VColumn.hxx>
36 : #include <connectivity/TKeys.hxx>
37 : #include <connectivity/TIndexes.hxx>
38 : #include <connectivity/TColumnsHelper.hxx>
39 : #include "mysql/YCatalog.hxx"
40 : #include "mysql/YColumns.hxx"
41 : #include "TConnection.hxx"
42 :
43 :
44 : using namespace ::comphelper;
45 : using namespace connectivity::mysql;
46 : using namespace connectivity::sdbcx;
47 : using namespace connectivity;
48 : using namespace ::com::sun::star::uno;
49 : using namespace ::com::sun::star::beans;
50 : using namespace ::com::sun::star::sdbcx;
51 : using namespace ::com::sun::star::sdbc;
52 : using namespace ::com::sun::star::container;
53 : using namespace ::com::sun::star::lang;
54 : namespace connectivity
55 : {
56 : namespace mysql
57 : {
58 0 : class OMySQLKeysHelper : public OKeysHelper
59 : {
60 : protected:
61 :
62 0 : virtual OUString getDropForeignKey() const SAL_OVERRIDE
63 : {
64 0 : return OUString(" DROP FOREIGN KEY ");
65 : }
66 : public:
67 0 : OMySQLKeysHelper( OTableHelper* _pTable,
68 : ::osl::Mutex& _rMutex,
69 : const TStringVector& _rVector
70 0 : ) : OKeysHelper(_pTable,_rMutex,_rVector){}
71 :
72 : };
73 : }
74 : }
75 :
76 0 : OMySQLTable::OMySQLTable( sdbcx::OCollection* _pTables,
77 : const Reference< XConnection >& _xConnection)
78 0 : :OTableHelper(_pTables,_xConnection,true)
79 : {
80 : // we create a new table here, so we should have all the rights or ;-)
81 : m_nPrivileges = Privilege::DROP |
82 : Privilege::REFERENCE |
83 : Privilege::ALTER |
84 : Privilege::CREATE |
85 : Privilege::READ |
86 : Privilege::DELETE |
87 : Privilege::UPDATE |
88 : Privilege::INSERT |
89 0 : Privilege::SELECT;
90 0 : construct();
91 0 : }
92 :
93 0 : OMySQLTable::OMySQLTable( sdbcx::OCollection* _pTables,
94 : const Reference< XConnection >& _xConnection,
95 : const OUString& _Name,
96 : const OUString& _Type,
97 : const OUString& _Description ,
98 : const OUString& _SchemaName,
99 : const OUString& _CatalogName,
100 : sal_Int32 _nPrivileges
101 : ) : OTableHelper( _pTables,
102 : _xConnection,
103 : true,
104 : _Name,
105 : _Type,
106 : _Description,
107 : _SchemaName,
108 : _CatalogName)
109 0 : , m_nPrivileges(_nPrivileges)
110 : {
111 0 : construct();
112 0 : }
113 :
114 0 : void OMySQLTable::construct()
115 : {
116 0 : OTableHelper::construct();
117 0 : if ( !isNew() )
118 0 : registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRIVILEGES), PROPERTY_ID_PRIVILEGES,PropertyAttribute::READONLY,&m_nPrivileges, cppu::UnoType<decltype(m_nPrivileges)>::get());
119 0 : }
120 :
121 0 : ::cppu::IPropertyArrayHelper* OMySQLTable::createArrayHelper( sal_Int32 /*_nId*/ ) const
122 : {
123 0 : return doCreateArrayHelper();
124 : }
125 :
126 0 : ::cppu::IPropertyArrayHelper & OMySQLTable::getInfoHelper()
127 : {
128 0 : return *static_cast<OMySQLTable_PROP*>(this)->getArrayHelper(isNew() ? 1 : 0);
129 : }
130 :
131 0 : sdbcx::OCollection* OMySQLTable::createColumns(const TStringVector& _rNames)
132 : {
133 0 : OMySQLColumns* pColumns = new OMySQLColumns(*this,true,m_aMutex,_rNames);
134 0 : pColumns->setParent(this);
135 0 : return pColumns;
136 : }
137 :
138 0 : sdbcx::OCollection* OMySQLTable::createKeys(const TStringVector& _rNames)
139 : {
140 0 : return new OMySQLKeysHelper(this,m_aMutex,_rNames);
141 : }
142 :
143 0 : sdbcx::OCollection* OMySQLTable::createIndexes(const TStringVector& _rNames)
144 : {
145 0 : return new OIndexesHelper(this,m_aMutex,_rNames);
146 : }
147 :
148 0 : Sequence< sal_Int8 > OMySQLTable::getUnoTunnelImplementationId()
149 : {
150 : static ::cppu::OImplementationId * pId = 0;
151 0 : if (! pId)
152 : {
153 0 : ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
154 0 : if (! pId)
155 : {
156 0 : static ::cppu::OImplementationId aId;
157 0 : pId = &aId;
158 0 : }
159 : }
160 0 : return pId->getImplementationId();
161 : }
162 :
163 : // com::sun::star::lang::XUnoTunnel
164 :
165 0 : sal_Int64 OMySQLTable::getSomething( const Sequence< sal_Int8 > & rId ) throw (RuntimeException, std::exception)
166 : {
167 0 : return (rId.getLength() == 16 && 0 == memcmp(getUnoTunnelImplementationId().getConstArray(), rId.getConstArray(), 16 ) )
168 : ? reinterpret_cast< sal_Int64 >( this )
169 0 : : OTable_TYPEDEF::getSomething(rId);
170 : }
171 :
172 : // XAlterTable
173 0 : void SAL_CALL OMySQLTable::alterColumnByName( const OUString& colName, const Reference< XPropertySet >& descriptor ) throw(SQLException, NoSuchElementException, RuntimeException, std::exception)
174 : {
175 0 : ::osl::MutexGuard aGuard(m_aMutex);
176 : checkDisposed(
177 : #ifdef __GNUC__
178 : ::connectivity::sdbcx::OTableDescriptor_BASE::rBHelper.bDisposed
179 : #else
180 : rBHelper.bDisposed
181 : #endif
182 0 : );
183 :
184 0 : if ( !m_pColumns || !m_pColumns->hasByName(colName) )
185 0 : throw NoSuchElementException(colName,*this);
186 :
187 :
188 0 : if ( !isNew() )
189 : {
190 : // first we have to check what should be altered
191 0 : Reference<XPropertySet> xProp;
192 0 : m_pColumns->getByName(colName) >>= xProp;
193 : // first check the types
194 0 : sal_Int32 nOldType = 0,nNewType = 0,nOldPrec = 0,nNewPrec = 0,nOldScale = 0,nNewScale = 0;
195 :
196 0 : ::dbtools::OPropertyMap& rProp = OMetaConnection::getPropMap();
197 0 : xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_TYPE)) >>= nOldType;
198 0 : descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_TYPE)) >>= nNewType;
199 : // and precisions and scale
200 0 : xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_PRECISION)) >>= nOldPrec;
201 0 : descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_PRECISION))>>= nNewPrec;
202 0 : xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_SCALE)) >>= nOldScale;
203 0 : descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_SCALE)) >>= nNewScale;
204 : // second: check the "is nullable" value
205 0 : sal_Int32 nOldNullable = 0,nNewNullable = 0;
206 0 : xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_ISNULLABLE)) >>= nOldNullable;
207 0 : descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_ISNULLABLE)) >>= nNewNullable;
208 :
209 : // check also the auto_increment
210 0 : bool bOldAutoIncrement = false,bAutoIncrement = false;
211 0 : xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_ISAUTOINCREMENT)) >>= bOldAutoIncrement;
212 0 : descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_ISAUTOINCREMENT)) >>= bAutoIncrement;
213 0 : bool bColumnNameChanged = false;
214 0 : OUString sOldDesc,sNewDesc;
215 0 : xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_DESCRIPTION)) >>= sOldDesc;
216 0 : descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_DESCRIPTION)) >>= sNewDesc;
217 :
218 0 : if ( nOldType != nNewType
219 0 : || nOldPrec != nNewPrec
220 0 : || nOldScale != nNewScale
221 0 : || nNewNullable != nOldNullable
222 0 : || bOldAutoIncrement != bAutoIncrement
223 0 : || sOldDesc != sNewDesc )
224 : {
225 : // special handling because they change dthe type names to distinguish
226 : // if a column should be an auto_incmrement one
227 0 : if ( bOldAutoIncrement != bAutoIncrement )
228 : {
229 0 : OUString sTypeName;
230 0 : descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_TYPENAME)) >>= sTypeName;
231 :
232 : static const char s_sAutoIncrement[] = "auto_increment";
233 0 : if ( bAutoIncrement )
234 : {
235 0 : if ( sTypeName.indexOf(s_sAutoIncrement) == -1 )
236 : {
237 0 : sTypeName += " ";
238 0 : sTypeName += s_sAutoIncrement;
239 : }
240 : }
241 : else
242 : {
243 0 : sal_Int32 nIndex = 0;
244 0 : if ( !sTypeName.isEmpty() && (nIndex = sTypeName.indexOf(s_sAutoIncrement)) != -1 )
245 : {
246 0 : sTypeName = sTypeName.copy(0,nIndex);
247 0 : descriptor->setPropertyValue(rProp.getNameByIndex(PROPERTY_ID_TYPENAME),makeAny(sTypeName));
248 : }
249 0 : }
250 : }
251 0 : alterColumnType(nNewType,colName,descriptor);
252 0 : bColumnNameChanged = true;
253 : }
254 :
255 : // third: check the default values
256 0 : OUString sNewDefault,sOldDefault;
257 0 : xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_DEFAULTVALUE)) >>= sOldDefault;
258 0 : descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_DEFAULTVALUE)) >>= sNewDefault;
259 :
260 0 : if(!sOldDefault.isEmpty())
261 : {
262 0 : dropDefaultValue(colName);
263 0 : if(!sNewDefault.isEmpty() && sOldDefault != sNewDefault)
264 0 : alterDefaultValue(sNewDefault,colName);
265 : }
266 0 : else if(!sNewDefault.isEmpty())
267 0 : alterDefaultValue(sNewDefault,colName);
268 :
269 : // now we should look if the name of the column changed
270 0 : OUString sNewColumnName;
271 0 : descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_NAME)) >>= sNewColumnName;
272 0 : if ( !sNewColumnName.equalsIgnoreAsciiCase(colName) && !bColumnNameChanged )
273 : {
274 0 : const OUString sQuote = getMetaData()->getIdentifierQuoteString( );
275 0 : OUString sSql = getAlterTableColumnPart() +
276 0 : " CHANGE " + ::dbtools::quoteName(sQuote,colName) +
277 0 : " " + OTables::adjustSQL(::dbtools::createStandardColumnPart(descriptor,getConnection(),static_cast<OTables*>(m_pTables),getTypeCreatePattern()));
278 0 : executeStatement(sSql);
279 : }
280 0 : m_pColumns->refresh();
281 : }
282 : else
283 : {
284 0 : if(m_pColumns)
285 : {
286 0 : m_pColumns->dropByName(colName);
287 0 : m_pColumns->appendByDescriptor(descriptor);
288 : }
289 0 : }
290 :
291 0 : }
292 :
293 0 : void OMySQLTable::alterColumnType(sal_Int32 nNewType,const OUString& _rColName, const Reference<XPropertySet>& _xDescriptor)
294 : {
295 0 : const OUString sQuote = getMetaData()->getIdentifierQuoteString( );
296 0 : OUString sSql = getAlterTableColumnPart() +
297 0 : " CHANGE " + ::dbtools::quoteName(sQuote,_rColName) +
298 0 : " ";
299 :
300 0 : OColumn* pColumn = new OColumn(true);
301 0 : Reference<XPropertySet> xProp = pColumn;
302 0 : ::comphelper::copyProperties(_xDescriptor,xProp);
303 0 : xProp->setPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE),makeAny(nNewType));
304 :
305 0 : sSql += OTables::adjustSQL(::dbtools::createStandardColumnPart(xProp,getConnection(),static_cast<OTables*>(m_pTables),getTypeCreatePattern()));
306 0 : executeStatement(sSql);
307 0 : }
308 :
309 0 : OUString OMySQLTable::getTypeCreatePattern() const
310 : {
311 0 : return OUString("(M,D)");
312 : }
313 :
314 0 : void OMySQLTable::alterDefaultValue(const OUString& _sNewDefault,const OUString& _rColName)
315 : {
316 0 : const OUString sQuote = getMetaData()->getIdentifierQuoteString( );
317 0 : OUString sSql = getAlterTableColumnPart() +
318 0 : " ALTER " + ::dbtools::quoteName(sQuote,_rColName) +
319 0 : " SET DEFAULT '" + _sNewDefault + "'";
320 :
321 0 : executeStatement(sSql);
322 0 : }
323 :
324 0 : void OMySQLTable::dropDefaultValue(const OUString& _rColName)
325 : {
326 0 : const OUString sQuote = getMetaData()->getIdentifierQuoteString( );
327 0 : OUString sSql = getAlterTableColumnPart() +
328 0 : " ALTER " + ::dbtools::quoteName(sQuote,_rColName) +
329 0 : " DROP DEFAULT";
330 :
331 0 : executeStatement(sSql);
332 0 : }
333 :
334 0 : OUString OMySQLTable::getAlterTableColumnPart()
335 : {
336 0 : OUString sSql( "ALTER TABLE " );
337 :
338 : OUString sComposedName(
339 0 : ::dbtools::composeTableName( getMetaData(), m_CatalogName, m_SchemaName, m_Name, true, ::dbtools::eInTableDefinitions ) );
340 0 : sSql += sComposedName;
341 :
342 0 : return sSql;
343 : }
344 :
345 0 : void OMySQLTable::executeStatement(const OUString& _rStatement )
346 : {
347 0 : OUString sSQL = _rStatement;
348 0 : if(sSQL.endsWith(","))
349 0 : sSQL = sSQL.replaceAt(sSQL.getLength()-1, 1, ")");
350 :
351 0 : Reference< XStatement > xStmt = getConnection()->createStatement( );
352 0 : if ( xStmt.is() )
353 : {
354 0 : xStmt->execute(sSQL);
355 0 : ::comphelper::disposeComponent(xStmt);
356 0 : }
357 0 : }
358 :
359 0 : OUString OMySQLTable::getRenameStart() const
360 : {
361 0 : return OUString("RENAME TABLE ");
362 : }
363 :
364 :
365 :
366 :
367 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|