/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace ::comphelper; using namespace connectivity::mysql; using namespace connectivity::sdbcx; using namespace connectivity; using namespace ::com::sun::star::uno; using namespace ::com::sun::star::beans; using namespace ::com::sun::star::sdbcx; using namespace ::com::sun::star::sdbc; using namespace ::com::sun::star::container; using namespace ::com::sun::star::lang; namespace connectivity { namespace mysql { class OMySQLKeysHelper : public OKeysHelper { protected: virtual OUString getDropForeignKey() const override { return OUString(" DROP FOREIGN KEY "); } public: OMySQLKeysHelper( OTableHelper* _pTable, ::osl::Mutex& _rMutex, const ::std::vector< OUString>& _rVector ) : OKeysHelper(_pTable,_rMutex,_rVector){} }; } } OMySQLTable::OMySQLTable( sdbcx::OCollection* _pTables, const Reference< XConnection >& _xConnection) :OTableHelper(_pTables,_xConnection,true) { // we create a new table here, so we should have all the rights or ;-) m_nPrivileges = Privilege::DROP | Privilege::REFERENCE | Privilege::ALTER | Privilege::CREATE | Privilege::READ | Privilege::DELETE | Privilege::UPDATE | Privilege::INSERT | Privilege::SELECT; construct(); } OMySQLTable::OMySQLTable( sdbcx::OCollection* _pTables, const Reference< XConnection >& _xConnection, const OUString& Name, const OUString& Type, const OUString& Description , const OUString& SchemaName, const OUString& CatalogName, sal_Int32 _nPrivileges ) : OTableHelper( _pTables, _xConnection, true, Name, Type, Description, SchemaName, CatalogName) , m_nPrivileges(_nPrivileges) { construct(); } void OMySQLTable::construct() { OTableHelper::construct(); if ( !isNew() ) registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRIVILEGES), PROPERTY_ID_PRIVILEGES,PropertyAttribute::READONLY,&m_nPrivileges, cppu::UnoType::get()); } ::cppu::IPropertyArrayHelper* OMySQLTable::createArrayHelper( sal_Int32 /*_nId*/ ) const { return doCreateArrayHelper(); } ::cppu::IPropertyArrayHelper & OMySQLTable::getInfoHelper() { return *static_cast(this)->getArrayHelper(isNew() ? 1 : 0); } sdbcx::OCollection* OMySQLTable::createColumns(const ::std::vector< OUString>& _rNames) { OMySQLColumns* pColumns = new OMySQLColumns(*this,m_aMutex,_rNames); pColumns->setParent(this); return pColumns; } sdbcx::OCollection* OMySQLTable::createKeys(const ::std::vector< OUString>& _rNames) { return new OMySQLKeysHelper(this,m_aMutex,_rNames); } sdbcx::OCollection* OMySQLTable::createIndexes(const ::std::vector< OUString>& _rNames) { return new OIndexesHelper(this,m_aMutex,_rNames); } Sequence< sal_Int8 > OMySQLTable::getUnoTunnelImplementationId() { static ::cppu::OImplementationId implId; return implId.getImplementationId(); } // css::lang::XUnoTunnel sal_Int64 OMySQLTable::getSomething( const Sequence< sal_Int8 > & rId ) { return (rId.getLength() == 16 && 0 == memcmp(getUnoTunnelImplementationId().getConstArray(), rId.getConstArray(), 16 ) ) ? reinterpret_cast< sal_Int64 >( this ) : OTable_TYPEDEF::getSomething(rId); } // XAlterTable void SAL_CALL OMySQLTable::alterColumnByName( const OUString& colName, const Reference< XPropertySet >& descriptor ) { ::osl::MutexGuard aGuard(m_aMutex); checkDisposed( #ifdef __GNUC__ ::connectivity::sdbcx::OTableDescriptor_BASE::rBHelper.bDisposed #else rBHelper.bDisposed #endif ); if ( !m_xColumns || !m_xColumns->hasByName(colName) ) throw NoSuchElementException(colName,*this); if ( !isNew() ) { // first we have to check what should be altered Reference xProp; m_xColumns->getByName(colName) >>= xProp; // first check the types sal_Int32 nOldType = 0,nNewType = 0,nOldPrec = 0,nNewPrec = 0,nOldScale = 0,nNewScale = 0; ::dbtools::OPropertyMap& rProp = OMetaConnection::getPropMap(); xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_TYPE)) >>= nOldType; descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_TYPE)) >>= nNewType; // and precisions and scale xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_PRECISION)) >>= nOldPrec; descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_PRECISION))>>= nNewPrec; xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_SCALE)) >>= nOldScale; descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_SCALE)) >>= nNewScale; // second: check the "is nullable" value sal_Int32 nOldNullable = 0,nNewNullable = 0; xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_ISNULLABLE)) >>= nOldNullable; descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_ISNULLABLE)) >>= nNewNullable; // check also the auto_increment bool bOldAutoIncrement = false,bAutoIncrement = false; xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_ISAUTOINCREMENT)) >>= bOldAutoIncrement; descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_ISAUTOINCREMENT)) >>= bAutoIncrement; bool bColumnNameChanged = false; OUString sOldDesc,sNewDesc; xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_DESCRIPTION)) >>= sOldDesc; descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_DESCRIPTION)) >>= sNewDesc; if ( nOldType != nNewType || nOldPrec != nNewPrec || nOldScale != nNewScale || nNewNullable != nOldNullable || bOldAutoIncrement != bAutoIncrement || sOldDesc != sNewDesc ) { // special handling because they changed the type names to distinguish // if a column should be an auto_incmrement one if ( bOldAutoIncrement != bAutoIncrement ) { OUString sTypeName; descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_TYPENAME)) >>= sTypeName; static const char s_sAutoIncrement[] = "auto_increment"; if ( bAutoIncrement ) { if ( sTypeName.indexOf(s_sAutoIncrement) == -1 ) { sTypeName += " "; sTypeName += s_sAutoIncrement; } } else { sal_Int32 nIndex = 0; if ( !sTypeName.isEmpty() && (nIndex = sTypeName.indexOf(s_sAutoIncrement)) != -1 ) { sTypeName = sTypeName.copy(0,nIndex); descriptor->setPropertyValue(rProp.getNameByIndex(PROPERTY_ID_TYPENAME),makeAny(sTypeName)); } } } alterColumnType(nNewType,colName,descriptor); bColumnNameChanged = true; } // third: check the default values OUString sNewDefault,sOldDefault; xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_DEFAULTVALUE)) >>= sOldDefault; descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_DEFAULTVALUE)) >>= sNewDefault; if(!sOldDefault.isEmpty()) { dropDefaultValue(colName); if(!sNewDefault.isEmpty() && sOldDefault != sNewDefault) alterDefaultValue(sNewDefault,colName); } else if(!sNewDefault.isEmpty()) alterDefaultValue(sNewDefault,colName); // now we should look if the name of the column changed OUString sNewColumnName; descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_NAME)) >>= sNewColumnName; if ( !sNewColumnName.equalsIgnoreAsciiCase(colName) && !bColumnNameChanged ) { const OUString sQuote = getMetaData()->getIdentifierQuoteString( ); OUString sSql = getAlterTableColumnPart() + " CHANGE " + ::dbtools::quoteName(sQuote,colName) + " " + OTables::adjustSQL(::dbtools::createStandardColumnPart(descriptor,getConnection(),static_cast(m_pTables),getTypeCreatePattern())); executeStatement(sSql); } m_xColumns->refresh(); } else { if(m_xColumns) { m_xColumns->dropByName(colName); m_xColumns->appendByDescriptor(descriptor); } } } void OMySQLTable::alterColumnType(sal_Int32 nNewType,const OUString& _rColName, const Reference& _xDescriptor) { const OUString sQuote = getMetaData()->getIdentifierQuoteString( ); OUString sSql = getAlterTableColumnPart() + " CHANGE " + ::dbtools::quoteName(sQuote,_rColName) + " "; OColumn* pColumn = new OColumn(true); Reference xProp = pColumn; ::comphelper::copyProperties(_xDescriptor,xProp); xProp->setPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE),makeAny(nNewType)); sSql += OTables::adjustSQL(::dbtools::createStandardColumnPart(xProp,getConnection(),static_cast(m_pTables),getTypeCreatePattern())); executeStatement(sSql); } OUString OMySQLTable::getTypeCreatePattern() const { return OUString("(M,D)"); } void OMySQLTable::alterDefaultValue(const OUString& _sNewDefault,const OUString& _rColName) { const OUString sQuote = getMetaData()->getIdentifierQuoteString( ); OUString sSql = getAlterTableColumnPart() + " ALTER " + ::dbtools::quoteName(sQuote,_rColName) + " SET DEFAULT '" + _sNewDefault + "'"; executeStatement(sSql); } void OMySQLTable::dropDefaultValue(const OUString& _rColName) { const OUString sQuote = getMetaData()->getIdentifierQuoteString( ); OUString sSql = getAlterTableColumnPart() + " ALTER " + ::dbtools::quoteName(sQuote,_rColName) + " DROP DEFAULT"; executeStatement(sSql); } OUString OMySQLTable::getAlterTableColumnPart() { OUString sSql( "ALTER TABLE " ); OUString sComposedName( ::dbtools::composeTableName( getMetaData(), m_CatalogName, m_SchemaName, m_Name, true, ::dbtools::EComposeRule::InTableDefinitions ) ); sSql += sComposedName; return sSql; } void OMySQLTable::executeStatement(const OUString& _rStatement ) { OUString sSQL = _rStatement; if(sSQL.endsWith(",")) sSQL = sSQL.replaceAt(sSQL.getLength()-1, 1, ")"); Reference< XStatement > xStmt = getConnection()->createStatement( ); if ( xStmt.is() ) { xStmt->execute(sSQL); ::comphelper::disposeComponent(xStmt); } } OUString OMySQLTable::getRenameStart() const { return OUString("RENAME TABLE "); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */