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