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 <connectivity/statementcomposer.hxx>
27  
28  #include <connectivity/dbtools.hxx>
29  
30  /** === begin UNO includes === **/
31  #include <com/sun/star/sdb/CommandType.hpp>
32  #include <com/sun/star/lang/NullPointerException.hpp>
33  #include <com/sun/star/lang/XComponent.hpp>
34  #include <com/sun/star/sdb/XQueriesSupplier.hpp>
35  #include <com/sun/star/lang/XMultiServiceFactory.hpp>
36  /** === end UNO includes === **/
37  
38  #include <unotools/sharedunocomponent.hxx>
39  #include <tools/diagnose_ex.h>
40  #include <comphelper/property.hxx>
41  
42  //........................................................................
43  namespace dbtools
44  {
45  //........................................................................
46  
47  	/** === begin UNO using === **/
48      using ::com::sun::star::uno::Reference;
49      using ::com::sun::star::sdbc::XConnection;
50      using ::com::sun::star::sdb::XSingleSelectQueryComposer;
51      using ::com::sun::star::lang::NullPointerException;
52      using ::com::sun::star::uno::Exception;
53      using ::com::sun::star::lang::XComponent;
54      using ::com::sun::star::uno::UNO_QUERY_THROW;
55      using ::com::sun::star::sdb::XQueriesSupplier;
56      using ::com::sun::star::container::XNameAccess;
57      using ::com::sun::star::uno::UNO_QUERY;
58      using ::com::sun::star::beans::XPropertySet;
59      using ::com::sun::star::lang::XMultiServiceFactory;
60      using ::com::sun::star::sdbc::SQLException;
61  	/** === end UNO using === **/
62      namespace CommandType = ::com::sun::star::sdb::CommandType;
63  
64  	//====================================================================
65  	//= StatementComposer_Data
66  	//====================================================================
67      struct StatementComposer_Data
68      {
69          const Reference< XConnection >          xConnection;
70          Reference< XSingleSelectQueryComposer > xComposer;
71          ::rtl::OUString                         sCommand;
72          ::rtl::OUString                         sFilter;
73          ::rtl::OUString                         sOrder;
74          sal_Int32                               nCommandType;
75          sal_Bool                                bEscapeProcessing;
76          bool                                    bComposerDirty;
77          bool                                    bDisposeComposer;
78  
StatementComposer_Datadbtools::StatementComposer_Data79          StatementComposer_Data( const Reference< XConnection >& _rxConnection )
80              :xConnection( _rxConnection )
81              ,sCommand()
82              ,sFilter()
83              ,sOrder()
84              ,nCommandType( CommandType::COMMAND )
85              ,bEscapeProcessing( sal_True )
86              ,bComposerDirty( true )
87              ,bDisposeComposer( true )
88          {
89              if ( !_rxConnection.is() )
90                  throw NullPointerException();
91          }
92      };
93  
94  	//--------------------------------------------------------------------
95      namespace
96      {
97          //----------------------------------------------------------------
lcl_resetComposer(StatementComposer_Data & _rData)98          void    lcl_resetComposer( StatementComposer_Data& _rData )
99          {
100              if ( _rData.bDisposeComposer && _rData.xComposer.is() )
101              {
102                  try
103                  {
104                      Reference< XComponent > xComposerComponent( _rData.xComposer, UNO_QUERY_THROW );
105                      xComposerComponent->dispose();
106                  }
107                  catch( const Exception& )
108                  {
109          	        DBG_UNHANDLED_EXCEPTION();
110                  }
111              }
112              _rData.xComposer.clear();
113          }
114  
115          //----------------------------------------------------------------
lcl_ensureUpToDateComposer_nothrow(StatementComposer_Data & _rData)116          bool    lcl_ensureUpToDateComposer_nothrow( StatementComposer_Data& _rData )
117          {
118              if ( !_rData.bComposerDirty )
119                  return _rData.xComposer.is();
120              lcl_resetComposer( _rData );
121  
122              try
123              {
124                  ::rtl::OUString sStatement;
125                  switch ( _rData.nCommandType )
126  	            {
127  		            case CommandType::COMMAND:
128  			            if ( _rData.bEscapeProcessing )
129  				            sStatement = _rData.sCommand;
130  			            // (in case of no escape processing  we assume a not parseable statement)
131  			            break;
132  
133                      case CommandType::TABLE:
134  		            {
135  			            if ( !_rData.sCommand.getLength() )
136                              break;
137  
138  			            sStatement = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "SELECT * FROM " ) );
139  
140  	                    ::rtl::OUString sCatalog, sSchema, sTable;
141  	                    qualifiedNameComponents( _rData.xConnection->getMetaData(), _rData.sCommand, sCatalog, sSchema, sTable, eInDataManipulation );
142  
143                          sStatement += composeTableNameForSelect( _rData.xConnection, sCatalog, sSchema, sTable );
144  		            }
145  		            break;
146  
147  		            case CommandType::QUERY:
148  		            {
149  			            // ask the connection for the query
150  			            Reference< XQueriesSupplier > xSupplyQueries( _rData.xConnection, UNO_QUERY_THROW );
151  			            Reference< XNameAccess >      xQueries( xSupplyQueries->getQueries(), UNO_QUERY_THROW );
152  
153  			            if ( !xQueries->hasByName( _rData.sCommand ) )
154  				            break;
155  
156  			            Reference< XPropertySet > xQuery( xQueries->getByName( _rData.sCommand ), UNO_QUERY_THROW );
157  
158                          //  a native query ?
159                          sal_Bool bQueryEscapeProcessing = sal_False;
160                          xQuery->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "EscapeProcessing" ) ) ) >>= bQueryEscapeProcessing;
161  			            if ( !bQueryEscapeProcessing )
162  				            break;
163  
164  			            // the command used by the query
165  			            xQuery->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Command" ) ) ) >>= sStatement;
166                          if ( !sStatement.getLength() )
167                              break;
168  
169  			            // use a composer to build a statement from the query filter/order props
170                          Reference< XMultiServiceFactory > xFactory( _rData.xConnection, UNO_QUERY_THROW );
171                          ::utl::SharedUNOComponent< XSingleSelectQueryComposer > xComposer;
172                          xComposer.set(
173                              xFactory->createInstance( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.sdb.SingleSelectQueryComposer" ) ) ),
174                              UNO_QUERY_THROW
175                          );
176  
177                          // the "basic" statement
178  			            xComposer->setElementaryQuery( sStatement );
179  
180                          // the sort order
181                          const ::rtl::OUString sPropOrder( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Order" ) ) );
182                          if ( ::comphelper::hasProperty( sPropOrder, xQuery ) )
183                          {
184                              ::rtl::OUString sOrder;
185                              OSL_VERIFY( xQuery->getPropertyValue( sPropOrder ) >>= sOrder );
186  				            xComposer->setOrder( sOrder );
187                          }
188  
189                          // the filter
190  			            sal_Bool bApplyFilter = sal_True;
191  			            const ::rtl::OUString sPropApply = ::rtl::OUString::createFromAscii( "ApplyFilter" );
192                          if ( ::comphelper::hasProperty( sPropApply, xQuery ) )
193                          {
194                              OSL_VERIFY( xQuery->getPropertyValue( sPropApply ) >>= bApplyFilter );
195                          }
196  
197  			            if ( bApplyFilter )
198                          {
199                              ::rtl::OUString sFilter;
200                              OSL_VERIFY( xQuery->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Filter" ) ) ) >>= sFilter );
201                              xComposer->setFilter( sFilter );
202                          }
203  
204                          // the composed statement
205                          sStatement = xComposer->getQuery();
206  		            }
207  		            break;
208  
209                      default:
210  			            OSL_ENSURE(sal_False, "lcl_ensureUpToDateComposer_nothrow: no table, no query, no statement - what else ?!");
211  			            break;
212  	            }
213  
214  	            if ( sStatement.getLength() )
215  	            {
216  		            // create an composer
217                      Reference< XMultiServiceFactory > xFactory( _rData.xConnection, UNO_QUERY_THROW );
218                      Reference< XSingleSelectQueryComposer > xComposer( xFactory->createInstance( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.sdb.SingleSelectQueryComposer" ) ) ),
219                          UNO_QUERY_THROW );
220  			        xComposer->setElementaryQuery( sStatement );
221  
222  			        // append sort/filter
223  				    xComposer->setOrder( _rData.sOrder );
224  					xComposer->setFilter( _rData.sFilter );
225  
226                      sStatement = xComposer->getQuery();
227  
228                      _rData.xComposer = xComposer;
229                      _rData.bComposerDirty = false;
230  		        }
231              }
232              catch( const SQLException& )
233              {
234                  // allowed to leave here
235              }
236              catch( const Exception& )
237              {
238              	DBG_UNHANDLED_EXCEPTION();
239              }
240  
241              return _rData.xComposer.is();
242          }
243      }
244  
245  	//====================================================================
246  	//= StatementComposer
247  	//====================================================================
248  	//--------------------------------------------------------------------
StatementComposer(const Reference<XConnection> & _rxConnection,const::rtl::OUString & _rCommand,const sal_Int32 _nCommandType,const sal_Bool _bEscapeProcessing)249      StatementComposer::StatementComposer( const Reference< XConnection >& _rxConnection,
250          const ::rtl::OUString&  _rCommand, const sal_Int32 _nCommandType, const sal_Bool _bEscapeProcessing )
251          :m_pData( new StatementComposer_Data( _rxConnection ) )
252      {
253          OSL_PRECOND( _rxConnection.is(), "StatementComposer::StatementComposer: illegal connection!" );
254          m_pData->sCommand = _rCommand;
255          m_pData->nCommandType = _nCommandType;
256          m_pData->bEscapeProcessing = _bEscapeProcessing;
257      }
258  
259  	//--------------------------------------------------------------------
~StatementComposer()260      StatementComposer::~StatementComposer()
261      {
262          lcl_resetComposer( *m_pData );
263      }
264  
265      //--------------------------------------------------------------------
setDisposeComposer(bool _bDoDispose)266      void StatementComposer::setDisposeComposer( bool _bDoDispose )
267      {
268          m_pData->bDisposeComposer = _bDoDispose;
269      }
270  
271      //--------------------------------------------------------------------
getDisposeComposer() const272      bool StatementComposer::getDisposeComposer() const
273      {
274          return m_pData->bDisposeComposer;
275      }
276  
277      //--------------------------------------------------------------------
setFilter(const::rtl::OUString & _rFilter)278      void StatementComposer::setFilter( const ::rtl::OUString& _rFilter )
279      {
280          m_pData->sFilter = _rFilter;
281          m_pData->bComposerDirty = true;
282      }
283  
284  	//--------------------------------------------------------------------
setOrder(const::rtl::OUString & _rOrder)285      void StatementComposer::setOrder( const ::rtl::OUString& _rOrder )
286      {
287          m_pData->sOrder = _rOrder;
288          m_pData->bComposerDirty = true;
289      }
290  
291  	//--------------------------------------------------------------------
getComposer()292      Reference< XSingleSelectQueryComposer > StatementComposer::getComposer()
293      {
294          lcl_ensureUpToDateComposer_nothrow( *m_pData );
295          return m_pData->xComposer;
296      }
297  
298  	//--------------------------------------------------------------------
getQuery()299      ::rtl::OUString StatementComposer::getQuery()
300      {
301          if ( lcl_ensureUpToDateComposer_nothrow( *m_pData ) )
302          {
303              return m_pData->xComposer->getQuery();
304          }
305  
306          return ::rtl::OUString();
307      }
308  
309  //........................................................................
310  } // namespace dbtools
311  //........................................................................
312