Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include "Driver.hxx"
21 : #include "ResultSet.hxx"
22 : #include "StatementCommonBase.hxx"
23 : #include "Util.hxx"
24 :
25 : #include <comphelper/sequence.hxx>
26 : #include <cppuhelper/typeprovider.hxx>
27 : #include <propertyids.hxx>
28 : #include <TConnection.hxx>
29 :
30 : using namespace ::connectivity::firebird;
31 :
32 : using namespace ::com::sun::star;
33 : using namespace ::com::sun::star::uno;
34 : using namespace ::com::sun::star::lang;
35 : using namespace ::com::sun::star::beans;
36 : using namespace ::com::sun::star::sdbc;
37 : using namespace ::com::sun::star::sdbcx;
38 : using namespace ::com::sun::star::container;
39 : using namespace ::com::sun::star::io;
40 : using namespace ::com::sun::star::util;
41 :
42 : using namespace ::comphelper;
43 : using namespace ::osl;
44 : using namespace ::std;
45 :
46 22 : OStatementCommonBase::OStatementCommonBase(Connection* _pConnection)
47 : : OStatementCommonBase_Base(m_aMutex),
48 : OPropertySetHelper(OStatementCommonBase_Base::rBHelper),
49 : m_pConnection(_pConnection),
50 : m_aStatementHandle( 0 ),
51 22 : rBHelper(OStatementCommonBase_Base::rBHelper)
52 : {
53 22 : }
54 :
55 22 : OStatementCommonBase::~OStatementCommonBase()
56 : {
57 22 : }
58 :
59 64 : void OStatementCommonBase::disposeResultSet()
60 : {
61 64 : uno::Reference< XComponent > xComp(m_xResultSet.get(), UNO_QUERY);
62 64 : if (xComp.is())
63 18 : xComp->dispose();
64 64 : m_xResultSet = uno::Reference< XResultSet>();
65 64 : }
66 :
67 42 : void OStatementCommonBase::freeStatementHandle()
68 : throw (SQLException)
69 : {
70 42 : if (m_aStatementHandle)
71 : {
72 : isc_dsql_free_statement(m_statusVector,
73 : &m_aStatementHandle,
74 18 : DSQL_drop);
75 : evaluateStatusVector(m_statusVector,
76 : "isc_dsql_free_statement",
77 18 : *this);
78 : }
79 42 : }
80 :
81 :
82 70 : Any SAL_CALL OStatementCommonBase::queryInterface( const Type & rType ) throw(RuntimeException, std::exception)
83 : {
84 70 : Any aRet = OStatementCommonBase_Base::queryInterface(rType);
85 70 : if(!aRet.hasValue())
86 4 : aRet = OPropertySetHelper::queryInterface(rType);
87 70 : return aRet;
88 : }
89 :
90 0 : Sequence< Type > SAL_CALL OStatementCommonBase::getTypes( ) throw(RuntimeException, std::exception)
91 : {
92 : ::cppu::OTypeCollection aTypes(
93 0 : ::cppu::UnoType< uno::Reference< XMultiPropertySet > >::get(),
94 0 : ::cppu::UnoType< uno::Reference< XFastPropertySet > >::get(),
95 0 : ::cppu::UnoType< uno::Reference< XPropertySet > >::get());
96 :
97 0 : return concatSequences(aTypes.getTypes(),OStatementCommonBase_Base::getTypes());
98 : }
99 :
100 :
101 0 : void SAL_CALL OStatementCommonBase::cancel( ) throw(RuntimeException, std::exception)
102 : {
103 0 : MutexGuard aGuard(m_aMutex);
104 0 : checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed);
105 : // cancel the current sql statement
106 0 : }
107 :
108 24 : void SAL_CALL OStatementCommonBase::close()
109 : throw(SQLException, RuntimeException, std::exception)
110 : {
111 : SAL_INFO("connectivity.firebird", "close");
112 :
113 : {
114 24 : MutexGuard aGuard(m_aMutex);
115 24 : checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed);
116 24 : disposeResultSet();
117 24 : freeStatementHandle();
118 : }
119 :
120 24 : dispose();
121 24 : }
122 :
123 18 : void OStatementCommonBase::prepareAndDescribeStatement(const OUString& sql,
124 : XSQLDA*& pOutSqlda,
125 : XSQLDA* pInSqlda)
126 : throw (SQLException)
127 : {
128 18 : MutexGuard aGuard(m_aMutex);
129 :
130 18 : freeStatementHandle();
131 :
132 18 : if (!pOutSqlda)
133 : {
134 18 : pOutSqlda = (XSQLDA*) calloc(1, XSQLDA_LENGTH(10));
135 18 : pOutSqlda->version = SQLDA_VERSION1;
136 18 : pOutSqlda->sqln = 10;
137 : }
138 :
139 18 : ISC_STATUS aErr = 0;
140 :
141 : aErr = isc_dsql_allocate_statement(m_statusVector,
142 18 : &m_pConnection->getDBHandle(),
143 36 : &m_aStatementHandle);
144 :
145 18 : if (aErr)
146 : {
147 : evaluateStatusVector(m_statusVector,
148 : "isc_dsql_allocate_statement",
149 0 : *this);
150 : }
151 : else
152 : {
153 : aErr = isc_dsql_prepare(m_statusVector,
154 18 : &m_pConnection->getTransaction(),
155 : &m_aStatementHandle,
156 : 0,
157 : OUStringToOString(sql, RTL_TEXTENCODING_UTF8).getStr(),
158 : FIREBIRD_SQL_DIALECT,
159 36 : pInSqlda);
160 :
161 18 : if (aErr)
162 : {
163 : evaluateStatusVector(m_statusVector,
164 : "isc_dsql_prepare",
165 0 : *this);
166 : }
167 : else
168 : {
169 : aErr = isc_dsql_describe(m_statusVector,
170 : &m_aStatementHandle,
171 : 1,
172 18 : pOutSqlda);
173 :
174 18 : if (aErr)
175 : {
176 : // TODO: free statement handle, etc.?
177 : evaluateStatusVector(m_statusVector,
178 : "isc_dsql_describe",
179 0 : *this);
180 : }
181 : else
182 : {
183 : // Ensure we have enough space in pOutSqlda
184 18 : if (pOutSqlda->sqld > pOutSqlda->sqln)
185 : {
186 0 : int n = pOutSqlda->sqld;
187 0 : free(pOutSqlda);
188 0 : pOutSqlda = (XSQLDA*) calloc(1, XSQLDA_LENGTH(n));
189 0 : pOutSqlda->version = SQLDA_VERSION1;
190 0 : pOutSqlda->sqln = n;
191 : aErr = isc_dsql_describe(m_statusVector,
192 : &m_aStatementHandle,
193 : 1,
194 0 : pOutSqlda);
195 : }
196 :
197 : // Process each XSQLVAR parameter structure in the output XSQLDA
198 18 : if (aErr)
199 : {
200 : evaluateStatusVector(m_statusVector,
201 : "isc_dsql_describe",
202 0 : *this);
203 : }
204 : else
205 : {
206 18 : mallocSQLVAR(pOutSqlda);
207 : }
208 : }
209 : }
210 18 : if(aErr)
211 : {
212 0 : freeStatementHandle();
213 : }
214 : }
215 18 : if(aErr)
216 : {
217 0 : free(pOutSqlda);
218 0 : pOutSqlda = NULL;
219 18 : }
220 18 : }
221 :
222 : // ---- XMultipleResults - UNSUPPORTED ----------------------------------------
223 0 : uno::Reference< XResultSet > SAL_CALL OStatementCommonBase::getResultSet() throw(SQLException, RuntimeException, std::exception)
224 : {
225 : // TODO: verify we really can't support this
226 : // return uno::Reference< XResultSet >();
227 0 : MutexGuard aGuard(m_aMutex);
228 0 : checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed);
229 :
230 0 : return m_xResultSet;
231 : }
232 :
233 0 : sal_Bool SAL_CALL OStatementCommonBase::getMoreResults() throw(SQLException, RuntimeException, std::exception)
234 : {
235 : // TODO: verify we really can't support this
236 0 : return sal_False;
237 : // MutexGuard aGuard( m_aMutex );
238 : // checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed);
239 : }
240 :
241 0 : sal_Int32 SAL_CALL OStatementCommonBase::getUpdateCount() throw(SQLException, RuntimeException, std::exception)
242 : {
243 : // TODO: verify we really can't support this
244 0 : return 0;
245 : }
246 :
247 :
248 : // ---- XWarningsSupplier - UNSUPPORTED ----------------------------------------
249 0 : Any SAL_CALL OStatementCommonBase::getWarnings() throw(SQLException, RuntimeException, std::exception)
250 : {
251 0 : return Any();
252 : }
253 :
254 0 : void SAL_CALL OStatementCommonBase::clearWarnings() throw(SQLException, RuntimeException, std::exception)
255 : {
256 0 : }
257 :
258 2 : ::cppu::IPropertyArrayHelper* OStatementCommonBase::createArrayHelper( ) const
259 : {
260 : // this properties are define by the service statement
261 : // they must in alphabetic order
262 2 : Sequence< Property > aProps(10);
263 2 : Property* pProperties = aProps.getArray();
264 2 : sal_Int32 nPos = 0;
265 6 : pProperties[nPos++] = ::com::sun::star::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CURSORNAME),
266 4 : PROPERTY_ID_CURSORNAME, cppu::UnoType<OUString>::get(), 0);
267 6 : pProperties[nPos++] = ::com::sun::star::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ESCAPEPROCESSING),
268 4 : PROPERTY_ID_ESCAPEPROCESSING, ::getBooleanCppuType(), 0);
269 6 : pProperties[nPos++] = ::com::sun::star::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION),
270 4 : PROPERTY_ID_FETCHDIRECTION, cppu::UnoType<sal_Int32>::get(), 0);
271 6 : pProperties[nPos++] = ::com::sun::star::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE),
272 4 : PROPERTY_ID_FETCHSIZE, cppu::UnoType<sal_Int32>::get(), 0);
273 6 : pProperties[nPos++] = ::com::sun::star::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXFIELDSIZE),
274 4 : PROPERTY_ID_MAXFIELDSIZE, cppu::UnoType<sal_Int32>::get(), 0);
275 6 : pProperties[nPos++] = ::com::sun::star::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXROWS),
276 4 : PROPERTY_ID_MAXROWS, cppu::UnoType<sal_Int32>::get(), 0);
277 6 : pProperties[nPos++] = ::com::sun::star::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_QUERYTIMEOUT),
278 4 : PROPERTY_ID_QUERYTIMEOUT, cppu::UnoType<sal_Int32>::get(), 0);
279 6 : pProperties[nPos++] = ::com::sun::star::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY),
280 4 : PROPERTY_ID_RESULTSETCONCURRENCY, cppu::UnoType<sal_Int32>::get(), 0);
281 6 : pProperties[nPos++] = ::com::sun::star::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE),
282 4 : PROPERTY_ID_RESULTSETTYPE, cppu::UnoType<sal_Int32>::get(), 0);
283 6 : pProperties[nPos++] = ::com::sun::star::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_USEBOOKMARKS),
284 4 : PROPERTY_ID_USEBOOKMARKS, ::getBooleanCppuType(), 0);
285 :
286 2 : return new ::cppu::OPropertyArrayHelper(aProps);
287 : }
288 :
289 :
290 4 : ::cppu::IPropertyArrayHelper & OStatementCommonBase::getInfoHelper()
291 : {
292 4 : return *const_cast<OStatementCommonBase*>(this)->getArrayHelper();
293 : }
294 :
295 2 : sal_Bool OStatementCommonBase::convertFastPropertyValue(
296 : Any & rConvertedValue,
297 : Any & rOldValue,
298 : sal_Int32 nHandle,
299 : const Any& rValue )
300 : throw (IllegalArgumentException)
301 : {
302 : (void) rConvertedValue;
303 : (void) rOldValue;
304 : (void) nHandle;
305 : (void) rValue;
306 2 : bool bConverted = false;
307 : // here we have to try to convert
308 2 : return bConverted;
309 : }
310 :
311 0 : void OStatementCommonBase::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any& rValue) throw (Exception, std::exception)
312 : {
313 : (void) rValue;
314 : // set the value to what ever is necessary
315 : switch(nHandle)
316 : {
317 : case PROPERTY_ID_QUERYTIMEOUT:
318 : case PROPERTY_ID_MAXFIELDSIZE:
319 : case PROPERTY_ID_MAXROWS:
320 : case PROPERTY_ID_CURSORNAME:
321 : case PROPERTY_ID_RESULTSETCONCURRENCY:
322 : case PROPERTY_ID_RESULTSETTYPE:
323 : case PROPERTY_ID_FETCHDIRECTION:
324 : case PROPERTY_ID_FETCHSIZE:
325 : case PROPERTY_ID_ESCAPEPROCESSING:
326 : case PROPERTY_ID_USEBOOKMARKS:
327 : default:
328 : ;
329 : }
330 0 : }
331 :
332 0 : void OStatementCommonBase::getFastPropertyValue(Any& rValue,sal_Int32 nHandle) const
333 : {
334 : (void) rValue;
335 : switch(nHandle)
336 : {
337 : case PROPERTY_ID_QUERYTIMEOUT:
338 : case PROPERTY_ID_MAXFIELDSIZE:
339 : case PROPERTY_ID_MAXROWS:
340 : case PROPERTY_ID_CURSORNAME:
341 : case PROPERTY_ID_RESULTSETCONCURRENCY:
342 : case PROPERTY_ID_RESULTSETTYPE:
343 : case PROPERTY_ID_FETCHDIRECTION:
344 : case PROPERTY_ID_FETCHSIZE:
345 : case PROPERTY_ID_ESCAPEPROCESSING:
346 : case PROPERTY_ID_USEBOOKMARKS:
347 : default:
348 : ;
349 : }
350 0 : }
351 :
352 346 : void SAL_CALL OStatementCommonBase::acquire() throw()
353 : {
354 346 : OStatementCommonBase_Base::acquire();
355 346 : }
356 :
357 346 : void SAL_CALL OStatementCommonBase::release() throw()
358 : {
359 346 : OStatementCommonBase_Base::release();
360 346 : }
361 :
362 0 : uno::Reference< ::com::sun::star::beans::XPropertySetInfo > SAL_CALL OStatementCommonBase::getPropertySetInfo( ) throw(RuntimeException, std::exception)
363 : {
364 0 : return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
365 : }
366 :
367 36 : short OStatementCommonBase::getSqlInfoItem(char aInfoItem)
368 : throw (SQLException)
369 : {
370 : ISC_STATUS_ARRAY aStatusVector;
371 : ISC_STATUS aErr;
372 :
373 36 : char aInfoItems[] = {aInfoItem};
374 : char aResultsBuffer[8];
375 :
376 : aErr = isc_dsql_sql_info(aStatusVector,
377 : &m_aStatementHandle,
378 : sizeof(aInfoItems),
379 : aInfoItems,
380 : sizeof(aResultsBuffer),
381 36 : aResultsBuffer);
382 :
383 36 : if (!aErr && aResultsBuffer[0] == aInfoItem)
384 : {
385 36 : const short aBytes = (short) isc_vax_integer(aResultsBuffer+1, 2);
386 36 : return (short) isc_vax_integer(aResultsBuffer+3, aBytes);
387 : }
388 :
389 : evaluateStatusVector(aStatusVector,
390 : "isc_dsq_sql_info",
391 0 : *this);
392 0 : return 0;
393 : }
394 :
395 18 : bool OStatementCommonBase::isDDLStatement()
396 : throw (SQLException)
397 : {
398 18 : if (getSqlInfoItem(isc_info_sql_stmt_type) == isc_info_sql_stmt_ddl)
399 0 : return true;
400 : else
401 18 : return false;
402 : }
403 :
404 18 : sal_Int32 OStatementCommonBase::getStatementChangeCount()
405 : throw (SQLException)
406 : {
407 18 : const short aStatementType = getSqlInfoItem(isc_info_sql_stmt_type);
408 :
409 :
410 :
411 : ISC_STATUS_ARRAY aStatusVector;
412 : ISC_STATUS aErr;
413 :
414 : // This is somewhat undocumented so I'm just guessing and hoping for the best.
415 18 : char aInfoItems[] = {isc_info_sql_records};
416 : char aResultsBuffer[1024];
417 :
418 : aErr = isc_dsql_sql_info(aStatusVector,
419 : &m_aStatementHandle,
420 : sizeof(aInfoItems),
421 : aInfoItems,
422 : sizeof(aResultsBuffer),
423 18 : aResultsBuffer);
424 :
425 18 : if (aErr)
426 : {
427 : evaluateStatusVector(aStatusVector,
428 : "isc_dsq_sql_info",
429 0 : *this);
430 0 : return 0;
431 : }
432 :
433 18 : short aDesiredInfoType = 0;
434 18 : switch (aStatementType)
435 : {
436 : case isc_info_sql_stmt_select:
437 18 : aDesiredInfoType = isc_info_req_select_count;
438 18 : break;
439 : case isc_info_sql_stmt_insert:
440 0 : aDesiredInfoType = isc_info_req_insert_count;
441 0 : break;
442 : case isc_info_sql_stmt_update:
443 0 : aDesiredInfoType = isc_info_req_update_count;
444 0 : break;
445 : case isc_info_sql_stmt_delete:
446 0 : aDesiredInfoType = isc_info_req_delete_count;
447 0 : break;
448 : default:
449 0 : throw SQLException(); // TODO: better error message?
450 : }
451 :
452 18 : char* pResults = aResultsBuffer;
453 18 : if (((short) *pResults++) == isc_info_sql_records)
454 : {
455 : // const short aTotalLength = (short) isc_vax_integer(pResults, 2);
456 18 : pResults += 2;
457 :
458 : // Seems to be of form TOKEN (1 byte), LENGTH (2 bytes), DATA (LENGTH bytes)
459 72 : while (*pResults != isc_info_rsb_end)
460 : {
461 54 : const char aToken = *pResults;
462 54 : const short aLength = (short) isc_vax_integer(pResults+1, 2);
463 :
464 54 : if (aToken == aDesiredInfoType)
465 : {
466 18 : return sal_Int32(isc_vax_integer(pResults + 3, aLength));
467 : }
468 :
469 36 : pResults += (3 + aLength);
470 : }
471 : }
472 :
473 0 : return 0;
474 12 : }
475 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|