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