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