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
OHSQLTable(sdbcx::OCollection * _pTables,const Reference<XConnection> & _xConnection)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 // -------------------------------------------------------------------------
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)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 // -------------------------------------------------------------------------
construct()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 // -----------------------------------------------------------------------------
createArrayHelper(sal_Int32) const107 ::cppu::IPropertyArrayHelper* OHSQLTable::createArrayHelper( sal_Int32 /*_nId*/ ) const
108 {
109 return doCreateArrayHelper();
110 }
111 // -------------------------------------------------------------------------
getInfoHelper()112 ::cppu::IPropertyArrayHelper & OHSQLTable::getInfoHelper()
113 {
114 return *static_cast<OHSQLTable_PROP*>(const_cast<OHSQLTable*>(this))->getArrayHelper(isNew() ? 1 : 0);
115 }
116 // -----------------------------------------------------------------------------
createColumns(const TStringVector & _rNames)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 // -----------------------------------------------------------------------------
createKeys(const TStringVector & _rNames)124 sdbcx::OCollection* OHSQLTable::createKeys(const TStringVector& _rNames)
125 {
126 return new OKeysHelper(this,m_aMutex,_rNames);
127 }
128 // -----------------------------------------------------------------------------
createIndexes(const TStringVector & _rNames)129 sdbcx::OCollection* OHSQLTable::createIndexes(const TStringVector& _rNames)
130 {
131 return new OIndexesHelper(this,m_aMutex,_rNames);
132 }
133 //--------------------------------------------------------------------------
getUnoTunnelImplementationId()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 //------------------------------------------------------------------
getSomething(const Sequence<sal_Int8> & rId)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
alterColumnByName(const::rtl::OUString & colName,const Reference<XPropertySet> & descriptor)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 // -----------------------------------------------------------------------------
alterColumnType(sal_Int32 nNewType,const::rtl::OUString & _rColName,const Reference<XPropertySet> & _xDescriptor)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 // -----------------------------------------------------------------------------
alterDefaultValue(const::rtl::OUString & _sNewDefault,const::rtl::OUString & _rColName)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 // -----------------------------------------------------------------------------
dropDefaultValue(const::rtl::OUString & _rColName)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 // -----------------------------------------------------------------------------
getAlterTableColumnPart()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 // -----------------------------------------------------------------------------
executeStatement(const::rtl::OUString & _rStatement)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 // -----------------------------------------------------------------------------
getTypes()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
rename(const::rtl::OUString & newName)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 // -------------------------------------------------------------------------
queryInterface(const Type & rType)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