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