/************************************************************** * * 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 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_connectivity.hxx" #include "hsqldb/HTable.hxx" #include "hsqldb/HTables.hxx" #include #include #include #include #include #include #include #include #include #include #include #include "connectivity/dbtools.hxx" #include "connectivity/sdbcx/VColumn.hxx" #include "connectivity/TKeys.hxx" #include "connectivity/TIndexes.hxx" #include "connectivity/TColumnsHelper.hxx" #include "hsqldb/HCatalog.hxx" #include "hsqldb/HColumns.hxx" #include "TConnection.hxx" #include using namespace ::comphelper; using namespace connectivity::hsqldb; 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; OHSQLTable::OHSQLTable( sdbcx::OCollection* _pTables, const Reference< XConnection >& _xConnection) :OTableHelper(_pTables,_xConnection,sal_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(); } // ------------------------------------------------------------------------- OHSQLTable::OHSQLTable( 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 ) : OTableHelper( _pTables, _xConnection, sal_True, _Name, _Type, _Description, _SchemaName, _CatalogName) , m_nPrivileges(_nPrivileges) { construct(); } // ------------------------------------------------------------------------- void OHSQLTable::construct() { OTableHelper::construct(); if ( !isNew() ) registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRIVILEGES), PROPERTY_ID_PRIVILEGES,PropertyAttribute::READONLY,&m_nPrivileges, ::getCppuType(&m_nPrivileges)); } // ----------------------------------------------------------------------------- ::cppu::IPropertyArrayHelper* OHSQLTable::createArrayHelper( sal_Int32 /*_nId*/ ) const { return doCreateArrayHelper(); } // ------------------------------------------------------------------------- ::cppu::IPropertyArrayHelper & OHSQLTable::getInfoHelper() { return *static_cast(const_cast(this))->getArrayHelper(isNew() ? 1 : 0); } // ----------------------------------------------------------------------------- sdbcx::OCollection* OHSQLTable::createColumns(const TStringVector& _rNames) { OHSQLColumns* pColumns = new OHSQLColumns(*this,sal_True,m_aMutex,_rNames); pColumns->setParent(this); return pColumns; } // ----------------------------------------------------------------------------- sdbcx::OCollection* OHSQLTable::createKeys(const TStringVector& _rNames) { return new OKeysHelper(this,m_aMutex,_rNames); } // ----------------------------------------------------------------------------- sdbcx::OCollection* OHSQLTable::createIndexes(const TStringVector& _rNames) { return new OIndexesHelper(this,m_aMutex,_rNames); } //-------------------------------------------------------------------------- Sequence< sal_Int8 > OHSQLTable::getUnoTunnelImplementationId() { static ::cppu::OImplementationId * pId = 0; if (! pId) { ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); if (! pId) { static ::cppu::OImplementationId aId; pId = &aId; } } return pId->getImplementationId(); } // com::sun::star::lang::XUnoTunnel //------------------------------------------------------------------ sal_Int64 OHSQLTable::getSomething( const Sequence< sal_Int8 > & rId ) throw (RuntimeException) { return (rId.getLength() == 16 && 0 == rtl_compareMemory(getUnoTunnelImplementationId().getConstArray(), rId.getConstArray(), 16 ) ) ? reinterpret_cast< sal_Int64 >( this ) : OTable_TYPEDEF::getSomething(rId); } // ------------------------------------------------------------------------- // XAlterTable void SAL_CALL OHSQLTable::alterColumnByName( const ::rtl::OUString& colName, const Reference< XPropertySet >& descriptor ) throw(SQLException, NoSuchElementException, RuntimeException) { ::osl::MutexGuard aGuard(m_aMutex); checkDisposed( #ifdef GCC ::connectivity::sdbcx::OTableDescriptor_BASE::rBHelper.bDisposed #else rBHelper.bDisposed #endif ); if ( m_pColumns && !m_pColumns->hasByName(colName) ) throw NoSuchElementException(colName,*this); if ( !isNew() ) { // first we have to check what should be altered Reference xProp; m_pColumns->getByName(colName) >>= xProp; // first check the types sal_Int32 nOldType = 0,nNewType = 0,nOldPrec = 0,nNewPrec = 0,nOldScale = 0,nNewScale = 0; ::rtl::OUString sOldTypeName, sNewTypeName; ::dbtools::OPropertyMap& rProp = OMetaConnection::getPropMap(); // type/typename xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_TYPE)) >>= nOldType; descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_TYPE)) >>= nNewType; xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_TYPENAME)) >>= sOldTypeName; descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_TYPENAME))>>= sNewTypeName; // and precsions 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 sal_Bool bOldAutoIncrement = sal_False,bAutoIncrement = sal_False; xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_ISAUTOINCREMENT)) >>= bOldAutoIncrement; descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_ISAUTOINCREMENT)) >>= bAutoIncrement; // now we should look if the name of the column changed ::rtl::OUString sNewColumnName; descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_NAME)) >>= sNewColumnName; if ( !sNewColumnName.equals(colName) ) { const ::rtl::OUString sQuote = getMetaData()->getIdentifierQuoteString( ); ::rtl::OUString sSql = getAlterTableColumnPart(); sSql += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" ALTER COLUMN ")); sSql += ::dbtools::quoteName(sQuote,colName); sSql += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" RENAME TO ")); sSql += ::dbtools::quoteName(sQuote,sNewColumnName); executeStatement(sSql); } if ( nOldType != nNewType || sOldTypeName != sNewTypeName || nOldPrec != nNewPrec || nOldScale != nNewScale || nNewNullable != nOldNullable || bOldAutoIncrement != bAutoIncrement ) { // special handling because they change the type names to distinguish // if a column should be an auto_incmrement one if ( bOldAutoIncrement != bAutoIncrement ) { /// TODO: insert special handling for auto increment "IDENTITY" and primary key } alterColumnType(nNewType,sNewColumnName,descriptor); } // third: check the default values ::rtl::OUString sNewDefault,sOldDefault; xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_DEFAULTVALUE)) >>= sOldDefault; descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_DEFAULTVALUE)) >>= sNewDefault; if(sOldDefault.getLength()) { dropDefaultValue(colName); if(sNewDefault.getLength() && sOldDefault != sNewDefault) alterDefaultValue(sNewDefault,sNewColumnName); } else if(!sOldDefault.getLength() && sNewDefault.getLength()) alterDefaultValue(sNewDefault,sNewColumnName); m_pColumns->refresh(); } else { if(m_pColumns) { m_pColumns->dropByName(colName); m_pColumns->appendByDescriptor(descriptor); } } } // ----------------------------------------------------------------------------- void OHSQLTable::alterColumnType(sal_Int32 nNewType,const ::rtl::OUString& _rColName, const Reference& _xDescriptor) { ::rtl::OUString sSql = getAlterTableColumnPart(); sSql += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" ALTER COLUMN ")); #if OSL_DEBUG_LEVEL > 0 try { ::rtl::OUString sDescriptorName; OSL_ENSURE( _xDescriptor.is() && ( _xDescriptor->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_NAME ) ) >>= sDescriptorName ) && ( sDescriptorName == _rColName ), "OHSQLTable::alterColumnType: unexpected column name!" ); } catch( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); } #else (void)_rColName; #endif OHSQLColumn* pColumn = new OHSQLColumn(sal_True); Reference xProp = pColumn; ::comphelper::copyProperties(_xDescriptor,xProp); xProp->setPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE),makeAny(nNewType)); sSql += ::dbtools::createStandardColumnPart(xProp,getConnection()); executeStatement(sSql); } // ----------------------------------------------------------------------------- void OHSQLTable::alterDefaultValue(const ::rtl::OUString& _sNewDefault,const ::rtl::OUString& _rColName) { ::rtl::OUString sSql = getAlterTableColumnPart(); sSql += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" ALTER COLUMN ")); const ::rtl::OUString sQuote = getMetaData()->getIdentifierQuoteString( ); sSql += ::dbtools::quoteName(sQuote,_rColName); sSql += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" SET DEFAULT '")) + _sNewDefault; sSql += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("'")); executeStatement(sSql); } // ----------------------------------------------------------------------------- void OHSQLTable::dropDefaultValue(const ::rtl::OUString& _rColName) { ::rtl::OUString sSql = getAlterTableColumnPart(); sSql += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" ALTER COLUMN ")); const ::rtl::OUString sQuote = getMetaData()->getIdentifierQuoteString( ); sSql += ::dbtools::quoteName(sQuote,_rColName); sSql += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" DROP DEFAULT")); executeStatement(sSql); } // ----------------------------------------------------------------------------- ::rtl::OUString OHSQLTable::getAlterTableColumnPart() { ::rtl::OUString sSql = ::rtl::OUString::createFromAscii("ALTER TABLE "); const ::rtl::OUString sQuote = getMetaData()->getIdentifierQuoteString( ); ::rtl::OUString sComposedName( ::dbtools::composeTableName( getMetaData(), m_CatalogName, m_SchemaName, m_Name, sal_True, ::dbtools::eInTableDefinitions ) ); sSql += sComposedName; return sSql; } // ----------------------------------------------------------------------------- void OHSQLTable::executeStatement(const ::rtl::OUString& _rStatement ) { ::rtl::OUString sSQL = _rStatement; if(sSQL.lastIndexOf(',') == (sSQL.getLength()-1)) sSQL = sSQL.replaceAt(sSQL.getLength()-1,1,::rtl::OUString::createFromAscii(")")); Reference< XStatement > xStmt = getConnection()->createStatement( ); if ( xStmt.is() ) { try { xStmt->execute(sSQL); } catch( const Exception& ) { ::comphelper::disposeComponent(xStmt); throw; } ::comphelper::disposeComponent(xStmt); } } // ----------------------------------------------------------------------------- Sequence< Type > SAL_CALL OHSQLTable::getTypes( ) throw(RuntimeException) { if ( ! m_Type.compareToAscii("VIEW") ) { Sequence< Type > aTypes = OTableHelper::getTypes(); ::std::vector aOwnTypes; aOwnTypes.reserve(aTypes.getLength()); const Type* pIter = aTypes.getConstArray(); const Type* pEnd = pIter + aTypes.getLength(); for(;pIter != pEnd;++pIter) { if( *pIter != ::getCppuType((const Reference*)0) ) { aOwnTypes.push_back(*pIter); } } Type *pTypes = aOwnTypes.empty() ? 0 : &aOwnTypes[0]; return Sequence< Type >(pTypes, aOwnTypes.size()); } return OTableHelper::getTypes(); } // ------------------------------------------------------------------------- // XRename void SAL_CALL OHSQLTable::rename( const ::rtl::OUString& newName ) throw(SQLException, ElementExistException, RuntimeException) { ::osl::MutexGuard aGuard(m_aMutex); checkDisposed( #ifdef GCC ::connectivity::sdbcx::OTableDescriptor_BASE::rBHelper.bDisposed #else rBHelper.bDisposed #endif ); if(!isNew()) { ::rtl::OUString sSql = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ALTER ")); if ( m_Type == ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("VIEW")) ) sSql += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" VIEW ")); else sSql += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" TABLE ")); ::rtl::OUString sQuote = getMetaData()->getIdentifierQuoteString( ); ::rtl::OUString sCatalog,sSchema,sTable; ::dbtools::qualifiedNameComponents(getMetaData(),newName,sCatalog,sSchema,sTable,::dbtools::eInDataManipulation); ::rtl::OUString sComposedName( ::dbtools::composeTableName( getMetaData(), m_CatalogName, m_SchemaName, m_Name, sal_True, ::dbtools::eInDataManipulation ) ); sSql += sComposedName + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" RENAME TO ")); sSql += ::dbtools::composeTableName( getMetaData(), sCatalog, sSchema, sTable, sal_True, ::dbtools::eInDataManipulation ); executeStatement(sSql); ::connectivity::OTable_TYPEDEF::rename(newName); } else ::dbtools::qualifiedNameComponents(getMetaData(),newName,m_CatalogName,m_SchemaName,m_Name,::dbtools::eInTableDefinitions); } // ------------------------------------------------------------------------- Any SAL_CALL OHSQLTable::queryInterface( const Type & rType ) throw(RuntimeException) { if( !m_Type.compareToAscii("VIEW") && rType == ::getCppuType((const Reference*)0) ) return Any(); return OTableHelper::queryInterface(rType); } // -------------------------------------------------------------------------