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 
31 #include "hsqldb/HView.hxx"
32 #include "hsqldb/HTools.hxx"
33 
34 #include "propertyids.hxx"
35 
36 #include "connectivity/dbexception.hxx"
37 #include "connectivity/dbtools.hxx"
38 
39 /** === begin UNO includes === **/
40 #include <com/sun/star/lang/WrappedTargetException.hpp>
41 #include <com/sun/star/lang/DisposedException.hpp>
42 #include <com/sun/star/sdbc/XRow.hpp>
43 /** === end UNO includes === **/
44 
45 #include <cppuhelper/exc_hlp.hxx>
46 #include <tools/diagnose_ex.h>
47 #include <unotools/sharedunocomponent.hxx>
48 
49 //........................................................................
50 namespace connectivity { namespace hsqldb
51 {
52 //........................................................................
53 
54 	/** === begin UNO using === **/
55 	using ::com::sun::star::uno::Reference;
56 	using ::com::sun::star::uno::UNO_QUERY;
57 	using ::com::sun::star::uno::UNO_QUERY_THROW;
58 	using ::com::sun::star::uno::Exception;
59 	using ::com::sun::star::uno::RuntimeException;
60 	using ::com::sun::star::uno::Any;
61 	using ::com::sun::star::uno::makeAny;
62     using ::com::sun::star::sdbc::XDatabaseMetaData;
63     using ::com::sun::star::sdbc::SQLException;
64     using ::com::sun::star::sdbc::XConnection;
65     using ::com::sun::star::lang::WrappedTargetException;
66     using ::com::sun::star::sdbc::XResultSet;
67     using ::com::sun::star::sdbc::XStatement;
68     using ::com::sun::star::lang::DisposedException;
69     using ::com::sun::star::sdbc::XRow;
70 	/** === end UNO using === **/
71 
72 	//====================================================================
73 	//= HView
74 	//====================================================================
75 	//--------------------------------------------------------------------
76     HView::HView( const Reference< XConnection >& _rxConnection, sal_Bool _bCaseSensitive,
77         const ::rtl::OUString& _rSchemaName, const ::rtl::OUString& _rName )
78         :HView_Base( _bCaseSensitive, _rName, _rxConnection->getMetaData(), 0, ::rtl::OUString(), _rSchemaName, ::rtl::OUString() )
79         ,m_xConnection( _rxConnection )
80     {
81     }
82 
83 	//--------------------------------------------------------------------
84     HView::~HView()
85     {
86     }
87 
88     //--------------------------------------------------------------------
89     IMPLEMENT_FORWARD_XINTERFACE2( HView, HView_Base, HView_IBASE )
90     IMPLEMENT_FORWARD_XTYPEPROVIDER2( HView, HView_Base, HView_IBASE )
91 
92     //--------------------------------------------------------------------
93     void SAL_CALL HView::alterCommand( const ::rtl::OUString& _rNewCommand ) throw (SQLException, RuntimeException)
94     {
95         // not really atomic ... as long as we do not have something like
96         //   ALTER VIEW <name> TO <command>
97         // in HSQL, we need to do it this way ...
98         //
99         // I can imagine scenarios where this fails, e.g. when dropping the view
100         // succeedes, re-creating it fails, some other thread alters a table which
101         // the view was based on, and then we try to restore the view with the
102         // original command, which then fails, too.
103         //
104         // However, there's not much chance to prevent this kind of errors without
105         // backend support.
106 
107         ::rtl::OUString sQualifiedName( ::dbtools::composeTableName(
108             m_xMetaData, m_CatalogName, m_SchemaName, m_Name, true, ::dbtools::eInDataManipulation ) );
109 
110         ::utl::SharedUNOComponent< XStatement > xStatement; xStatement.set( m_xConnection->createStatement(), UNO_QUERY_THROW );
111 
112         // create a statement which can be used to re-create the original view, in case
113         // dropping it succeeds, but creating it with a new statement fails
114         ::rtl::OUStringBuffer aRestoreCommand;
115         aRestoreCommand.appendAscii( "CREATE VIEW " );
116         aRestoreCommand.append     ( sQualifiedName );
117         aRestoreCommand.appendAscii( " AS " );
118         aRestoreCommand.append     ( impl_getCommand_throw( true ) );
119         ::rtl::OUString sRestoreCommand( aRestoreCommand.makeStringAndClear() );
120 
121         bool bDropSucceeded( false );
122         try
123         {
124             // drop the existing view
125             ::rtl::OUStringBuffer aCommand;
126             aCommand.appendAscii( "DROP VIEW " );
127             aCommand.append     ( sQualifiedName );
128             xStatement->execute( aCommand.makeStringAndClear() );
129             bDropSucceeded = true;
130 
131             // create a new one with the same name
132             aCommand.appendAscii( "CREATE VIEW " );
133             aCommand.append     ( sQualifiedName );
134             aCommand.appendAscii( " AS " );
135             aCommand.append     ( _rNewCommand );
136             xStatement->execute( aCommand.makeStringAndClear() );
137         }
138         catch( const SQLException& )
139         {
140             if ( bDropSucceeded )
141                 // drop succeeded, but creation failed -> re-create the view with the original
142                 // statemnet
143                 xStatement->execute( sRestoreCommand );
144             throw;
145         }
146         catch( const RuntimeException& )
147         {
148             if ( bDropSucceeded )
149                 xStatement->execute( sRestoreCommand );
150             throw;
151         }
152         catch( const Exception& )
153         {
154             if ( bDropSucceeded )
155                 xStatement->execute( sRestoreCommand );
156             DBG_UNHANDLED_EXCEPTION();
157         }
158     }
159 
160     //--------------------------------------------------------------------
161     void SAL_CALL HView::getFastPropertyValue( Any& _rValue, sal_Int32 _nHandle ) const
162     {
163         if ( _nHandle == PROPERTY_ID_COMMAND )
164         {
165             // retrieve the very current command, don't rely on the base classes cached value
166             // (which we initialized empty, anyway)
167             _rValue <<= impl_getCommand_throw( false );
168             return;
169         }
170 
171         HView_Base::getFastPropertyValue( _rValue, _nHandle );
172     }
173 
174     //--------------------------------------------------------------------
175     ::rtl::OUString HView::impl_getCommand_throw( bool _bAllowSQLException ) const
176     {
177         ::rtl::OUString sCommand;
178 
179         try
180         {
181             ::rtl::OUStringBuffer aCommand;
182             aCommand.appendAscii( "SELECT VIEW_DEFINITION FROM INFORMATION_SCHEMA.SYSTEM_VIEWS " );
183             HTools::appendTableFilterCrit( aCommand, m_CatalogName, m_SchemaName, m_Name, false );
184             ::utl::SharedUNOComponent< XStatement > xStatement; xStatement.set( m_xConnection->createStatement(), UNO_QUERY_THROW );
185             Reference< XResultSet > xResult( xStatement->executeQuery( aCommand.makeStringAndClear() ), UNO_QUERY_THROW );
186             if ( !xResult->next() )
187             {
188                 // hmm. There is no view view the name as we know it. Can only mean some other instance
189                 // dropped this view meanwhile ...
190                 throw DisposedException();
191             }
192 
193             Reference< XRow > xRow( xResult, UNO_QUERY_THROW );
194             sCommand = xRow->getString( 1 );
195         }
196         catch( const RuntimeException& ) { throw; }
197         catch( const SQLException& e )
198         {
199             if ( _bAllowSQLException )
200                 throw;
201             throw WrappedTargetException( e.Message, static_cast< XAlterView* >( const_cast< HView* >( this ) ), ::cppu::getCaughtException() );
202         }
203         catch( const Exception& )
204         {
205             DBG_UNHANDLED_EXCEPTION();
206         }
207 
208         return sCommand;
209     }
210 
211 //........................................................................
212 } } // namespace connectivity::hsqldb
213 //........................................................................
214