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