xref: /core/connectivity/source/drivers/firebird/PreparedStatement.cxx (revision 1ef8ab3ed7930cec2569ee576a409c7a6bbb42e9)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include "Connection.hxx"
21 #include "PreparedStatement.hxx"
22 #include "ResultSet.hxx"
23 #include "ResultSetMetaData.hxx"
24 #include "Util.hxx"
25 
26 #include <comphelper/sequence.hxx>
27 #include <connectivity/dbexception.hxx>
28 #include <cppuhelper/typeprovider.hxx>
29 #include <osl/diagnose.h>
30 #include <propertyids.hxx>
31 #include <time.h>
32 #include <connectivity/dbtools.hxx>
33 
34 #include <com/sun/star/sdbc/DataType.hpp>
35 #include <com/sun/star/lang/DisposedException.hpp>
36 
37 using namespace connectivity::firebird;
38 
39 using namespace ::comphelper;
40 using namespace ::osl;
41 
42 using namespace com::sun::star;
43 using namespace com::sun::star::uno;
44 using namespace com::sun::star::lang;
45 using namespace com::sun::star::beans;
46 using namespace com::sun::star::sdbc;
47 using namespace com::sun::star::container;
48 using namespace com::sun::star::io;
49 using namespace com::sun::star::util;
50 
51 IMPLEMENT_SERVICE_INFO(OPreparedStatement,"com.sun.star.sdbcx.firebird.PreparedStatement","com.sun.star.sdbc.PreparedStatement");
52 
53 
54 OPreparedStatement::OPreparedStatement( Connection* _pConnection,
55                                         const OUString& sql)
56     :OStatementCommonBase(_pConnection)
57     ,m_sSqlStatement(sql)
58     ,m_pOutSqlda(nullptr)
59     ,m_pInSqlda(nullptr)
60     ,m_sTableName()
61 {
62     SAL_INFO("connectivity.firebird", "OPreparedStatement(). "
63              "sql: " << sql);
64 }
65 
66 void OPreparedStatement::ensurePrepared()
67     throw (SQLException, RuntimeException)
68 {
69     MutexGuard aGuard(m_aMutex);
70     checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed);
71 
72     if (m_aStatementHandle)
73         return;
74 
75     ISC_STATUS aErr = 0;
76 
77     if (!m_pInSqlda)
78     {
79         m_pInSqlda = static_cast<XSQLDA*>(calloc(1, XSQLDA_LENGTH(10)));
80         m_pInSqlda->version = SQLDA_VERSION1;
81         m_pInSqlda->sqln = 10;
82     }
83 
84     prepareAndDescribeStatement(m_sSqlStatement,
85                                m_pOutSqlda,
86                                m_pInSqlda);
87 
88     OStringVector vec;
89     tokenizeSQL( OUStringToOString(m_sSqlStatement, RTL_TEXTENCODING_UTF8), vec );
90     m_sTableName =
91             OStringToOUString(
92             extractSingleTableFromSelect( vec ), RTL_TEXTENCODING_UTF8);
93 
94     aErr = isc_dsql_describe_bind(m_statusVector,
95                                   &m_aStatementHandle,
96                                   1,
97                                   m_pInSqlda);
98 
99     if (aErr)
100     {
101         SAL_WARN("connectivity.firebird", "isc_dsql_describe_bind failed");
102     }
103     else if (m_pInSqlda->sqld > m_pInSqlda->sqln) // Not large enough
104     {
105         short nItems = m_pInSqlda->sqld;
106         free(m_pInSqlda);
107         m_pInSqlda = static_cast<XSQLDA*>(calloc(1, XSQLDA_LENGTH(nItems)));
108         m_pInSqlda->version = SQLDA_VERSION1;
109         m_pInSqlda->sqln = nItems;
110         aErr = isc_dsql_describe_bind(m_statusVector,
111                                       &m_aStatementHandle,
112                                       1,
113                                       m_pInSqlda);
114         SAL_WARN_IF(aErr, "connectivity.firebird", "isc_dsql_describe_bind failed");
115     }
116 
117     if (!aErr)
118         mallocSQLVAR(m_pInSqlda);
119     else
120         evaluateStatusVector(m_statusVector, m_sSqlStatement, *this);
121 }
122 
123 OPreparedStatement::~OPreparedStatement()
124 {
125 }
126 
127 void SAL_CALL OPreparedStatement::acquire() throw()
128 {
129     OStatementCommonBase::acquire();
130 }
131 
132 void SAL_CALL OPreparedStatement::release() throw()
133 {
134     OStatementCommonBase::release();
135 }
136 
137 Any SAL_CALL OPreparedStatement::queryInterface(const Type& rType)
138     throw(RuntimeException, std::exception)
139 {
140     Any aRet = OStatementCommonBase::queryInterface(rType);
141     if(!aRet.hasValue())
142         aRet = OPreparedStatement_Base::queryInterface(rType);
143     return aRet;
144 }
145 
146 uno::Sequence< Type > SAL_CALL OPreparedStatement::getTypes()
147     throw(RuntimeException, std::exception)
148 {
149     return concatSequences(OPreparedStatement_Base::getTypes(),
150                            OStatementCommonBase::getTypes());
151 }
152 
153 Reference< XResultSetMetaData > SAL_CALL OPreparedStatement::getMetaData()
154     throw(SQLException, RuntimeException, std::exception)
155 {
156     ::osl::MutexGuard aGuard( m_aMutex );
157     checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed);
158     ensurePrepared();
159 
160     if(!m_xMetaData.is())
161         m_xMetaData = new OResultSetMetaData(m_pConnection.get()
162                                            , m_pOutSqlda
163                                            , m_sTableName);
164 
165     return m_xMetaData;
166 }
167 
168 void SAL_CALL OPreparedStatement::close() throw(SQLException, RuntimeException, std::exception)
169 {
170     MutexGuard aGuard( m_aMutex );
171     checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed);
172 
173     OStatementCommonBase::close();
174     if (m_pInSqlda)
175     {
176         freeSQLVAR(m_pInSqlda);
177         free(m_pInSqlda);
178         m_pInSqlda = nullptr;
179     }
180     if (m_pOutSqlda)
181     {
182         freeSQLVAR(m_pOutSqlda);
183         free(m_pOutSqlda);
184         m_pOutSqlda = nullptr;
185     }
186 }
187 
188 void SAL_CALL OPreparedStatement::disposing()
189 {
190     close();
191 }
192 
193 void SAL_CALL OPreparedStatement::setString(sal_Int32 nParameterIndex,
194                                             const OUString& x)
195     throw(SQLException, RuntimeException, std::exception)
196 {
197     SAL_INFO("connectivity.firebird",
198              "setString(" << nParameterIndex << " , " << x << ")");
199 
200     MutexGuard aGuard( m_aMutex );
201     checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed);
202     ensurePrepared();
203 
204     checkParameterIndex(nParameterIndex);
205     setParameterNull(nParameterIndex, false);
206 
207     OString str = OUStringToOString(x , RTL_TEXTENCODING_UTF8 );
208 
209     XSQLVAR* pVar = m_pInSqlda->sqlvar + (nParameterIndex - 1);
210 
211     int dtype = (pVar->sqltype & ~1); // drop flag bit for now
212 
213     if (str.getLength() > pVar->sqllen)
214         str = str.copy(0, pVar->sqllen);
215 
216     switch (dtype) {
217     case SQL_VARYING:
218     {
219         const sal_Int32 max_varchar_len = 0xFFFF;
220         // First 2 bytes indicate string size
221         if (str.getLength() > max_varchar_len)
222         {
223             str = str.copy(0, max_varchar_len);
224         }
225         const short nLength = str.getLength();
226         memcpy(pVar->sqldata, &nLength, 2);
227         // Actual data
228         memcpy(pVar->sqldata + 2, str.getStr(), str.getLength());
229         break;
230     }
231     case SQL_TEXT:
232         memcpy(pVar->sqldata, str.getStr(), str.getLength());
233         // Fill remainder with spaces
234         memset(pVar->sqldata + str.getLength(), ' ', pVar->sqllen - str.getLength());
235         break;
236     default:
237         ::dbtools::throwSQLException(
238             "Incorrect type for setString",
239             ::dbtools::StandardSQLState::INVALID_SQL_DATA_TYPE,
240             *this);
241     }
242 }
243 
244 Reference< XConnection > SAL_CALL OPreparedStatement::getConnection()
245     throw(SQLException, RuntimeException, std::exception)
246 {
247     MutexGuard aGuard( m_aMutex );
248     checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed);
249 
250     return Reference<XConnection>(m_pConnection.get());
251 }
252 
253 sal_Bool SAL_CALL OPreparedStatement::execute()
254     throw(SQLException, RuntimeException, std::exception)
255 {
256     SAL_INFO("connectivity.firebird", "executeQuery(). "
257         "Got called with sql: " <<  m_sSqlStatement);
258 
259     MutexGuard aGuard( m_aMutex );
260     checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed);
261 
262     ensurePrepared();
263 
264     ISC_STATUS aErr;
265 
266     if (m_xResultSet.is()) // Checks whether we have already run the statement.
267     {
268         disposeResultSet();
269         // Closes the cursor from the last run.
270         // This doesn't actually free the statement -- using DSQL_close closes
271         // the cursor and keeps the statement, using DSQL_drop frees the statement
272         // (and associated cursors).
273         aErr = isc_dsql_free_statement(m_statusVector,
274                                        &m_aStatementHandle,
275                                        DSQL_close);
276         if (aErr)
277             evaluateStatusVector(m_statusVector,
278                                  "isc_dsql_free_statement: close cursor",
279                                  *this);
280     }
281 
282     aErr = isc_dsql_execute(m_statusVector,
283                                 &m_pConnection->getTransaction(),
284                                 &m_aStatementHandle,
285                                 1,
286                                 m_pInSqlda);
287     if (aErr)
288     {
289         SAL_WARN("connectivity.firebird", "isc_dsql_execute failed" );
290         evaluateStatusVector(m_statusVector, "isc_dsql_execute", *this);
291     }
292 
293     m_xResultSet = new OResultSet(m_pConnection.get(),
294                                   m_aMutex,
295                                   uno::Reference< XInterface >(*this),
296                                   m_aStatementHandle,
297                                   m_pOutSqlda,
298                                   m_sTableName);
299 
300     if (getStatementChangeCount() > 0)
301         m_pConnection->notifyDatabaseModified();
302 
303     return m_xResultSet.is();
304     // TODO: implement handling of multiple ResultSets.
305 }
306 
307 sal_Int32 SAL_CALL OPreparedStatement::executeUpdate()
308     throw(SQLException, RuntimeException, std::exception)
309 {
310     execute();
311     return getStatementChangeCount();
312 }
313 
314 Reference< XResultSet > SAL_CALL OPreparedStatement::executeQuery()
315     throw(SQLException, RuntimeException, std::exception)
316 {
317     execute();
318     return m_xResultSet;
319 }
320 
321 namespace {
322 
323 /**
324  * Take out the number part of a fix point decimal without
325  * the information of where is the fracional part from a
326  * string representation of a number. (e.g. 54.654 -> 54654)
327  */
328 sal_Int64 toNumericWithoutDecimalPlace(const OUString& sSource)
329 {
330     OUString sNumber(sSource);
331 
332     // cut off leading 0 eventually ( eg. 0.567 -> .567)
333     (void)sSource.startsWith("0", &sNumber);
334 
335     sal_Int32 nDotIndex = sNumber.indexOf((sal_Unicode)'.');
336 
337     if( nDotIndex < 0)
338     {
339         return sNumber.toInt64(); // no dot -> it's an integer
340     }
341     else
342     {
343         // remove dot
344         OUStringBuffer sBuffer(15);
345         if(nDotIndex > 0)
346         {
347             sBuffer.append(sNumber.copy(0, nDotIndex));
348         }
349         sBuffer.append(sNumber.copy(nDotIndex + 1));
350         return sBuffer.makeStringAndClear().toInt64();
351     }
352 }
353 
354 }
355 
356 //----- XParameters -----------------------------------------------------------
357 void SAL_CALL OPreparedStatement::setNull(sal_Int32 nIndex, sal_Int32 /*nSqlType*/)
358     throw(SQLException, RuntimeException, std::exception)
359 {
360     MutexGuard aGuard( m_aMutex );
361     checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed);
362     ensurePrepared();
363 
364     setParameterNull(nIndex);
365 }
366 
367 void SAL_CALL OPreparedStatement::setBoolean(sal_Int32 /*nIndex*/, sal_Bool /*bValue*/)
368     throw(SQLException, RuntimeException, std::exception)
369 {
370     // FIREBIRD3: will need to be implemented.
371     ::dbtools::throwFunctionNotSupportedSQLException("XParameters::setBoolean", *this);
372 }
373 
374 template <typename T>
375 void OPreparedStatement::setValue(sal_Int32 nIndex, T& nValue, ISC_SHORT nType)
376     throw(SQLException, RuntimeException)
377 {
378     MutexGuard aGuard( m_aMutex );
379     checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed);
380     ensurePrepared();
381 
382     checkParameterIndex(nIndex);
383     setParameterNull(nIndex, false);
384 
385     XSQLVAR* pVar = m_pInSqlda->sqlvar + (nIndex - 1);
386 
387     if ((pVar->sqltype & ~1) != nType)
388     {
389        ::dbtools::throwSQLException(
390             "Incorrect type for setString",
391             ::dbtools::StandardSQLState::INVALID_SQL_DATA_TYPE,
392             *this);
393     }
394 
395     memcpy(pVar->sqldata, &nValue, sizeof(nValue));
396 }
397 
398 void SAL_CALL OPreparedStatement::setByte(sal_Int32 /*nIndex*/, sal_Int8 /*nValue*/)
399     throw(SQLException, RuntimeException, std::exception)
400 {
401     ::dbtools::throwFunctionNotSupportedSQLException("XParameters::setByte", *this);
402 }
403 
404 void SAL_CALL OPreparedStatement::setShort(sal_Int32 nIndex, sal_Int16 nValue)
405     throw(SQLException, RuntimeException, std::exception)
406 {
407     setValue< sal_Int16 >(nIndex, nValue, SQL_SHORT);
408 }
409 
410 void SAL_CALL OPreparedStatement::setInt(sal_Int32 nIndex, sal_Int32 nValue)
411     throw(SQLException, RuntimeException, std::exception)
412 {
413     setValue< sal_Int32 >(nIndex, nValue, SQL_LONG);
414 }
415 
416 void SAL_CALL OPreparedStatement::setLong(sal_Int32 nIndex, sal_Int64 nValue)
417     throw(SQLException, RuntimeException, std::exception)
418 {
419     setValue< sal_Int64 >(nIndex, nValue, SQL_INT64);
420 }
421 
422 void SAL_CALL OPreparedStatement::setFloat(sal_Int32 nIndex, float nValue)
423     throw(SQLException, RuntimeException, std::exception)
424 {
425     setValue< float >(nIndex, nValue, SQL_FLOAT);
426 }
427 
428 void SAL_CALL OPreparedStatement::setDouble(sal_Int32 nIndex, double nValue)
429     throw(SQLException, RuntimeException, std::exception)
430 {
431     setValue< double >(nIndex, nValue, SQL_DOUBLE); // TODO: SQL_D_FLOAT?
432 }
433 
434 void SAL_CALL OPreparedStatement::setDate(sal_Int32 nIndex, const Date& rDate)
435     throw(SQLException, RuntimeException, std::exception)
436 {
437     struct tm aCTime;
438     aCTime.tm_mday = rDate.Day;
439     aCTime.tm_mon = rDate.Month -1;
440     aCTime.tm_year = rDate.Year -1900;
441 
442     ISC_DATE aISCDate;
443     isc_encode_sql_date(&aCTime, &aISCDate);
444 
445     setValue< ISC_DATE >(nIndex, aISCDate, SQL_TYPE_DATE);
446 }
447 
448 void SAL_CALL OPreparedStatement::setTime( sal_Int32 nIndex, const css::util::Time& rTime)
449     throw(SQLException, RuntimeException, std::exception)
450 {
451     struct tm aCTime;
452     aCTime.tm_sec = rTime.Seconds;
453     aCTime.tm_min = rTime.Minutes;
454     aCTime.tm_hour = rTime.Hours;
455 
456     ISC_TIME aISCTime;
457     isc_encode_sql_time(&aCTime, &aISCTime);
458 
459     setValue< ISC_TIME >(nIndex, aISCTime, SQL_TYPE_TIME);
460 }
461 
462 void SAL_CALL OPreparedStatement::setTimestamp(sal_Int32 nIndex, const DateTime& rTimestamp)
463     throw(SQLException, RuntimeException, std::exception)
464 {
465     struct tm aCTime;
466     aCTime.tm_sec = rTimestamp.Seconds;
467     aCTime.tm_min = rTimestamp.Minutes;
468     aCTime.tm_hour = rTimestamp.Hours;
469     aCTime.tm_mday = rTimestamp.Day;
470     aCTime.tm_mon = rTimestamp.Month - 1;
471     aCTime.tm_year = rTimestamp.Year - 1900;
472 
473     ISC_TIMESTAMP aISCTimestamp;
474     isc_encode_timestamp(&aCTime, &aISCTimestamp);
475 
476     setValue< ISC_TIMESTAMP >(nIndex, aISCTimestamp, SQL_TIMESTAMP);
477 }
478 
479 
480 // void OPreaparedStatement::set
481 void OPreparedStatement::openBlobForWriting(isc_blob_handle& rBlobHandle, ISC_QUAD& rBlobId)
482 {
483     ISC_STATUS aErr;
484 
485     aErr = isc_create_blob2(m_statusVector,
486                             &m_pConnection->getDBHandle(),
487                             &m_pConnection->getTransaction(),
488                             &rBlobHandle,
489                             &rBlobId,
490                             0, // Blob parameter buffer length
491                             nullptr); // Blob parameter buffer handle
492 
493     if (aErr)
494     {
495         evaluateStatusVector(m_statusVector,
496                              "setBlob failed on " + m_sSqlStatement,
497                              *this);
498         assert(false);
499     }
500 }
501 
502 void OPreparedStatement::closeBlobAfterWriting(isc_blob_handle& rBlobHandle)
503 {
504     ISC_STATUS aErr;
505 
506     aErr = isc_close_blob(m_statusVector,
507                           &rBlobHandle);
508     if (aErr)
509     {
510         evaluateStatusVector(m_statusVector,
511                              "isc_close_blob failed",
512                              *this);
513         assert(false);
514     }
515 }
516 
517 void SAL_CALL OPreparedStatement::setClob( sal_Int32 parameterIndex, const Reference< XClob >& x ) throw(SQLException, RuntimeException, std::exception)
518 {
519     (void) parameterIndex;
520     (void) x;
521     ::osl::MutexGuard aGuard( m_aMutex );
522     checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed);
523 
524 }
525 
526 void SAL_CALL OPreparedStatement::setBlob(sal_Int32 nParameterIndex,
527                                           const Reference< XBlob >& xBlob)
528     throw (SQLException, RuntimeException, std::exception)
529 {
530     ::osl::MutexGuard aGuard(m_aMutex);
531     checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed);
532 
533 #if SAL_TYPES_SIZEOFPOINTER == 8
534     isc_blob_handle aBlobHandle = 0;
535 #else
536     isc_blob_handle aBlobHandle = nullptr;
537 #endif
538     ISC_QUAD aBlobId;
539 
540     openBlobForWriting(aBlobHandle, aBlobId);
541 
542     // Max segment size is 2^16 == SAL_MAX_UINT16
543     // LEM TODO: SAL_MAX_UINT16 is 2^16-1; this mixup is probably innocuous; to be checked
544     sal_uInt64 nDataWritten = 0;
545     ISC_STATUS aErr = 0;
546     while (xBlob->length() - nDataWritten > 0)
547     {
548         sal_uInt64 nDataRemaining = xBlob->length() - nDataWritten;
549         sal_uInt16 nWriteSize = (nDataRemaining > SAL_MAX_UINT16) ? SAL_MAX_UINT16 : nDataRemaining;
550         aErr = isc_put_segment(m_statusVector,
551                                &aBlobHandle,
552                                nWriteSize,
553                                reinterpret_cast<const char*>(xBlob->getBytes(nDataWritten, nWriteSize).getConstArray()));
554         nDataWritten += nWriteSize;
555 
556 
557         if (aErr)
558             break;
559 
560     }
561 
562     // We need to make sure we close the Blob even if their are errors, hence evaluate
563     // errors after closing.
564     closeBlobAfterWriting(aBlobHandle);
565 
566     if (aErr)
567     {
568         evaluateStatusVector(m_statusVector,
569                              "isc_put_segment failed",
570                              *this);
571         assert(false);
572     }
573 
574     setValue< ISC_QUAD >(nParameterIndex, aBlobId, SQL_BLOB);
575 }
576 
577 
578 void SAL_CALL OPreparedStatement::setArray( sal_Int32 parameterIndex, const Reference< XArray >& x ) throw(SQLException, RuntimeException, std::exception)
579 {
580     (void) parameterIndex;
581     (void) x;
582     ::osl::MutexGuard aGuard( m_aMutex );
583     checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed);
584 
585 }
586 
587 
588 void SAL_CALL OPreparedStatement::setRef( sal_Int32 parameterIndex, const Reference< XRef >& x ) throw(SQLException, RuntimeException, std::exception)
589 {
590     (void) parameterIndex;
591     (void) x;
592     ::osl::MutexGuard aGuard( m_aMutex );
593     checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed);
594 
595 }
596 
597 
598 void SAL_CALL OPreparedStatement::setObjectWithInfo( sal_Int32 parameterIndex, const Any& x, sal_Int32 sqlType, sal_Int32 scale ) throw(SQLException, RuntimeException, std::exception)
599 {
600     checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed);
601     ::osl::MutexGuard aGuard( m_aMutex );
602 
603     XSQLVAR* pVar = m_pInSqlda->sqlvar + (parameterIndex - 1);
604     int dType = (pVar->sqltype & ~1); // drop null flag
605 
606     if(sqlType == DataType::DECIMAL || sqlType == DataType::NUMERIC)
607     {
608         double myDouble=0.0;
609         OUString myString;
610         if( x >>= myDouble )
611         {
612             myString = OUString::number( myDouble );
613         }
614         else
615         {
616             x >>= myString;
617         }
618 
619         // fill in the number with nulls in fractional part.
620         // We need this because  e.g. 0.450 != 0.045 despite
621         // their scale is equal
622         OUStringBuffer sBuffer(15);
623         sBuffer.append(myString);
624         if(myString.indexOf('.') != -1) // there is a dot
625         {
626             for(sal_Int32 i=myString.copy(myString.indexOf('.')+1).getLength(); i<scale;i++)
627             {
628                 sBuffer.append('0');
629             }
630         }
631         else
632         {
633             for (sal_Int32 i=0; i<scale; i++)
634             {
635                 sBuffer.append('0');
636             }
637         }
638         myString = sBuffer.makeStringAndClear();
639         // set value depending on type
640         sal_Int16 n16Value = 0;
641         sal_Int32 n32Value = 0;
642         sal_Int64 n64Value = 0;
643         switch(dType)
644         {
645             case SQL_SHORT:
646                 n16Value = (sal_Int16) toNumericWithoutDecimalPlace(myString);
647                 setValue< sal_Int16 >(parameterIndex,
648                         n16Value,
649                         dType);
650                 break;
651             case SQL_LONG:
652             case SQL_DOUBLE: // TODO FIXME 32 bits
653                 n32Value = (sal_Int32) toNumericWithoutDecimalPlace(myString);
654                 setValue< sal_Int32 >(parameterIndex,
655                         n32Value,
656                         dType);
657                 break;
658             case SQL_INT64:
659                 n64Value = (sal_Int64) toNumericWithoutDecimalPlace(myString);
660                 setValue< sal_Int64 >(parameterIndex,
661                         n64Value,
662                         dType);
663                 break;
664             default:
665                 SAL_WARN("connectivity.firebird",
666                         "No Firebird sql type found for numeric or decimal types");
667                 ::dbtools::setObjectWithInfo(this,parameterIndex,x,sqlType,scale);
668         }
669     }
670     else
671     {
672         ::dbtools::setObjectWithInfo(this,parameterIndex,x,sqlType,scale);
673     }
674 
675 }
676 
677 
678 void SAL_CALL OPreparedStatement::setObjectNull( sal_Int32 parameterIndex, sal_Int32 sqlType, const ::rtl::OUString& typeName ) throw(SQLException, RuntimeException, std::exception)
679 {
680     (void) parameterIndex;
681     (void) sqlType;
682     (void) typeName;
683     ::osl::MutexGuard aGuard( m_aMutex );
684     checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed);
685 
686 }
687 
688 
689 void SAL_CALL OPreparedStatement::setObject( sal_Int32 parameterIndex, const Any& x ) throw(SQLException, RuntimeException, std::exception)
690 {
691     (void) parameterIndex;
692     (void) x;
693     ::osl::MutexGuard aGuard( m_aMutex );
694     checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed);
695 
696 }
697 
698 void SAL_CALL OPreparedStatement::setBytes(sal_Int32 nParameterIndex,
699                                            const Sequence< sal_Int8 >& xBytes)
700     throw (SQLException, RuntimeException, std::exception)
701 {
702     ::osl::MutexGuard aGuard(m_aMutex);
703     checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed);
704 
705 #if SAL_TYPES_SIZEOFPOINTER == 8
706     isc_blob_handle aBlobHandle = 0;
707 #else
708     isc_blob_handle aBlobHandle = nullptr;
709 #endif
710     ISC_QUAD aBlobId;
711 
712     openBlobForWriting(aBlobHandle, aBlobId);
713 
714     // Max segment size is 2^16 == SAL_MAX_UINT16
715     sal_uInt64 nDataWritten = 0;
716     ISC_STATUS aErr = 0;
717     while (xBytes.getLength() - nDataWritten > 0)
718     {
719         sal_uInt64 nDataRemaining = xBytes.getLength() - nDataWritten;
720         sal_uInt16 nWriteSize = (nDataRemaining > SAL_MAX_UINT16) ? SAL_MAX_UINT16 : nDataRemaining;
721         aErr = isc_put_segment(m_statusVector,
722                                &aBlobHandle,
723                                nWriteSize,
724                                reinterpret_cast<const char*>(xBytes.getConstArray()) + nDataWritten);
725         nDataWritten += nWriteSize;
726 
727         if (aErr)
728             break;
729     }
730 
731     // We need to make sure we close the Blob even if their are errors, hence evaluate
732     // errors after closing.
733     closeBlobAfterWriting(aBlobHandle);
734 
735     if (aErr)
736     {
737         evaluateStatusVector(m_statusVector,
738                              "isc_put_segment failed",
739                              *this);
740         assert(false);
741     }
742 
743     setValue< ISC_QUAD >(nParameterIndex, aBlobId, SQL_BLOB);
744 }
745 
746 
747 void SAL_CALL OPreparedStatement::setCharacterStream( sal_Int32 parameterIndex, const Reference< css::io::XInputStream >& x, sal_Int32 length ) throw(SQLException, RuntimeException, std::exception)
748 {
749     (void) parameterIndex;
750     (void) x;
751     (void) length;
752     ::osl::MutexGuard aGuard( m_aMutex );
753     checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed);
754 
755 }
756 
757 
758 void SAL_CALL OPreparedStatement::setBinaryStream( sal_Int32 parameterIndex, const Reference< css::io::XInputStream >& x, sal_Int32 length ) throw(SQLException, RuntimeException, std::exception)
759 {
760     (void) parameterIndex;
761     (void) x;
762     (void) length;
763     ::osl::MutexGuard aGuard( m_aMutex );
764     checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed);
765 
766 }
767 
768 
769 void SAL_CALL OPreparedStatement::clearParameters(  ) throw(SQLException, RuntimeException, std::exception)
770 {
771 }
772 
773 // ---- Batch methods -- unsupported -----------------------------------------
774 void SAL_CALL OPreparedStatement::clearBatch()
775     throw(SQLException, RuntimeException, std::exception)
776 {
777     // Unsupported
778 }
779 
780 void SAL_CALL OPreparedStatement::addBatch()
781     throw(SQLException, RuntimeException, std::exception)
782 {
783     // Unsupported by firebird
784 }
785 
786 Sequence< sal_Int32 > SAL_CALL OPreparedStatement::executeBatch()
787     throw(SQLException, RuntimeException, std::exception)
788 {
789     // Unsupported by firebird
790     return Sequence< sal_Int32 >();
791 }
792 
793 void OPreparedStatement::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any& rValue) throw (Exception, std::exception)
794 {
795     switch(nHandle)
796     {
797         case PROPERTY_ID_RESULTSETCONCURRENCY:
798             break;
799         case PROPERTY_ID_RESULTSETTYPE:
800             break;
801         case PROPERTY_ID_FETCHDIRECTION:
802             break;
803         case PROPERTY_ID_USEBOOKMARKS:
804             break;
805         default:
806             OStatementCommonBase::setFastPropertyValue_NoBroadcast(nHandle,rValue);
807     }
808 }
809 
810 void OPreparedStatement::checkParameterIndex(sal_Int32 nParameterIndex)
811     throw(SQLException, RuntimeException)
812 {
813     ensurePrepared();
814     if ((nParameterIndex == 0) || (nParameterIndex > m_pInSqlda->sqld))
815     {
816         ::dbtools::throwSQLException(
817             "No column " + OUString::number(nParameterIndex),
818             ::dbtools::StandardSQLState::COLUMN_NOT_FOUND,
819             *this);
820     }
821 }
822 
823 void OPreparedStatement::setParameterNull(sal_Int32 nParameterIndex,
824                                           bool bSetNull)
825 {
826     XSQLVAR* pVar = m_pInSqlda->sqlvar + (nParameterIndex - 1);
827     if (bSetNull)
828     {
829         pVar->sqltype |= 1;
830         *pVar->sqlind = -1;
831     }
832     else
833         *pVar->sqlind = 0;
834 }
835 
836 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
837