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