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 "hsqldb/HTable.hxx" 27 #include "hsqldb/HTables.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 "hsqldb/HCatalog.hxx" 45 #include "hsqldb/HColumns.hxx" 46 #include "TConnection.hxx" 47 48 #include <tools/diagnose_ex.h> 49 50 51 using namespace ::comphelper; 52 using namespace connectivity::hsqldb; 53 using namespace connectivity::sdbcx; 54 using namespace connectivity; 55 using namespace ::com::sun::star::uno; 56 using namespace ::com::sun::star::beans; 57 using namespace ::com::sun::star::sdbcx; 58 using namespace ::com::sun::star::sdbc; 59 using namespace ::com::sun::star::container; 60 using namespace ::com::sun::star::lang; 61 62 OHSQLTable::OHSQLTable( sdbcx::OCollection* _pTables, 63 const Reference< XConnection >& _xConnection) 64 :OTableHelper(_pTables,_xConnection,sal_True) 65 { 66 // we create a new table here, so we should have all the rights or ;-) 67 m_nPrivileges = Privilege::DROP | 68 Privilege::REFERENCE | 69 Privilege::ALTER | 70 Privilege::CREATE | 71 Privilege::READ | 72 Privilege::DELETE | 73 Privilege::UPDATE | 74 Privilege::INSERT | 75 Privilege::SELECT; 76 construct(); 77 } 78 // ------------------------------------------------------------------------- 79 OHSQLTable::OHSQLTable( sdbcx::OCollection* _pTables, 80 const Reference< XConnection >& _xConnection, 81 const ::rtl::OUString& _Name, 82 const ::rtl::OUString& _Type, 83 const ::rtl::OUString& _Description , 84 const ::rtl::OUString& _SchemaName, 85 const ::rtl::OUString& _CatalogName, 86 sal_Int32 _nPrivileges 87 ) : OTableHelper( _pTables, 88 _xConnection, 89 sal_True, 90 _Name, 91 _Type, 92 _Description, 93 _SchemaName, 94 _CatalogName) 95 , m_nPrivileges(_nPrivileges) 96 { 97 construct(); 98 } 99 // ------------------------------------------------------------------------- 100 void OHSQLTable::construct() 101 { 102 OTableHelper::construct(); 103 if ( !isNew() ) 104 registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRIVILEGES), PROPERTY_ID_PRIVILEGES,PropertyAttribute::READONLY,&m_nPrivileges, ::getCppuType(&m_nPrivileges)); 105 } 106 // ----------------------------------------------------------------------------- 107 ::cppu::IPropertyArrayHelper* OHSQLTable::createArrayHelper( sal_Int32 /*_nId*/ ) const 108 { 109 return doCreateArrayHelper(); 110 } 111 // ------------------------------------------------------------------------- 112 ::cppu::IPropertyArrayHelper & OHSQLTable::getInfoHelper() 113 { 114 return *static_cast<OHSQLTable_PROP*>(const_cast<OHSQLTable*>(this))->getArrayHelper(isNew() ? 1 : 0); 115 } 116 // ----------------------------------------------------------------------------- 117 sdbcx::OCollection* OHSQLTable::createColumns(const TStringVector& _rNames) 118 { 119 OHSQLColumns* pColumns = new OHSQLColumns(*this,sal_True,m_aMutex,_rNames); 120 pColumns->setParent(this); 121 return pColumns; 122 } 123 // ----------------------------------------------------------------------------- 124 sdbcx::OCollection* OHSQLTable::createKeys(const TStringVector& _rNames) 125 { 126 return new OKeysHelper(this,m_aMutex,_rNames); 127 } 128 // ----------------------------------------------------------------------------- 129 sdbcx::OCollection* OHSQLTable::createIndexes(const TStringVector& _rNames) 130 { 131 return new OIndexesHelper(this,m_aMutex,_rNames); 132 } 133 //-------------------------------------------------------------------------- 134 Sequence< sal_Int8 > OHSQLTable::getUnoTunnelImplementationId() 135 { 136 static ::cppu::OImplementationId * pId = 0; 137 if (! pId) 138 { 139 ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); 140 if (! pId) 141 { 142 static ::cppu::OImplementationId aId; 143 pId = &aId; 144 } 145 } 146 return pId->getImplementationId(); 147 } 148 149 // com::sun::star::lang::XUnoTunnel 150 //------------------------------------------------------------------ 151 sal_Int64 OHSQLTable::getSomething( const Sequence< sal_Int8 > & rId ) throw (RuntimeException) 152 { 153 return (rId.getLength() == 16 && 0 == rtl_compareMemory(getUnoTunnelImplementationId().getConstArray(), rId.getConstArray(), 16 ) ) 154 ? reinterpret_cast< sal_Int64 >( this ) 155 : OTable_TYPEDEF::getSomething(rId); 156 } 157 // ------------------------------------------------------------------------- 158 // XAlterTable 159 void SAL_CALL OHSQLTable::alterColumnByName( const ::rtl::OUString& colName, const Reference< XPropertySet >& descriptor ) throw(SQLException, NoSuchElementException, RuntimeException) 160 { 161 ::osl::MutexGuard aGuard(m_aMutex); 162 checkDisposed( 163 #ifdef GCC 164 ::connectivity::sdbcx::OTableDescriptor_BASE::rBHelper.bDisposed 165 #else 166 rBHelper.bDisposed 167 #endif 168 ); 169 170 if ( m_pColumns && !m_pColumns->hasByName(colName) ) 171 throw NoSuchElementException(colName,*this); 172 173 174 if ( !isNew() ) 175 { 176 // first we have to check what should be altered 177 Reference<XPropertySet> xProp; 178 m_pColumns->getByName(colName) >>= xProp; 179 // first check the types 180 sal_Int32 nOldType = 0,nNewType = 0,nOldPrec = 0,nNewPrec = 0,nOldScale = 0,nNewScale = 0; 181 ::rtl::OUString sOldTypeName, sNewTypeName; 182 183 ::dbtools::OPropertyMap& rProp = OMetaConnection::getPropMap(); 184 185 // type/typename 186 xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_TYPE)) >>= nOldType; 187 descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_TYPE)) >>= nNewType; 188 xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_TYPENAME)) >>= sOldTypeName; 189 descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_TYPENAME))>>= sNewTypeName; 190 191 // and precsions and scale 192 xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_PRECISION)) >>= nOldPrec; 193 descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_PRECISION))>>= nNewPrec; 194 xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_SCALE)) >>= nOldScale; 195 descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_SCALE)) >>= nNewScale; 196 197 // second: check the "is nullable" value 198 sal_Int32 nOldNullable = 0,nNewNullable = 0; 199 xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_ISNULLABLE)) >>= nOldNullable; 200 descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_ISNULLABLE)) >>= nNewNullable; 201 202 // check also the auto_increment 203 sal_Bool bOldAutoIncrement = sal_False,bAutoIncrement = sal_False; 204 xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_ISAUTOINCREMENT)) >>= bOldAutoIncrement; 205 descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_ISAUTOINCREMENT)) >>= bAutoIncrement; 206 207 // now we should look if the name of the column changed 208 ::rtl::OUString sNewColumnName; 209 descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_NAME)) >>= sNewColumnName; 210 if ( !sNewColumnName.equals(colName) ) 211 { 212 const ::rtl::OUString sQuote = getMetaData()->getIdentifierQuoteString( ); 213 214 ::rtl::OUString sSql = getAlterTableColumnPart(); 215 sSql += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" ALTER COLUMN ")); 216 sSql += ::dbtools::quoteName(sQuote,colName); 217 218 sSql += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" RENAME TO ")); 219 sSql += ::dbtools::quoteName(sQuote,sNewColumnName); 220 221 executeStatement(sSql); 222 } 223 224 if ( nOldType != nNewType 225 || sOldTypeName != sNewTypeName 226 || nOldPrec != nNewPrec 227 || nOldScale != nNewScale 228 || nNewNullable != nOldNullable 229 || bOldAutoIncrement != bAutoIncrement ) 230 { 231 // special handling because they change the type names to distinguish 232 // if a column should be an auto_incmrement one 233 if ( bOldAutoIncrement != bAutoIncrement ) 234 { 235 /// TODO: insert special handling for auto increment "IDENTITY" and primary key 236 } 237 alterColumnType(nNewType,sNewColumnName,descriptor); 238 } 239 240 // third: check the default values 241 ::rtl::OUString sNewDefault,sOldDefault; 242 xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_DEFAULTVALUE)) >>= sOldDefault; 243 descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_DEFAULTVALUE)) >>= sNewDefault; 244 245 if(sOldDefault.getLength()) 246 { 247 dropDefaultValue(colName); 248 if(sNewDefault.getLength() && sOldDefault != sNewDefault) 249 alterDefaultValue(sNewDefault,sNewColumnName); 250 } 251 else if(!sOldDefault.getLength() && sNewDefault.getLength()) 252 alterDefaultValue(sNewDefault,sNewColumnName); 253 254 m_pColumns->refresh(); 255 } 256 else 257 { 258 if(m_pColumns) 259 { 260 m_pColumns->dropByName(colName); 261 m_pColumns->appendByDescriptor(descriptor); 262 } 263 } 264 265 } 266 // ----------------------------------------------------------------------------- 267 void OHSQLTable::alterColumnType(sal_Int32 nNewType,const ::rtl::OUString& _rColName, const Reference<XPropertySet>& _xDescriptor) 268 { 269 ::rtl::OUString sSql = getAlterTableColumnPart(); 270 271 sSql += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" ALTER COLUMN ")); 272 #if OSL_DEBUG_LEVEL > 0 273 try 274 { 275 ::rtl::OUString sDescriptorName; 276 OSL_ENSURE( _xDescriptor.is() 277 && ( _xDescriptor->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_NAME ) ) >>= sDescriptorName ) 278 && ( sDescriptorName == _rColName ), 279 "OHSQLTable::alterColumnType: unexpected column name!" ); 280 } 281 catch( const Exception& ) 282 { 283 DBG_UNHANDLED_EXCEPTION(); 284 } 285 #else 286 (void)_rColName; 287 #endif 288 289 OHSQLColumn* pColumn = new OHSQLColumn(sal_True); 290 Reference<XPropertySet> xProp = pColumn; 291 ::comphelper::copyProperties(_xDescriptor,xProp); 292 xProp->setPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE),makeAny(nNewType)); 293 294 sSql += ::dbtools::createStandardColumnPart(xProp,getConnection()); 295 executeStatement(sSql); 296 } 297 // ----------------------------------------------------------------------------- 298 void OHSQLTable::alterDefaultValue(const ::rtl::OUString& _sNewDefault,const ::rtl::OUString& _rColName) 299 { 300 ::rtl::OUString sSql = getAlterTableColumnPart(); 301 sSql += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" ALTER COLUMN ")); 302 303 const ::rtl::OUString sQuote = getMetaData()->getIdentifierQuoteString( ); 304 sSql += ::dbtools::quoteName(sQuote,_rColName); 305 sSql += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" SET DEFAULT '")) + _sNewDefault; 306 sSql += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("'")); 307 308 executeStatement(sSql); 309 } 310 // ----------------------------------------------------------------------------- 311 void OHSQLTable::dropDefaultValue(const ::rtl::OUString& _rColName) 312 { 313 ::rtl::OUString sSql = getAlterTableColumnPart(); 314 sSql += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" ALTER COLUMN ")); 315 316 const ::rtl::OUString sQuote = getMetaData()->getIdentifierQuoteString( ); 317 sSql += ::dbtools::quoteName(sQuote,_rColName); 318 sSql += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" DROP DEFAULT")); 319 320 executeStatement(sSql); 321 } 322 // ----------------------------------------------------------------------------- 323 ::rtl::OUString OHSQLTable::getAlterTableColumnPart() 324 { 325 ::rtl::OUString sSql = ::rtl::OUString::createFromAscii("ALTER TABLE "); 326 const ::rtl::OUString sQuote = getMetaData()->getIdentifierQuoteString( ); 327 328 ::rtl::OUString sComposedName( ::dbtools::composeTableName( getMetaData(), m_CatalogName, m_SchemaName, m_Name, sal_True, ::dbtools::eInTableDefinitions ) ); 329 sSql += sComposedName; 330 331 return sSql; 332 } 333 // ----------------------------------------------------------------------------- 334 void OHSQLTable::executeStatement(const ::rtl::OUString& _rStatement ) 335 { 336 ::rtl::OUString sSQL = _rStatement; 337 if(sSQL.lastIndexOf(',') == (sSQL.getLength()-1)) 338 sSQL = sSQL.replaceAt(sSQL.getLength()-1,1,::rtl::OUString::createFromAscii(")")); 339 340 Reference< XStatement > xStmt = getConnection()->createStatement( ); 341 if ( xStmt.is() ) 342 { 343 try { xStmt->execute(sSQL); } 344 catch( const Exception& ) 345 { 346 ::comphelper::disposeComponent(xStmt); 347 throw; 348 } 349 ::comphelper::disposeComponent(xStmt); 350 } 351 } 352 // ----------------------------------------------------------------------------- 353 Sequence< Type > SAL_CALL OHSQLTable::getTypes( ) throw(RuntimeException) 354 { 355 if ( ! m_Type.compareToAscii("VIEW") ) 356 { 357 Sequence< Type > aTypes = OTableHelper::getTypes(); 358 ::std::vector<Type> aOwnTypes; 359 aOwnTypes.reserve(aTypes.getLength()); 360 const Type* pIter = aTypes.getConstArray(); 361 const Type* pEnd = pIter + aTypes.getLength(); 362 for(;pIter != pEnd;++pIter) 363 { 364 if( *pIter != ::getCppuType((const Reference<XRename>*)0) ) 365 { 366 aOwnTypes.push_back(*pIter); 367 } 368 } 369 Type *pTypes = aOwnTypes.empty() ? 0 : &aOwnTypes[0]; 370 return Sequence< Type >(pTypes, aOwnTypes.size()); 371 } 372 return OTableHelper::getTypes(); 373 } 374 // ------------------------------------------------------------------------- 375 // XRename 376 void SAL_CALL OHSQLTable::rename( const ::rtl::OUString& newName ) throw(SQLException, ElementExistException, RuntimeException) 377 { 378 ::osl::MutexGuard aGuard(m_aMutex); 379 checkDisposed( 380 #ifdef GCC 381 ::connectivity::sdbcx::OTableDescriptor_BASE::rBHelper.bDisposed 382 #else 383 rBHelper.bDisposed 384 #endif 385 ); 386 387 if(!isNew()) 388 { 389 ::rtl::OUString sSql = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ALTER ")); 390 if ( m_Type == ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("VIEW")) ) 391 sSql += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" VIEW ")); 392 else 393 sSql += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" TABLE ")); 394 395 ::rtl::OUString sQuote = getMetaData()->getIdentifierQuoteString( ); 396 397 ::rtl::OUString sCatalog,sSchema,sTable; 398 ::dbtools::qualifiedNameComponents(getMetaData(),newName,sCatalog,sSchema,sTable,::dbtools::eInDataManipulation); 399 400 ::rtl::OUString sComposedName( 401 ::dbtools::composeTableName( getMetaData(), m_CatalogName, m_SchemaName, m_Name, sal_True, ::dbtools::eInDataManipulation ) ); 402 sSql += sComposedName 403 + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" RENAME TO ")); 404 sSql += ::dbtools::composeTableName( getMetaData(), sCatalog, sSchema, sTable, sal_True, ::dbtools::eInDataManipulation ); 405 406 executeStatement(sSql); 407 408 ::connectivity::OTable_TYPEDEF::rename(newName); 409 } 410 else 411 ::dbtools::qualifiedNameComponents(getMetaData(),newName,m_CatalogName,m_SchemaName,m_Name,::dbtools::eInTableDefinitions); 412 } 413 414 // ------------------------------------------------------------------------- 415 Any SAL_CALL OHSQLTable::queryInterface( const Type & rType ) throw(RuntimeException) 416 { 417 if( !m_Type.compareToAscii("VIEW") && rType == ::getCppuType((const Reference<XRename>*)0) ) 418 return Any(); 419 420 return OTableHelper::queryInterface(rType); 421 } 422 // ------------------------------------------------------------------------- 423 424