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