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 // ----------------------------------------------------------------------------- 67 virtual ::rtl::OUString getDropForeignKey() const 68 { 69 return ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" DROP FOREIGN KEY ")); 70 } 71 public: 72 OMySQLKeysHelper( OTableHelper* _pTable, 73 ::osl::Mutex& _rMutex, 74 const TStringVector& _rVector 75 ) : OKeysHelper(_pTable,_rMutex,_rVector){} 76 77 }; 78 } 79 } 80 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 // ------------------------------------------------------------------------- 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 // ------------------------------------------------------------------------- 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 // ----------------------------------------------------------------------------- 126 ::cppu::IPropertyArrayHelper* OMySQLTable::createArrayHelper( sal_Int32 /*_nId*/ ) const 127 { 128 return doCreateArrayHelper(); 129 } 130 // ------------------------------------------------------------------------- 131 ::cppu::IPropertyArrayHelper & OMySQLTable::getInfoHelper() 132 { 133 return *static_cast<OMySQLTable_PROP*>(const_cast<OMySQLTable*>(this))->getArrayHelper(isNew() ? 1 : 0); 134 } 135 // ----------------------------------------------------------------------------- 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 // ----------------------------------------------------------------------------- 143 sdbcx::OCollection* OMySQLTable::createKeys(const TStringVector& _rNames) 144 { 145 return new OMySQLKeysHelper(this,m_aMutex,_rNames); 146 } 147 // ----------------------------------------------------------------------------- 148 sdbcx::OCollection* OMySQLTable::createIndexes(const TStringVector& _rNames) 149 { 150 return new OIndexesHelper(this,m_aMutex,_rNames); 151 } 152 //-------------------------------------------------------------------------- 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 //------------------------------------------------------------------ 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 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 // ----------------------------------------------------------------------------- 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 // ----------------------------------------------------------------------------- 317 ::rtl::OUString OMySQLTable::getTypeCreatePattern() const 318 { 319 static const ::rtl::OUString s_sCreatePattern(RTL_CONSTASCII_USTRINGPARAM("(M,D)")); 320 return s_sCreatePattern; 321 } 322 // ----------------------------------------------------------------------------- 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 // ----------------------------------------------------------------------------- 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 // ----------------------------------------------------------------------------- 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 // ----------------------------------------------------------------------------- 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 // ----------------------------------------------------------------------------- 374 ::rtl::OUString OMySQLTable::getRenameStart() const 375 { 376 return ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("RENAME TABLE ")); 377 } 378 379 380 381 382