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 "adabas/BTable.hxx"
27 #include "adabas/BTables.hxx"
28 #include "adabas/BIndexes.hxx"
29 #include "adabas/BColumns.hxx"
30 #include "adabas/BKeys.hxx"
31 #include <com/sun/star/sdbc/XRow.hpp>
32 #include <com/sun/star/sdbc/XResultSet.hpp>
33 #include <com/sun/star/sdbcx/KeyType.hpp>
34 #include <com/sun/star/sdbc/KeyRule.hpp>
35 #include <cppuhelper/typeprovider.hxx>
36 #include <com/sun/star/lang/DisposedException.hpp>
37 #include <com/sun/star/sdbc/ColumnValue.hpp>
38 #include <comphelper/sequence.hxx>
39 #include <comphelper/extract.hxx>
40 #include <comphelper/types.hxx>
41 #include "connectivity/dbtools.hxx"
42 #include "adabas/BCatalog.hxx"
43 
44 
45 using namespace ::comphelper;
46 using namespace connectivity::adabas;
47 using namespace connectivity;
48 using namespace ::com::sun::star::uno;
49 using namespace ::com::sun::star::beans;
50 using namespace ::com::sun::star::sdbcx;
51 using namespace ::com::sun::star::sdbc;
52 using namespace ::com::sun::star::container;
53 using namespace ::com::sun::star::lang;
54 
OAdabasTable(sdbcx::OCollection * _pTables,OAdabasConnection * _pConnection)55 OAdabasTable::OAdabasTable(	sdbcx::OCollection* _pTables,
56 						   OAdabasConnection* _pConnection)
57 	:OTable_TYPEDEF(_pTables,_pConnection,sal_True)
58 	,m_pConnection(_pConnection)
59 {
60 	construct();
61 }
62 // -------------------------------------------------------------------------
OAdabasTable(sdbcx::OCollection * _pTables,OAdabasConnection * _pConnection,const::rtl::OUString & _Name,const::rtl::OUString & _Type,const::rtl::OUString & _Description,const::rtl::OUString & _SchemaName,const::rtl::OUString & _CatalogName)63 OAdabasTable::OAdabasTable(	sdbcx::OCollection* _pTables,
64 						   OAdabasConnection* _pConnection,
65 					const ::rtl::OUString& _Name,
66 					const ::rtl::OUString& _Type,
67 					const ::rtl::OUString& _Description ,
68 					const ::rtl::OUString& _SchemaName,
69 					const ::rtl::OUString& _CatalogName
70 				) : OTableHelper(	_pTables,
71 									_pConnection,
72 									sal_True,
73 									_Name,
74 									_Type,
75 									_Description,
76 									_SchemaName,
77 									_CatalogName)
78 				,m_pConnection(_pConnection)
79 {
80 	construct();
81 }
82 // -----------------------------------------------------------------------------
createColumns(const TStringVector & _rNames)83 sdbcx::OCollection* OAdabasTable::createColumns(const TStringVector& _rNames)
84 {
85 	return new OColumns(this,m_aMutex,_rNames);
86 }
87 // -----------------------------------------------------------------------------
createKeys(const TStringVector & _rNames)88 sdbcx::OCollection* OAdabasTable::createKeys(const TStringVector& _rNames)
89 {
90 	return new OKeys(this,m_aMutex,_rNames);
91 }
92 // -----------------------------------------------------------------------------
createIndexes(const TStringVector & _rNames)93 sdbcx::OCollection* OAdabasTable::createIndexes(const TStringVector& _rNames)
94 {
95 	return new OIndexes(this,m_aMutex,_rNames);
96 }
97 //--------------------------------------------------------------------------
getUnoTunnelImplementationId()98 Sequence< sal_Int8 > OAdabasTable::getUnoTunnelImplementationId()
99 {
100 	static ::cppu::OImplementationId * pId = 0;
101 	if (! pId)
102 	{
103 		::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
104 		if (! pId)
105 		{
106 			static ::cppu::OImplementationId aId;
107 			pId = &aId;
108 		}
109 	}
110 	return pId->getImplementationId();
111 }
112 
113 // com::sun::star::lang::XUnoTunnel
114 //------------------------------------------------------------------
getSomething(const Sequence<sal_Int8> & rId)115 sal_Int64 OAdabasTable::getSomething( const Sequence< sal_Int8 > & rId ) throw (RuntimeException)
116 {
117 	return (rId.getLength() == 16 && 0 == rtl_compareMemory(getUnoTunnelImplementationId().getConstArray(),  rId.getConstArray(), 16 ) )
118 				? reinterpret_cast< sal_Int64 >( this )
119 				: OTable_TYPEDEF::getSomething(rId);
120 }
121 // -------------------------------------------------------------------------
122 // XAlterTable
alterColumnByName(const::rtl::OUString & colName,const Reference<XPropertySet> & descriptor)123 void SAL_CALL OAdabasTable::alterColumnByName( const ::rtl::OUString& colName, const Reference< XPropertySet >& descriptor ) throw(SQLException, NoSuchElementException, RuntimeException)
124 {
125 	::osl::MutexGuard aGuard(m_aMutex);
126 	checkDisposed(
127 #ifdef GCC
128 		::connectivity::sdbcx::OTableDescriptor_BASE::rBHelper.bDisposed
129 #else
130 		rBHelper.bDisposed
131 #endif
132 		);
133 
134 	if(m_pColumns && !m_pColumns->hasByName(colName))
135 		throw NoSuchElementException(colName,*this);
136 
137 
138 	if(!isNew())
139 	{
140 		beginTransAction();
141 
142 		try
143 		{
144 			// first we have to check what should be altered
145 			Reference<XPropertySet> xProp;
146 			m_pColumns->getByName(colName) >>= xProp;
147 			// first check the types
148 			sal_Int32 nOldType = 0,nNewType = 0,nOldPrec = 0,nNewPrec = 0,nOldScale = 0,nNewScale = 0;
149 
150 			xProp->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE))			>>= nOldType;
151 			descriptor->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE))	>>= nNewType;
152 			// and precsions and scale
153 			xProp->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION))	>>= nOldPrec;
154 			descriptor->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION))>>= nNewPrec;
155 			xProp->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE))		>>= nOldScale;
156 			descriptor->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE))	>>= nNewScale;
157 
158 			if(nOldType != nNewType || nOldPrec != nNewPrec || nOldScale != nNewScale)
159 				alterColumnType(colName,descriptor);
160 
161 			// second: check the "is nullable" value
162 			sal_Int32 nOldNullable = 0,nNewNullable = 0;
163 			xProp->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISNULLABLE))		>>= nOldNullable;
164 			descriptor->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISNULLABLE))	>>= nNewNullable;
165 			if(nNewNullable != nOldNullable)
166 				alterNotNullValue(nNewNullable,colName);
167 
168 			// third: check the default values
169 			::rtl::OUString sNewDefault,sOldDefault;
170 			xProp->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DEFAULTVALUE))		>>= sOldDefault;
171 			descriptor->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DEFAULTVALUE)) >>= sNewDefault;
172 
173 			if(sOldDefault.getLength())
174 			{
175 				if(sNewDefault.getLength() && sOldDefault != sNewDefault)
176 					alterDefaultValue(sNewDefault,colName);
177 				else if(!sNewDefault.getLength())
178 					dropDefaultValue(colName);
179 			}
180 			else if(!sOldDefault.getLength() && sNewDefault.getLength())
181 				addDefaultValue(sNewDefault,colName);
182 
183 			// now we should look if the name of the column changed
184 			::rtl::OUString sNewColumnName;
185 			descriptor->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME)) >>= sNewColumnName;
186 			if(!sNewColumnName.equalsIgnoreAsciiCase(colName))
187 			{
188 				const ::rtl::OUString sQuote = m_pConnection->getMetaData()->getIdentifierQuoteString(  );
189 				const ::rtl::OUString& sDot = OAdabasCatalog::getDot();
190 
191 				::rtl::OUString sSql = ::rtl::OUString::createFromAscii("RENAME COLUMN ") ;
192 				sSql += ::dbtools::quoteName(sQuote,m_SchemaName) + sDot + ::dbtools::quoteName(sQuote,m_Name);
193 				sSql += sDot + ::dbtools::quoteName(sQuote,colName);
194 				sSql += ::rtl::OUString::createFromAscii(" TO ");
195 				sSql += ::dbtools::quoteName(sQuote,sNewColumnName);
196 
197 				Reference< XStatement > xStmt = m_pConnection->createStatement(  );
198 				if(xStmt.is())
199 				{
200 					xStmt->execute(sSql);
201 					::comphelper::disposeComponent(xStmt);
202 				}
203 			}
204 			m_pColumns->refresh();
205 		}
206 		catch(const SQLException&)
207 		{
208 			rollbackTransAction();
209 			throw;
210 		}
211 		endTransAction();
212 	}
213 	else
214 	{
215 		if(m_pColumns)
216 		{
217 			m_pColumns->dropByName(colName);
218 			m_pColumns->appendByDescriptor(descriptor);
219 		}
220 	}
221 
222 }
223 // -------------------------------------------------------------------------
getName()224 ::rtl::OUString SAL_CALL OAdabasTable::getName() throw(::com::sun::star::uno::RuntimeException)
225 {
226 	::rtl::OUString sName = m_SchemaName;
227 	if(m_SchemaName.getLength())
228 	{
229 		const ::rtl::OUString& sDot = OAdabasCatalog::getDot();
230 		sName += sDot;
231 	}
232 	sName += m_Name;
233 	return sName;
234 }
235 // -----------------------------------------------------------------------------
alterColumnType(const::rtl::OUString & _rColName,const Reference<XPropertySet> & _xDescriptor)236 void OAdabasTable::alterColumnType(const ::rtl::OUString& _rColName, const Reference<XPropertySet>& _xDescriptor)
237 {
238 	::rtl::OUString sSql = getAlterTableColumnPart(_rColName);
239 	sSql += ::rtl::OUString::createFromAscii(" ");
240 	sSql += OTables::getColumnSqlType(_xDescriptor);
241 
242 	Reference< XStatement > xStmt = m_pConnection->createStatement(  );
243 	if(xStmt.is())
244 	{
245 		xStmt->execute(sSql);
246 		::comphelper::disposeComponent(xStmt);
247 	}
248 }
249 // -----------------------------------------------------------------------------
alterNotNullValue(sal_Int32 _nNewNullable,const::rtl::OUString & _rColName)250 void OAdabasTable::alterNotNullValue(sal_Int32 _nNewNullable,const ::rtl::OUString& _rColName)
251 {
252 	::rtl::OUString sSql = getAlterTableColumnPart(_rColName);
253 
254 	if(_nNewNullable == ColumnValue::NO_NULLS)
255 	{
256 		sSql += ::rtl::OUString::createFromAscii(" NOT NULL");
257 	}
258 	else
259 	{
260 		sSql += ::rtl::OUString::createFromAscii(" DEFAULT NULL");
261 	}
262 
263 	Reference< XStatement > xStmt = m_pConnection->createStatement();
264 	if(xStmt.is())
265 	{
266 		xStmt->execute(sSql);
267 		::comphelper::disposeComponent(xStmt);
268 	}
269 }
270 // -----------------------------------------------------------------------------
alterDefaultValue(const::rtl::OUString & _sNewDefault,const::rtl::OUString & _rColName)271 void OAdabasTable::alterDefaultValue(const ::rtl::OUString& _sNewDefault,const ::rtl::OUString& _rColName)
272 {
273 	::rtl::OUString sSql = getAlterTableColumnPart(_rColName);
274 	sSql += ::rtl::OUString::createFromAscii(" ALTER ") + _sNewDefault;
275 
276 	Reference< XStatement > xStmt = m_pConnection->createStatement();
277 	if(xStmt.is())
278 	{
279 		xStmt->execute(sSql);
280 		::comphelper::disposeComponent(xStmt);
281 	}
282 }
283 // -----------------------------------------------------------------------------
dropDefaultValue(const::rtl::OUString & _rColName)284 void OAdabasTable::dropDefaultValue(const ::rtl::OUString& _rColName)
285 {
286 	::rtl::OUString sSql = getAlterTableColumnPart(_rColName);
287 	sSql += ::rtl::OUString::createFromAscii(" DROP DEFAULT");
288 
289 	Reference< XStatement > xStmt = m_pConnection->createStatement();
290 	if(xStmt.is())
291 	{
292 		xStmt->execute(sSql);
293 		::comphelper::disposeComponent(xStmt);
294 	}
295 }
296 // -----------------------------------------------------------------------------
addDefaultValue(const::rtl::OUString & _sNewDefault,const::rtl::OUString & _rColName)297 void OAdabasTable::addDefaultValue(const ::rtl::OUString& _sNewDefault,const ::rtl::OUString& _rColName)
298 {
299 	::rtl::OUString sSql = getAlterTableColumnPart(_rColName);
300 	sSql += ::rtl::OUString::createFromAscii(" ADD ") + _sNewDefault;
301 
302 	Reference< XStatement > xStmt = m_pConnection->createStatement();
303 	if(xStmt.is())
304 	{
305 		xStmt->execute(sSql);
306 		::comphelper::disposeComponent(xStmt);
307 	}
308 }
309 // -----------------------------------------------------------------------------
beginTransAction()310 void OAdabasTable::beginTransAction()
311 {
312 	try
313 	{
314 		Reference< XStatement > xStmt = m_pConnection->createStatement();
315 		if(xStmt.is())
316 		{
317 			xStmt->execute(::rtl::OUString::createFromAscii("SUBTRANS BEGIN") );
318 			::comphelper::disposeComponent(xStmt);
319 		}
320 	}
321 	catch(const Exception&)
322 	{
323 	}
324 }
325 // -----------------------------------------------------------------------------
endTransAction()326 void OAdabasTable::endTransAction()
327 {
328 	try
329 	{
330 		Reference< XStatement > xStmt = m_pConnection->createStatement();
331 		if(xStmt.is())
332 		{
333 			xStmt->execute(::rtl::OUString::createFromAscii("SUBTRANS END") );
334 			::comphelper::disposeComponent(xStmt);
335 		}
336 	}
337 	catch(const Exception&)
338 	{
339 	}
340 }
341 // -----------------------------------------------------------------------------
rollbackTransAction()342 void OAdabasTable::rollbackTransAction()
343 {
344 	try
345 	{
346 		Reference< XStatement > xStmt = m_pConnection->createStatement();
347 		if(xStmt.is())
348 		{
349 			xStmt->execute(::rtl::OUString::createFromAscii("SUBTRANS ROLLBACK") );
350 			::comphelper::disposeComponent(xStmt);
351 		}
352 	}
353 	catch(const Exception&)
354 	{
355 	}
356 }
357 // -----------------------------------------------------------------------------
getAlterTableColumnPart(const::rtl::OUString & _rsColumnName)358 ::rtl::OUString OAdabasTable::getAlterTableColumnPart(const ::rtl::OUString& _rsColumnName )
359 {
360 	::rtl::OUString sSql = ::rtl::OUString::createFromAscii("ALTER TABLE ");
361 	const ::rtl::OUString sQuote = m_pConnection->getMetaData()->getIdentifierQuoteString(  );
362 	const ::rtl::OUString& sDot = OAdabasCatalog::getDot();
363 
364 	sSql += ::dbtools::quoteName(sQuote,m_SchemaName) + sDot + ::dbtools::quoteName(sQuote,m_Name)
365 		 + ::rtl::OUString::createFromAscii(" COLUMN ")
366 		 + ::dbtools::quoteName(sQuote,_rsColumnName);
367 	return sSql;
368 }
369 // -----------------------------------------------------------------------------
370 
371 
372 
373