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