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
21 #include <osl/diagnose.h>
22 #include <odbc/OStatement.hxx>
23 #include <odbc/OConnection.hxx>
24 #include <odbc/OResultSet.hxx>
25 #include <comphelper/property.hxx>
26 #include <odbc/OTools.hxx>
27 #include <osl/thread.h>
28 #include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
29 #include <com/sun/star/sdbc/ResultSetType.hpp>
30 #include <com/sun/star/sdbc/FetchDirection.hpp>
31 #include <com/sun/star/lang/DisposedException.hpp>
32 #include <comphelper/sequence.hxx>
33 #include <cppuhelper/typeprovider.hxx>
34 #include <cppuhelper/queryinterface.hxx>
35 #include <comphelper/types.hxx>
36 #include <rtl/strbuf.hxx>
37 #include <algorithm>
38 #include <strings.hrc>
39 #include <connectivity/dbexception.hxx>
40
41 using namespace ::comphelper;
42
43 #define THROW_SQL(x) \
44 OTools::ThrowException(m_pConnection.get(),x,m_aStatementHandle,SQL_HANDLE_STMT,*this)
45
46
47 using namespace connectivity::odbc;
48
49 using namespace com::sun::star::uno;
50 using namespace com::sun::star::lang;
51 using namespace com::sun::star::beans;
52 using namespace com::sun::star::sdbc;
53 using namespace com::sun::star::sdbcx;
54 using namespace com::sun::star::container;
55 using namespace com::sun::star::io;
56 using namespace com::sun::star::util;
57
OStatement_Base(OConnection * _pConnection)58 OStatement_Base::OStatement_Base(OConnection* _pConnection )
59 :OStatement_BASE(m_aMutex)
60 ,OPropertySetHelper(OStatement_BASE::rBHelper)
61 ,m_pConnection(_pConnection)
62 ,m_aStatementHandle(SQL_NULL_HANDLE)
63 ,m_pRowStatusArray(nullptr)
64 {
65 osl_atomic_increment( &m_refCount );
66 m_aStatementHandle = m_pConnection->createStatementHandle();
67
68 //setMaxFieldSize(0);
69 // Don't do this. By ODBC spec, "0" is the default for the SQL_ATTR_MAX_LENGTH attribute. We once introduced
70 // this line since a PostgreSQL ODBC driver had a default other than 0. However, current drivers (at least 8.3
71 // and later) have a proper default of 0, so there should be no need anymore.
72 // On the other hand, the NotesSQL driver (IBM's ODBC driver for the Lotus Notes series) wrongly interprets
73 // "0" as "0", whereas the ODBC spec says it should in fact mean "unlimited".
74 // So, removing this line seems to be the best option for now.
75 // If we ever again encounter an ODBC driver which needs this option, then we should introduce a data source
76 // setting for it, instead of unconditionally doing it.
77
78 osl_atomic_decrement( &m_refCount );
79 }
80
~OStatement_Base()81 OStatement_Base::~OStatement_Base()
82 {
83 OSL_ENSURE(!m_aStatementHandle,"Sohould ne null here!");
84 }
85
disposeResultSet()86 void OStatement_Base::disposeResultSet()
87 {
88 // free the cursor if alive
89 Reference< XComponent > xComp(m_xResultSet.get(), UNO_QUERY);
90 if (xComp.is())
91 xComp->dispose();
92 m_xResultSet.clear();
93 }
94
disposing()95 void SAL_CALL OStatement_Base::disposing()
96 {
97 ::osl::MutexGuard aGuard(m_aMutex);
98
99 disposeResultSet();
100 ::comphelper::disposeComponent(m_xGeneratedStatement);
101
102 OSL_ENSURE(m_aStatementHandle,"OStatement_BASE2::disposing: StatementHandle is null!");
103 if (m_pConnection.is())
104 {
105 m_pConnection->freeStatementHandle(m_aStatementHandle);
106 m_pConnection.clear();
107 }
108 OSL_ENSURE(!m_aStatementHandle,"Sohould ne null here!");
109
110 OStatement_BASE::disposing();
111 }
112
disposing()113 void OStatement_BASE2::disposing()
114 {
115 ::osl::MutexGuard aGuard1(m_aMutex);
116 OStatement_Base::disposing();
117 }
118
queryInterface(const Type & rType)119 Any SAL_CALL OStatement_Base::queryInterface( const Type & rType )
120 {
121 if ( m_pConnection.is() && !m_pConnection->isAutoRetrievingEnabled() && rType == cppu::UnoType<XGeneratedResultSet>::get())
122 return Any();
123 Any aRet = OStatement_BASE::queryInterface(rType);
124 return aRet.hasValue() ? aRet : OPropertySetHelper::queryInterface(rType);
125 }
126
getTypes()127 Sequence< Type > SAL_CALL OStatement_Base::getTypes( )
128 {
129 ::cppu::OTypeCollection aTypes( cppu::UnoType<XMultiPropertySet>::get(),
130 cppu::UnoType<XFastPropertySet>::get(),
131 cppu::UnoType<XPropertySet>::get());
132 Sequence< Type > aOldTypes = OStatement_BASE::getTypes();
133 if ( m_pConnection.is() && !m_pConnection->isAutoRetrievingEnabled() )
134 {
135 auto newEnd = std::remove(aOldTypes.begin(), aOldTypes.end(),
136 cppu::UnoType<XGeneratedResultSet>::get());
137 aOldTypes.realloc(std::distance(aOldTypes.begin(), newEnd));
138 }
139
140 return ::comphelper::concatSequences(aTypes.getTypes(),aOldTypes);
141 }
142
getGeneratedValues()143 Reference< XResultSet > SAL_CALL OStatement_Base::getGeneratedValues( )
144 {
145 OSL_ENSURE( m_pConnection.is() && m_pConnection->isAutoRetrievingEnabled(),"Illegal call here. isAutoRetrievingEnabled is false!");
146 Reference< XResultSet > xRes;
147 if ( m_pConnection.is() )
148 {
149 OUString sStmt = m_pConnection->getTransformedGeneratedStatement(m_sSqlStatement);
150 if ( !sStmt.isEmpty() )
151 {
152 ::comphelper::disposeComponent(m_xGeneratedStatement);
153 m_xGeneratedStatement = m_pConnection->createStatement();
154 xRes = m_xGeneratedStatement->executeQuery(sStmt);
155 }
156 }
157 return xRes;
158 }
159
cancel()160 void SAL_CALL OStatement_Base::cancel( )
161 {
162 ::osl::MutexGuard aGuard( m_aMutex );
163 checkDisposed(OStatement_BASE::rBHelper.bDisposed);
164
165 OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
166 N3SQLCancel(m_aStatementHandle);
167 }
168
169
close()170 void SAL_CALL OStatement_Base::close( )
171 {
172 {
173 ::osl::MutexGuard aGuard( m_aMutex );
174 checkDisposed(OStatement_BASE::rBHelper.bDisposed);
175
176 }
177 dispose();
178 }
179
180
clearBatch()181 void SAL_CALL OStatement::clearBatch( )
182 {
183
184 }
185
reset()186 void OStatement_Base::reset()
187 {
188 ::osl::MutexGuard aGuard( m_aMutex );
189 checkDisposed(OStatement_BASE::rBHelper.bDisposed);
190
191
192 clearWarnings ();
193
194 if (m_xResultSet.get().is())
195 {
196 clearMyResultSet();
197 }
198 if(m_aStatementHandle)
199 {
200 THROW_SQL(N3SQLFreeStmt(m_aStatementHandle, SQL_CLOSE));
201 }
202 }
203
204 // clearMyResultSet
205 // If a ResultSet was created for this Statement, close it
clearMyResultSet()206 void OStatement_Base::clearMyResultSet()
207 {
208 ::osl::MutexGuard aGuard( m_aMutex );
209 checkDisposed(OStatement_BASE::rBHelper.bDisposed);
210
211 try
212 {
213 Reference<XCloseable> xCloseable(
214 m_xResultSet.get(), css::uno::UNO_QUERY);
215 if ( xCloseable.is() )
216 xCloseable->close();
217 }
218 catch( const DisposedException& ) { }
219
220 m_xResultSet.clear();
221 }
222
getRowCount()223 SQLLEN OStatement_Base::getRowCount()
224 {
225 ::osl::MutexGuard aGuard( m_aMutex );
226 checkDisposed(OStatement_BASE::rBHelper.bDisposed);
227
228
229 SQLLEN numRows = 0;
230
231 try {
232 THROW_SQL(N3SQLRowCount(m_aStatementHandle,&numRows));
233 }
234 catch (const SQLException&)
235 {
236 }
237 return numRows;
238 }
239
240 // lockIfNecessary
241 // If the given SQL statement contains a 'FOR UPDATE' clause, change
242 // the concurrency to lock so that the row can then be updated. Returns
243 // true if the concurrency has been changed
lockIfNecessary(const OUString & sql)244 bool OStatement_Base::lockIfNecessary (const OUString& sql)
245 {
246 bool rc = false;
247
248 // First, convert the statement to upper case
249
250 OUString sqlStatement = sql.toAsciiUpperCase ();
251
252 // Now, look for the FOR UPDATE keywords. If there is any extra white
253 // space between the FOR and UPDATE, this will fail.
254
255 sal_Int32 index = sqlStatement.indexOf(" FOR UPDATE");
256
257 // We found it. Change our concurrency level to ensure that the
258 // row can be updated.
259
260 if (index > 0)
261 {
262 OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
263 try
264 {
265 THROW_SQL((setStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_CONCURRENCY, SQL_CONCUR_LOCK)));
266 }
267 catch (const SQLWarning& warn)
268 {
269 // Catch any warnings and place on the warning stack
270 setWarning (warn);
271 }
272 rc = true;
273 }
274
275 return rc;
276 }
277
278 // setWarning
279 // Sets the warning
280
281
setWarning(const SQLWarning & ex)282 void OStatement_Base::setWarning (const SQLWarning &ex)
283 {
284 ::osl::MutexGuard aGuard( m_aMutex );
285 checkDisposed(OStatement_BASE::rBHelper.bDisposed);
286
287
288 m_aLastWarning = ex;
289 }
290
291
292 // getColumnCount
293 // Return the number of columns in the ResultSet
getColumnCount()294 sal_Int32 OStatement_Base::getColumnCount()
295 {
296 ::osl::MutexGuard aGuard( m_aMutex );
297 checkDisposed(OStatement_BASE::rBHelper.bDisposed);
298
299
300 sal_Int16 numCols = 0;
301 OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
302
303 try {
304 THROW_SQL(N3SQLNumResultCols(m_aStatementHandle,&numCols));
305 }
306 catch (const SQLException&)
307 {
308 }
309 return numCols;
310 }
311
312
execute(const OUString & sql)313 sal_Bool SAL_CALL OStatement_Base::execute( const OUString& sql )
314 {
315 ::osl::MutexGuard aGuard( m_aMutex );
316 checkDisposed(OStatement_BASE::rBHelper.bDisposed);
317 m_sSqlStatement = sql;
318
319
320 OString aSql(OUStringToOString(sql,getOwnConnection()->getTextEncoding()));
321
322 bool hasResultSet = false;
323 SQLWarning aWarning;
324
325 // Reset the statement handle and warning
326
327 reset();
328
329 // Check for a 'FOR UPDATE' statement. If present, change
330 // the concurrency to lock
331
332 lockIfNecessary (sql);
333
334 // Call SQLExecDirect
335 OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
336
337 try {
338 THROW_SQL(N3SQLExecDirect(m_aStatementHandle, reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(aSql.getStr())), aSql.getLength()));
339 }
340 catch (const SQLWarning& ex) {
341
342 // Save pointer to warning and save with ResultSet
343 // object once it is created.
344
345 aWarning = ex;
346 }
347
348 // Now determine if there is a result set associated with
349 // the SQL statement that was executed. Get the column
350 // count, and if it is not zero, there is a result set.
351
352 if (getColumnCount () > 0)
353 {
354 hasResultSet = true;
355 }
356
357 return hasResultSet;
358 }
359
360 // getResultSet
361 // getResultSet returns the current result as a ResultSet. It
362 // returns NULL if the current result is not a ResultSet.
363
getResultSet(bool checkCount)364 Reference< XResultSet > OStatement_Base::getResultSet(bool checkCount)
365 {
366 ::osl::MutexGuard aGuard( m_aMutex );
367 checkDisposed(OStatement_BASE::rBHelper.bDisposed);
368
369
370 if (m_xResultSet.get().is()) // if resultset already retrieved,
371 {
372 // throw exception to avoid sequence error
373 ::dbtools::throwFunctionSequenceException(*this);
374 }
375
376 OResultSet* pRs = nullptr;
377 sal_Int32 numCols = 1;
378
379 // If we already know we have result columns, checkCount
380 // is false. This is an optimization to prevent unneeded
381 // calls to getColumnCount
382
383 if (checkCount)
384 numCols = getColumnCount ();
385
386 // Only return a result set if there are result columns
387
388 if (numCols > 0)
389 {
390 OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
391 pRs = createResulSet();
392 pRs->construct();
393
394 // Save a copy of our last result set
395 // Changed to save copy at getResultSet.
396 //m_xResultSet = rs;
397 }
398 else
399 clearMyResultSet ();
400
401 return pRs;
402 }
403
404 // getStmtOption
405 // Invoke SQLGetStmtOption with the given option.
406
407
408 template < typename T, SQLINTEGER BufferLength > T OStatement_Base::getStmtOption (SQLINTEGER fOption) const
409 {
410 T result (0);
411 OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
412 N3SQLGetStmtAttr(m_aStatementHandle, fOption, &result, BufferLength, nullptr);
413 return result;
414 }
setStmtOption(SQLINTEGER fOption,T value) const415 template < typename T, SQLINTEGER BufferLength > SQLRETURN OStatement_Base::setStmtOption (SQLINTEGER fOption, T value) const
416 {
417 OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
418 SQLPOINTER sv = reinterpret_cast<SQLPOINTER>(value);
419 return N3SQLSetStmtAttr(m_aStatementHandle, fOption, sv, BufferLength);
420 }
421
422
executeQuery(const OUString & sql)423 Reference< XResultSet > SAL_CALL OStatement_Base::executeQuery( const OUString& sql )
424 {
425 ::osl::MutexGuard aGuard( m_aMutex );
426 checkDisposed(OStatement_BASE::rBHelper.bDisposed);
427
428
429 Reference< XResultSet > xRS;
430
431 // Execute the statement. If execute returns true, a result
432 // set exists.
433
434 if (execute (sql))
435 {
436 xRS = getResultSet (false);
437 m_xResultSet = xRS;
438 }
439 else
440 {
441 // No ResultSet was produced. Raise an exception
442 m_pConnection->throwGenericSQLException(STR_NO_RESULTSET,*this);
443 }
444 return xRS;
445 }
446
447
getConnection()448 Reference< XConnection > SAL_CALL OStatement_Base::getConnection( )
449 {
450 ::osl::MutexGuard aGuard( m_aMutex );
451 checkDisposed(OStatement_BASE::rBHelper.bDisposed);
452
453 return Reference< XConnection >(m_pConnection.get());
454 }
455
456
queryInterface(const Type & rType)457 Any SAL_CALL OStatement::queryInterface( const Type & rType )
458 {
459 Any aRet = ::cppu::queryInterface(rType,static_cast< XBatchExecution*> (this));
460 return aRet.hasValue() ? aRet : OStatement_Base::queryInterface(rType);
461 }
462
463
addBatch(const OUString & sql)464 void SAL_CALL OStatement::addBatch( const OUString& sql )
465 {
466 ::osl::MutexGuard aGuard( m_aMutex );
467 checkDisposed(OStatement_BASE::rBHelper.bDisposed);
468
469
470 m_aBatchVector.push_back(sql);
471 }
472
executeBatch()473 Sequence< sal_Int32 > SAL_CALL OStatement::executeBatch( )
474 {
475 ::osl::MutexGuard aGuard( m_aMutex );
476 checkDisposed(OStatement_BASE::rBHelper.bDisposed);
477
478 OStringBuffer aBatchSql;
479 sal_Int32 nLen = m_aBatchVector.size();
480
481 for (auto const& elem : m_aBatchVector)
482 {
483 aBatchSql.append(OUStringToOString(elem,getOwnConnection()->getTextEncoding()));
484 aBatchSql.append(";");
485 }
486
487 OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
488 auto s = aBatchSql.makeStringAndClear();
489 THROW_SQL(N3SQLExecDirect(m_aStatementHandle, reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(s.getStr())), s.getLength()));
490
491 Sequence< sal_Int32 > aRet(nLen);
492 sal_Int32* pArray = aRet.getArray();
493 for(sal_Int32 j=0;j<nLen;++j)
494 {
495 SQLRETURN nError = N3SQLMoreResults(m_aStatementHandle);
496 if(nError == SQL_SUCCESS)
497 {
498 SQLLEN nRowCount=0;
499 N3SQLRowCount(m_aStatementHandle,&nRowCount);
500 pArray[j] = nRowCount;
501 }
502 }
503 return aRet;
504 }
505
506
executeUpdate(const OUString & sql)507 sal_Int32 SAL_CALL OStatement_Base::executeUpdate( const OUString& sql )
508 {
509 ::osl::MutexGuard aGuard( m_aMutex );
510 checkDisposed(OStatement_BASE::rBHelper.bDisposed);
511
512
513 sal_Int32 numRows = -1;
514
515 // Execute the statement. If execute returns false, a
516 // row count exists.
517
518 if (!execute (sql)) {
519 numRows = getUpdateCount();
520 }
521 else {
522
523 // No update count was produced (a ResultSet was). Raise
524 // an exception
525
526 ::connectivity::SharedResources aResources;
527 const OUString sError( aResources.getResourceString(STR_NO_ROWCOUNT));
528 throw SQLException (sError, *this,OUString(),0,Any());
529 }
530 return numRows;
531
532 }
533
534
getResultSet()535 Reference< XResultSet > SAL_CALL OStatement_Base::getResultSet( )
536 {
537 ::osl::MutexGuard aGuard( m_aMutex );
538 checkDisposed(OStatement_BASE::rBHelper.bDisposed);
539
540
541 m_xResultSet = getResultSet(true);
542 return m_xResultSet;
543 }
544
545
getUpdateCount()546 sal_Int32 SAL_CALL OStatement_Base::getUpdateCount( )
547 {
548 ::osl::MutexGuard aGuard( m_aMutex );
549 checkDisposed(OStatement_BASE::rBHelper.bDisposed);
550
551
552 sal_Int32 rowCount = -1;
553
554 // Only return a row count for SQL statements that did not
555 // return a result set.
556
557 if (getColumnCount () == 0)
558 rowCount = getRowCount ();
559
560 return rowCount;
561 }
562
563
getMoreResults()564 sal_Bool SAL_CALL OStatement_Base::getMoreResults( )
565 {
566 ::osl::MutexGuard aGuard( m_aMutex );
567 checkDisposed(OStatement_BASE::rBHelper.bDisposed);
568
569
570 SQLWarning warning;
571 bool hasResultSet = false;
572
573 // clear previous warnings
574
575 clearWarnings ();
576
577 // Call SQLMoreResults
578 OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
579
580 try {
581 hasResultSet = N3SQLMoreResults(m_aStatementHandle) == SQL_SUCCESS;
582 }
583 catch (const SQLWarning &ex) {
584
585 // Save pointer to warning and save with ResultSet
586 // object once it is created.
587
588 warning = ex;
589 }
590
591 // There are more results (it may not be a result set, though)
592
593 if (hasResultSet)
594 {
595
596 // Now determine if there is a result set associated
597 // with the SQL statement that was executed. Get the
598 // column count, and if it is zero, there is not a
599 // result set.
600
601 if (getColumnCount () == 0)
602 hasResultSet = false;
603 }
604
605 // Set the warning for the statement, if one was generated
606
607 setWarning (warning);
608
609 // Return the result set indicator
610
611 return hasResultSet;
612 }
613
614
getWarnings()615 Any SAL_CALL OStatement_Base::getWarnings( )
616 {
617 ::osl::MutexGuard aGuard( m_aMutex );
618 checkDisposed(OStatement_BASE::rBHelper.bDisposed);
619
620
621 return makeAny(m_aLastWarning);
622 }
623
624
clearWarnings()625 void SAL_CALL OStatement_Base::clearWarnings( )
626 {
627 ::osl::MutexGuard aGuard( m_aMutex );
628 checkDisposed(OStatement_BASE::rBHelper.bDisposed);
629
630
631 m_aLastWarning = SQLWarning();
632 }
633
634
getQueryTimeOut() const635 sal_Int64 OStatement_Base::getQueryTimeOut() const
636 {
637 return getStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_QUERY_TIMEOUT);
638 }
639
getMaxRows() const640 sal_Int64 OStatement_Base::getMaxRows() const
641 {
642 return getStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_MAX_ROWS);
643 }
644
getResultSetConcurrency() const645 sal_Int32 OStatement_Base::getResultSetConcurrency() const
646 {
647 OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
648 SQLULEN nValue (getStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_CONCURRENCY));
649 if(nValue == SQL_CONCUR_READ_ONLY)
650 nValue = ResultSetConcurrency::READ_ONLY;
651 else
652 nValue = ResultSetConcurrency::UPDATABLE;
653 return nValue;
654 }
655
getResultSetType() const656 sal_Int32 OStatement_Base::getResultSetType() const
657 {
658 OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
659 SQLULEN nValue (getStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_CURSOR_TYPE));
660 switch(nValue)
661 {
662 case SQL_CURSOR_FORWARD_ONLY:
663 nValue = ResultSetType::FORWARD_ONLY;
664 break;
665 case SQL_CURSOR_KEYSET_DRIVEN:
666 case SQL_CURSOR_STATIC:
667 nValue = ResultSetType::SCROLL_INSENSITIVE;
668 break;
669 case SQL_CURSOR_DYNAMIC:
670 nValue = ResultSetType::SCROLL_SENSITIVE;
671 break;
672 default:
673 OSL_FAIL("Unknown ODBC Cursor Type");
674 }
675
676 return nValue;
677 }
678
getFetchDirection() const679 sal_Int32 OStatement_Base::getFetchDirection() const
680 {
681 OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
682 SQLULEN nValue (getStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_CURSOR_SCROLLABLE));
683 switch(nValue)
684 {
685 case SQL_SCROLLABLE:
686 nValue = FetchDirection::REVERSE;
687 break;
688 default:
689 nValue = FetchDirection::FORWARD;
690 break;
691 }
692
693 return nValue;
694 }
695
getFetchSize() const696 sal_Int32 OStatement_Base::getFetchSize() const
697 {
698 OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
699 return getStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_ROW_ARRAY_SIZE);
700 }
701
getMaxFieldSize() const702 sal_Int64 OStatement_Base::getMaxFieldSize() const
703 {
704 return getStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_MAX_LENGTH);
705 }
706
getCursorName() const707 OUString OStatement_Base::getCursorName() const
708 {
709 OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
710 SQLCHAR pName[258];
711 SQLSMALLINT nRealLen = 0;
712 N3SQLGetCursorName(m_aStatementHandle,pName,256,&nRealLen);
713 return OUString::createFromAscii(reinterpret_cast<char*>(pName));
714 }
715
setQueryTimeOut(sal_Int64 seconds)716 void OStatement_Base::setQueryTimeOut(sal_Int64 seconds)
717 {
718 OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
719 setStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_QUERY_TIMEOUT,seconds);
720 }
721
setMaxRows(sal_Int64 _par0)722 void OStatement_Base::setMaxRows(sal_Int64 _par0)
723 {
724 OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
725 setStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_MAX_ROWS, _par0);
726 }
727
setResultSetConcurrency(sal_Int32 _par0)728 void OStatement_Base::setResultSetConcurrency(sal_Int32 _par0)
729 {
730 SQLULEN nSet;
731 if(_par0 == ResultSetConcurrency::READ_ONLY)
732 nSet = SQL_CONCUR_READ_ONLY;
733 else
734 nSet = SQL_CONCUR_VALUES;
735
736 OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
737 setStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_CONCURRENCY, nSet);
738 }
739
setResultSetType(sal_Int32 _par0)740 void OStatement_Base::setResultSetType(sal_Int32 _par0)
741 {
742
743 OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
744 setStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_ROW_BIND_TYPE, SQL_BIND_BY_COLUMN);
745
746 bool bUseBookmark = isUsingBookmarks();
747 SQLULEN nSet( SQL_UNSPECIFIED );
748 switch(_par0)
749 {
750 case ResultSetType::FORWARD_ONLY:
751 nSet = SQL_UNSPECIFIED;
752 break;
753 case ResultSetType::SCROLL_INSENSITIVE:
754 nSet = SQL_INSENSITIVE;
755 setStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_CURSOR_TYPE, SQL_CURSOR_KEYSET_DRIVEN);
756 break;
757 case ResultSetType::SCROLL_SENSITIVE:
758 if(bUseBookmark)
759 {
760 SQLUINTEGER nCurProp = getCursorProperties(SQL_CURSOR_DYNAMIC,true);
761 if((nCurProp & SQL_CA1_BOOKMARK) != SQL_CA1_BOOKMARK) // check if bookmark for this type isn't supported
762 { // we have to test the next one
763 nCurProp = getCursorProperties(SQL_CURSOR_KEYSET_DRIVEN,true);
764 bool bNotBookmarks = ((nCurProp & SQL_CA1_BOOKMARK) != SQL_CA1_BOOKMARK);
765 nCurProp = getCursorProperties(SQL_CURSOR_KEYSET_DRIVEN,false);
766 nSet = SQL_CURSOR_KEYSET_DRIVEN;
767 if( bNotBookmarks ||
768 ((nCurProp & SQL_CA2_SENSITIVITY_DELETIONS) != SQL_CA2_SENSITIVITY_DELETIONS) ||
769 ((nCurProp & SQL_CA2_SENSITIVITY_ADDITIONS) != SQL_CA2_SENSITIVITY_ADDITIONS))
770 {
771 // bookmarks for keyset isn't supported so reset bookmark setting
772 setUsingBookmarks(false);
773 nSet = SQL_CURSOR_DYNAMIC;
774 }
775 }
776 else
777 nSet = SQL_CURSOR_DYNAMIC;
778 }
779 else
780 nSet = SQL_CURSOR_DYNAMIC;
781 if( setStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_CURSOR_TYPE, nSet) != SQL_SUCCESS )
782 {
783 setStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_CURSOR_TYPE, SQL_CURSOR_KEYSET_DRIVEN);
784 }
785 nSet = SQL_SENSITIVE;
786 break;
787 default:
788 OSL_FAIL( "OStatement_Base::setResultSetType: invalid result set type!" );
789 break;
790 }
791
792
793 setStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_CURSOR_SENSITIVITY, nSet);
794 }
795
setEscapeProcessing(const bool _bEscapeProc)796 void OStatement_Base::setEscapeProcessing( const bool _bEscapeProc )
797 {
798 OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
799 SQLULEN nEscapeProc( _bEscapeProc ? SQL_NOSCAN_OFF : SQL_NOSCAN_ON );
800 setStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_NOSCAN, nEscapeProc);
801 }
802
803
setFetchDirection(sal_Int32 _par0)804 void OStatement_Base::setFetchDirection(sal_Int32 _par0)
805 {
806 OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
807 if(_par0 == FetchDirection::FORWARD)
808 {
809 setStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_CURSOR_SCROLLABLE, SQL_NONSCROLLABLE);
810 }
811 else if(_par0 == FetchDirection::REVERSE)
812 {
813 setStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_CURSOR_SCROLLABLE, SQL_SCROLLABLE);
814 }
815 }
816
setFetchSize(sal_Int32 _par0)817 void OStatement_Base::setFetchSize(sal_Int32 _par0)
818 {
819 OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
820 OSL_ENSURE(_par0>0,"Illegal fetch size!");
821 if ( _par0 > 0 )
822 {
823 setStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_ROW_ARRAY_SIZE, _par0);
824
825 delete[] m_pRowStatusArray;
826 m_pRowStatusArray = new SQLUSMALLINT[_par0];
827 setStmtOption<SQLUSMALLINT*, SQL_IS_POINTER>(SQL_ATTR_ROW_STATUS_PTR, m_pRowStatusArray);
828 }
829 }
830
setMaxFieldSize(sal_Int64 _par0)831 void OStatement_Base::setMaxFieldSize(sal_Int64 _par0)
832 {
833 OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
834 setStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_MAX_LENGTH, _par0);
835 }
836
setCursorName(const OUString & _par0)837 void OStatement_Base::setCursorName(const OUString &_par0)
838 {
839 OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
840 OString aName(OUStringToOString(_par0,getOwnConnection()->getTextEncoding()));
841 N3SQLSetCursorName(m_aStatementHandle, reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(aName.getStr())), static_cast<SQLSMALLINT>(aName.getLength()));
842 }
843
isUsingBookmarks() const844 bool OStatement_Base::isUsingBookmarks() const
845 {
846 OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
847 return SQL_UB_OFF != getStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_USE_BOOKMARKS);
848 }
849
getEscapeProcessing() const850 bool OStatement_Base::getEscapeProcessing() const
851 {
852 OSL_ENSURE( m_aStatementHandle, "StatementHandle is null!" );
853 return SQL_NOSCAN_OFF == getStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_USE_BOOKMARKS);
854 }
855
setUsingBookmarks(bool _bUseBookmark)856 void OStatement_Base::setUsingBookmarks(bool _bUseBookmark)
857 {
858 OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
859 SQLULEN nValue = _bUseBookmark ? SQL_UB_VARIABLE : SQL_UB_OFF;
860 setStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_USE_BOOKMARKS, nValue);
861 }
862
createArrayHelper() const863 ::cppu::IPropertyArrayHelper* OStatement_Base::createArrayHelper( ) const
864 {
865 Sequence< Property > aProps(10);
866 Property* pProperties = aProps.getArray();
867 sal_Int32 nPos = 0;
868 pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CURSORNAME),
869 PROPERTY_ID_CURSORNAME, cppu::UnoType<OUString>::get(), 0);
870 pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ESCAPEPROCESSING),
871 PROPERTY_ID_ESCAPEPROCESSING, cppu::UnoType<bool>::get(), 0);
872 pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION),
873 PROPERTY_ID_FETCHDIRECTION, cppu::UnoType<sal_Int32>::get(), 0);
874 pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE),
875 PROPERTY_ID_FETCHSIZE, cppu::UnoType<sal_Int32>::get(), 0);
876 pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXFIELDSIZE),
877 PROPERTY_ID_MAXFIELDSIZE, cppu::UnoType<sal_Int32>::get(), 0);
878 pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXROWS),
879 PROPERTY_ID_MAXROWS, cppu::UnoType<sal_Int32>::get(), 0);
880 pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_QUERYTIMEOUT),
881 PROPERTY_ID_QUERYTIMEOUT, cppu::UnoType<sal_Int32>::get(), 0);
882 pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY),
883 PROPERTY_ID_RESULTSETCONCURRENCY, cppu::UnoType<sal_Int32>::get(), 0);
884 pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE),
885 PROPERTY_ID_RESULTSETTYPE, cppu::UnoType<sal_Int32>::get(), 0);
886 pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_USEBOOKMARKS),
887 PROPERTY_ID_USEBOOKMARKS, cppu::UnoType<bool>::get(), 0);
888
889 return new ::cppu::OPropertyArrayHelper(aProps);
890 }
891
892
getInfoHelper()893 ::cppu::IPropertyArrayHelper & OStatement_Base::getInfoHelper()
894 {
895 return *getArrayHelper();
896 }
897
convertFastPropertyValue(Any & rConvertedValue,Any & rOldValue,sal_Int32 nHandle,const Any & rValue)898 sal_Bool OStatement_Base::convertFastPropertyValue(
899 Any & rConvertedValue,
900 Any & rOldValue,
901 sal_Int32 nHandle,
902 const Any& rValue )
903 {
904 bool bConverted = false;
905 try
906 {
907 switch(nHandle)
908 {
909 case PROPERTY_ID_QUERYTIMEOUT:
910 bConverted = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getQueryTimeOut());
911 break;
912
913 case PROPERTY_ID_MAXFIELDSIZE:
914 bConverted = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getMaxFieldSize());
915 break;
916
917 case PROPERTY_ID_MAXROWS:
918 bConverted = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getMaxRows());
919 break;
920
921 case PROPERTY_ID_CURSORNAME:
922 bConverted = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getCursorName());
923 break;
924
925 case PROPERTY_ID_RESULTSETCONCURRENCY:
926 bConverted = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getResultSetConcurrency());
927 break;
928
929 case PROPERTY_ID_RESULTSETTYPE:
930 bConverted = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getResultSetType());
931 break;
932
933 case PROPERTY_ID_FETCHDIRECTION:
934 bConverted = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getFetchDirection());
935 break;
936
937 case PROPERTY_ID_FETCHSIZE:
938 bConverted = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getFetchSize());
939 break;
940
941 case PROPERTY_ID_USEBOOKMARKS:
942 bConverted = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, isUsingBookmarks());
943 break;
944
945 case PROPERTY_ID_ESCAPEPROCESSING:
946 bConverted = ::comphelper::tryPropertyValue( rConvertedValue, rOldValue, rValue, getEscapeProcessing() );
947 break;
948
949 }
950 }
951 catch(const SQLException&)
952 {
953 // throw Exception(e.Message,*this);
954 }
955 return bConverted;
956 }
957
setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any & rValue)958 void OStatement_Base::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any& rValue)
959 {
960 try
961 {
962 switch(nHandle)
963 {
964 case PROPERTY_ID_QUERYTIMEOUT:
965 setQueryTimeOut(comphelper::getINT64(rValue));
966 break;
967 case PROPERTY_ID_MAXFIELDSIZE:
968 setMaxFieldSize(comphelper::getINT64(rValue));
969 break;
970 case PROPERTY_ID_MAXROWS:
971 setMaxRows(comphelper::getINT64(rValue));
972 break;
973 case PROPERTY_ID_CURSORNAME:
974 setCursorName(comphelper::getString(rValue));
975 break;
976 case PROPERTY_ID_RESULTSETCONCURRENCY:
977 setResultSetConcurrency(comphelper::getINT32(rValue));
978 break;
979 case PROPERTY_ID_RESULTSETTYPE:
980 setResultSetType(comphelper::getINT32(rValue));
981 break;
982 case PROPERTY_ID_FETCHDIRECTION:
983 setFetchDirection(comphelper::getINT32(rValue));
984 break;
985 case PROPERTY_ID_FETCHSIZE:
986 setFetchSize(comphelper::getINT32(rValue));
987 break;
988 case PROPERTY_ID_USEBOOKMARKS:
989 setUsingBookmarks(comphelper::getBOOL(rValue));
990 break;
991 case PROPERTY_ID_ESCAPEPROCESSING:
992 setEscapeProcessing( ::comphelper::getBOOL( rValue ) );
993 break;
994 default:
995 OSL_FAIL( "OStatement_Base::setFastPropertyValue_NoBroadcast: what property?" );
996 break;
997 }
998 }
999 catch(const SQLException& )
1000 {
1001 // throw Exception(e.Message,*this);
1002 }
1003 }
1004
getFastPropertyValue(Any & rValue,sal_Int32 nHandle) const1005 void OStatement_Base::getFastPropertyValue(Any& rValue,sal_Int32 nHandle) const
1006 {
1007 switch(nHandle)
1008 {
1009 case PROPERTY_ID_QUERYTIMEOUT:
1010 rValue <<= getQueryTimeOut();
1011 break;
1012 case PROPERTY_ID_MAXFIELDSIZE:
1013 rValue <<= getMaxFieldSize();
1014 break;
1015 case PROPERTY_ID_MAXROWS:
1016 rValue <<= getMaxRows();
1017 break;
1018 case PROPERTY_ID_CURSORNAME:
1019 rValue <<= getCursorName();
1020 break;
1021 case PROPERTY_ID_RESULTSETCONCURRENCY:
1022 rValue <<= getResultSetConcurrency();
1023 break;
1024 case PROPERTY_ID_RESULTSETTYPE:
1025 rValue <<= getResultSetType();
1026 break;
1027 case PROPERTY_ID_FETCHDIRECTION:
1028 rValue <<= getFetchDirection();
1029 break;
1030 case PROPERTY_ID_FETCHSIZE:
1031 rValue <<= getFetchSize();
1032 break;
1033 case PROPERTY_ID_USEBOOKMARKS:
1034 rValue <<= isUsingBookmarks();
1035 break;
1036 case PROPERTY_ID_ESCAPEPROCESSING:
1037 rValue <<= getEscapeProcessing();
1038 break;
1039 default:
1040 OSL_FAIL( "OStatement_Base::getFastPropertyValue: what property?" );
1041 break;
1042 }
1043 }
1044
1045 IMPLEMENT_SERVICE_INFO(OStatement,"com.sun.star.sdbcx.OStatement","com.sun.star.sdbc.Statement");
1046
acquire()1047 void SAL_CALL OStatement_Base::acquire() throw()
1048 {
1049 OStatement_BASE::acquire();
1050 }
1051
release()1052 void SAL_CALL OStatement_Base::release() throw()
1053 {
1054 OStatement_BASE::release();
1055 }
1056
acquire()1057 void SAL_CALL OStatement::acquire() throw()
1058 {
1059 OStatement_BASE2::acquire();
1060 }
1061
release()1062 void SAL_CALL OStatement::release() throw()
1063 {
1064 OStatement_BASE2::release();
1065 }
1066
createResulSet()1067 OResultSet* OStatement_Base::createResulSet()
1068 {
1069 return new OResultSet(m_aStatementHandle,this);
1070 }
1071
getPropertySetInfo()1072 Reference< css::beans::XPropertySetInfo > SAL_CALL OStatement_Base::getPropertySetInfo( )
1073 {
1074 return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
1075 }
1076
getCursorProperties(SQLINTEGER _nCursorType,bool bFirst)1077 SQLUINTEGER OStatement_Base::getCursorProperties(SQLINTEGER _nCursorType, bool bFirst)
1078 {
1079 SQLUINTEGER nValueLen = 0;
1080 try
1081 {
1082 SQLUSMALLINT nAskFor = SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2;
1083 if(SQL_CURSOR_KEYSET_DRIVEN == _nCursorType)
1084 nAskFor = bFirst ? SQL_KEYSET_CURSOR_ATTRIBUTES1 : SQL_KEYSET_CURSOR_ATTRIBUTES2;
1085 else if(SQL_CURSOR_STATIC == _nCursorType)
1086 nAskFor = bFirst ? SQL_STATIC_CURSOR_ATTRIBUTES1 : SQL_STATIC_CURSOR_ATTRIBUTES2;
1087 else if(SQL_CURSOR_FORWARD_ONLY == _nCursorType)
1088 nAskFor = bFirst ? SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES1 : SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2;
1089 else if(SQL_CURSOR_DYNAMIC == _nCursorType)
1090 nAskFor = bFirst ? SQL_DYNAMIC_CURSOR_ATTRIBUTES1 : SQL_DYNAMIC_CURSOR_ATTRIBUTES2;
1091
1092
1093 OTools::GetInfo(getOwnConnection(),getConnectionHandle(),nAskFor,nValueLen,nullptr);
1094 }
1095 catch(const Exception&)
1096 { // we don't want our result destroy here
1097 nValueLen = 0;
1098 }
1099 return nValueLen;
1100 }
1101
1102
1103 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1104