1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sal/config.h>
23 #include <string_view>
25 #include "Connection.hxx"
26 #include "PreparedStatement.hxx"
27 #include "ResultSet.hxx"
28 #include "ResultSetMetaData.hxx"
31 #include <comphelper/sequence.hxx>
32 #include <connectivity/dbexception.hxx>
33 #include <propertyids.hxx>
34 #include <connectivity/dbtools.hxx>
35 #include <sal/log.hxx>
37 #include <com/sun/star/sdbc/DataType.hpp>
39 using namespace connectivity::firebird
;
41 using namespace ::comphelper
;
42 using namespace ::osl
;
44 using namespace com::sun::star
;
45 using namespace com::sun::star::uno
;
46 using namespace com::sun::star::lang
;
47 using namespace com::sun::star::beans
;
48 using namespace com::sun::star::sdbc
;
49 using namespace com::sun::star::container
;
50 using namespace com::sun::star::io
;
51 using namespace com::sun::star::util
;
53 IMPLEMENT_SERVICE_INFO(OPreparedStatement
,"com.sun.star.sdbcx.firebird.PreparedStatement","com.sun.star.sdbc.PreparedStatement");
56 OPreparedStatement::OPreparedStatement( Connection
* _pConnection
,
58 :OStatementCommonBase(_pConnection
)
63 SAL_INFO("connectivity.firebird", "OPreparedStatement(). "
67 void OPreparedStatement::ensurePrepared()
69 MutexGuard
aGuard(m_aMutex
);
70 checkDisposed(OStatementCommonBase_Base::rBHelper
.bDisposed
);
72 if (m_aStatementHandle
)
79 m_pInSqlda
= static_cast<XSQLDA
*>(calloc(1, XSQLDA_LENGTH(10)));
80 m_pInSqlda
->version
= SQLDA_VERSION1
;
81 m_pInSqlda
->sqln
= 10;
84 prepareAndDescribeStatement(m_sSqlStatement
,
88 aErr
= isc_dsql_describe_bind(m_statusVector
,
95 SAL_WARN("connectivity.firebird", "isc_dsql_describe_bind failed");
97 else if (m_pInSqlda
->sqld
> m_pInSqlda
->sqln
) // Not large enough
99 short nItems
= m_pInSqlda
->sqld
;
101 m_pInSqlda
= static_cast<XSQLDA
*>(calloc(1, XSQLDA_LENGTH(nItems
)));
102 m_pInSqlda
->version
= SQLDA_VERSION1
;
103 m_pInSqlda
->sqln
= nItems
;
104 aErr
= isc_dsql_describe_bind(m_statusVector
,
108 SAL_WARN_IF(aErr
, "connectivity.firebird", "isc_dsql_describe_bind failed");
112 mallocSQLVAR(m_pInSqlda
);
114 evaluateStatusVector(m_statusVector
, m_sSqlStatement
, *this);
117 OPreparedStatement::~OPreparedStatement()
121 void SAL_CALL
OPreparedStatement::acquire() noexcept
123 OStatementCommonBase::acquire();
126 void SAL_CALL
OPreparedStatement::release() noexcept
128 OStatementCommonBase::release();
131 Any SAL_CALL
OPreparedStatement::queryInterface(const Type
& rType
)
133 Any aRet
= OStatementCommonBase::queryInterface(rType
);
135 aRet
= OPreparedStatement_Base::queryInterface(rType
);
139 uno::Sequence
< Type
> SAL_CALL
OPreparedStatement::getTypes()
141 return concatSequences(OPreparedStatement_Base::getTypes(),
142 OStatementCommonBase::getTypes());
145 Reference
< XResultSetMetaData
> SAL_CALL
OPreparedStatement::getMetaData()
147 ::osl::MutexGuard
aGuard( m_aMutex
);
148 checkDisposed(OStatementCommonBase_Base::rBHelper
.bDisposed
);
151 if(!m_xMetaData
.is())
152 m_xMetaData
= new OResultSetMetaData(m_pConnection
.get()
158 void SAL_CALL
OPreparedStatement::close()
160 MutexGuard
aGuard( m_aMutex
);
161 checkDisposed(OStatementCommonBase_Base::rBHelper
.bDisposed
);
163 OStatementCommonBase::close();
166 freeSQLVAR(m_pInSqlda
);
168 m_pInSqlda
= nullptr;
172 freeSQLVAR(m_pOutSqlda
);
174 m_pOutSqlda
= nullptr;
178 void SAL_CALL
OPreparedStatement::disposing()
183 void SAL_CALL
OPreparedStatement::setString(sal_Int32 nParameterIndex
,
184 const OUString
& sInput
)
186 SAL_INFO("connectivity.firebird",
187 "setString(" << nParameterIndex
<< " , " << sInput
<< ")");
189 MutexGuard
aGuard( m_aMutex
);
190 checkDisposed(OStatementCommonBase_Base::rBHelper
.bDisposed
);
193 checkParameterIndex(nParameterIndex
);
194 setParameterNull(nParameterIndex
, false);
196 OString str
= OUStringToOString(sInput
, RTL_TEXTENCODING_UTF8
);
198 XSQLVAR
* pVar
= m_pInSqlda
->sqlvar
+ (nParameterIndex
- 1);
200 int dtype
= (pVar
->sqltype
& ~1); // drop flag bit for now
202 if (str
.getLength() > pVar
->sqllen
)
203 str
= str
.copy(0, pVar
->sqllen
);
208 const sal_Int32 max_varchar_len
= 0xFFFF;
209 // First 2 bytes indicate string size
210 if (str
.getLength() > max_varchar_len
)
212 str
= str
.copy(0, max_varchar_len
);
214 const auto nLength
= str
.getLength();
215 memcpy(pVar
->sqldata
, &nLength
, 2);
217 memcpy(pVar
->sqldata
+ 2, str
.getStr(), str
.getLength());
221 memcpy(pVar
->sqldata
, str
.getStr(), str
.getLength());
222 // Fill remainder with spaces
223 memset(pVar
->sqldata
+ str
.getLength(), ' ', pVar
->sqllen
- str
.getLength());
225 case SQL_BLOB
: // Clob
226 assert( pVar
->sqlsubtype
== static_cast<short>(BlobSubtype::Clob
) );
227 setClob(nParameterIndex
, sInput
);
231 sal_Int32 int32Value
= sInput
.toInt32();
232 if ( (int32Value
< std::numeric_limits
<sal_Int16
>::min()) ||
233 (int32Value
> std::numeric_limits
<sal_Int16
>::max()) )
235 ::dbtools::throwSQLException(
236 "Value out of range for SQL_SHORT type",
237 ::dbtools::StandardSQLState::INVALID_SQL_DATA_TYPE
,
240 setShort(nParameterIndex
, int32Value
);
245 sal_Int32 int32Value
= sInput
.toInt32();
246 setInt(nParameterIndex
, int32Value
);
251 sal_Int64 int64Value
= sInput
.toInt64();
252 setLong(nParameterIndex
, int64Value
);
257 float floatValue
= sInput
.toFloat();
258 setFloat(nParameterIndex
, floatValue
);
263 bool boolValue
= sInput
.toBoolean();
264 setBoolean(nParameterIndex
, boolValue
);
268 ::dbtools::throwSQLException(
269 "Incorrect type for setString",
270 ::dbtools::StandardSQLState::INVALID_SQL_DATA_TYPE
,
275 Reference
< XConnection
> SAL_CALL
OPreparedStatement::getConnection()
277 MutexGuard
aGuard( m_aMutex
);
278 checkDisposed(OStatementCommonBase_Base::rBHelper
.bDisposed
);
280 return m_pConnection
;
283 sal_Bool SAL_CALL
OPreparedStatement::execute()
285 SAL_INFO("connectivity.firebird", "executeQuery(). "
286 "Got called with sql: " << m_sSqlStatement
);
288 MutexGuard
aGuard( m_aMutex
);
289 checkDisposed(OStatementCommonBase_Base::rBHelper
.bDisposed
);
295 if (m_xResultSet
.is()) // Checks whether we have already run the statement.
298 // Closes the cursor from the last run.
299 // This doesn't actually free the statement -- using DSQL_close closes
300 // the cursor and keeps the statement, using DSQL_drop frees the statement
301 // (and associated cursors).
302 aErr
= isc_dsql_free_statement(m_statusVector
,
307 // Do not throw error. Trying to close a closed cursor is not a
309 OUString sErrMsg
= StatusVectorToString(m_statusVector
,
310 u
"isc_dsql_free_statement: close cursor");
311 SAL_WARN("connectivity.firebird", sErrMsg
);
315 aErr
= isc_dsql_execute(m_statusVector
,
316 &m_pConnection
->getTransaction(),
322 SAL_WARN("connectivity.firebird", "isc_dsql_execute failed" );
323 evaluateStatusVector(m_statusVector
, u
"isc_dsql_execute", *this);
326 m_xResultSet
= new OResultSet(m_pConnection
.get(),
328 uno::Reference
< XInterface
>(*this),
332 if (getStatementChangeCount() > 0)
333 m_pConnection
->notifyDatabaseModified();
335 return m_xResultSet
.is();
336 // TODO: implement handling of multiple ResultSets.
339 sal_Int32 SAL_CALL
OPreparedStatement::executeUpdate()
342 return getStatementChangeCount();
345 Reference
< XResultSet
> SAL_CALL
OPreparedStatement::executeQuery()
354 * Take out the number part of a fix point decimal without
355 * the information of where is the fractional part from a
356 * string representation of a number. (e.g. 54.654 -> 54654)
358 sal_Int64
toNumericWithoutDecimalPlace(const OUString
& sSource
)
360 OUString
sNumber(sSource
);
362 // cut off leading 0 eventually ( eg. 0.567 -> .567)
363 (void)sSource
.startsWith("0", &sNumber
);
365 sal_Int32 nDotIndex
= sNumber
.indexOf('.');
369 return sNumber
.toInt64(); // no dot -> it's an integer
374 OUStringBuffer
sBuffer(15);
377 sBuffer
.append(sNumber
.subView(0, nDotIndex
));
379 sBuffer
.append(sNumber
.subView(nDotIndex
+ 1));
380 return sBuffer
.makeStringAndClear().toInt64();
386 //----- XParameters -----------------------------------------------------------
387 void SAL_CALL
OPreparedStatement::setNull(sal_Int32 nIndex
, sal_Int32
/*nSqlType*/)
389 MutexGuard
aGuard( m_aMutex
);
390 checkDisposed(OStatementCommonBase_Base::rBHelper
.bDisposed
);
393 checkParameterIndex(nIndex
);
394 setParameterNull(nIndex
);
397 void SAL_CALL
OPreparedStatement::setBoolean(sal_Int32 nIndex
, sal_Bool bValue
)
399 setValue
< sal_Bool
>(nIndex
, bValue
, SQL_BOOLEAN
);
402 template <typename T
>
403 void OPreparedStatement::setValue(sal_Int32 nIndex
, const T
& nValue
, ISC_SHORT nType
)
405 MutexGuard
aGuard( m_aMutex
);
406 checkDisposed(OStatementCommonBase_Base::rBHelper
.bDisposed
);
409 checkParameterIndex(nIndex
);
410 setParameterNull(nIndex
, false);
412 XSQLVAR
* pVar
= m_pInSqlda
->sqlvar
+ (nIndex
- 1);
414 if ((pVar
->sqltype
& ~1) != nType
)
416 ::dbtools::throwSQLException(
417 "Incorrect type for setValue",
418 ::dbtools::StandardSQLState::INVALID_SQL_DATA_TYPE
,
422 memcpy(pVar
->sqldata
, &nValue
, sizeof(nValue
));
425 void SAL_CALL
OPreparedStatement::setByte(sal_Int32 nIndex
, sal_Int8 nValue
)
427 // there's no TINYINT or equivalent on Firebird,
428 // so do the same as setShort
429 setValue
< sal_Int16
>(nIndex
, nValue
, SQL_SHORT
);
432 void SAL_CALL
OPreparedStatement::setShort(sal_Int32 nIndex
, sal_Int16 nValue
)
434 setValue
< sal_Int16
>(nIndex
, nValue
, SQL_SHORT
);
437 void SAL_CALL
OPreparedStatement::setInt(sal_Int32 nIndex
, sal_Int32 nValue
)
439 setValue
< sal_Int32
>(nIndex
, nValue
, SQL_LONG
);
442 void SAL_CALL
OPreparedStatement::setLong(sal_Int32 nIndex
, sal_Int64 nValue
)
444 setValue
< sal_Int64
>(nIndex
, nValue
, SQL_INT64
);
447 void SAL_CALL
OPreparedStatement::setFloat(sal_Int32 nIndex
, float nValue
)
449 setValue
< float >(nIndex
, nValue
, SQL_FLOAT
);
452 void SAL_CALL
OPreparedStatement::setDouble(sal_Int32 nIndex
, double nValue
)
454 MutexGuard
aGuard( m_aMutex
);
455 checkDisposed(OStatementCommonBase_Base::rBHelper
.bDisposed
);
458 XSQLVAR
* pVar
= m_pInSqlda
->sqlvar
+ (nIndex
- 1);
459 short dType
= (pVar
->sqltype
& ~1); // drop flag bit for now
460 short dSubType
= pVar
->sqlsubtype
;
461 // Assume it is a sub type of a number.
462 if(dSubType
< 0 || dSubType
> 2)
464 ::dbtools::throwSQLException(
465 "Incorrect number sub type",
466 ::dbtools::StandardSQLState::INVALID_SQL_DATA_TYPE
,
469 // firebird stores scale as a negative number
470 ColumnTypeInfo columnType
{ dType
, dSubType
,
471 static_cast<short>(-pVar
->sqlscale
) };
473 // Caller might try to set an integer type here. It makes sense to convert
474 // it instead of throwing an error.
475 switch(columnType
.getSdbcType())
477 case DataType::SMALLINT
:
478 setValue
< sal_Int16
>(nIndex
,
479 static_cast<sal_Int16
>(nValue
),
482 case DataType::INTEGER
:
483 setValue
< sal_Int32
>(nIndex
,
484 static_cast<sal_Int32
>(nValue
),
487 case DataType::BIGINT
:
488 setValue
< sal_Int64
>(nIndex
,
489 static_cast<sal_Int64
>(nValue
),
492 case DataType::NUMERIC
:
493 case DataType::DECIMAL
:
494 // take decimal places into account, later on they are removed in makeNumericString
495 setObjectWithInfo(nIndex
,Any
{nValue
}, columnType
.getSdbcType(), columnType
.getScale());
498 setValue
< double >(nIndex
, nValue
, SQL_DOUBLE
); // TODO: SQL_D_FLOAT?
502 void SAL_CALL
OPreparedStatement::setDate(sal_Int32 nIndex
, const Date
& rDate
)
505 aCTime
.tm_mday
= rDate
.Day
;
506 aCTime
.tm_mon
= rDate
.Month
-1;
507 aCTime
.tm_year
= rDate
.Year
-1900;
510 isc_encode_sql_date(&aCTime
, &aISCDate
);
512 setValue
< ISC_DATE
>(nIndex
, aISCDate
, SQL_TYPE_DATE
);
515 void SAL_CALL
OPreparedStatement::setTime( sal_Int32 nIndex
, const css::util::Time
& rTime
)
518 aCTime
.tm_sec
= rTime
.Seconds
;
519 aCTime
.tm_min
= rTime
.Minutes
;
520 aCTime
.tm_hour
= rTime
.Hours
;
523 isc_encode_sql_time(&aCTime
, &aISCTime
);
525 // Here we "know" that ISC_TIME is simply in units of seconds/ISC_TIME_SECONDS_PRECISION with no
526 // other funkiness, so we can simply add the fraction of a second.
527 aISCTime
+= rTime
.NanoSeconds
/ (1000000000 / ISC_TIME_SECONDS_PRECISION
);
529 setValue
< ISC_TIME
>(nIndex
, aISCTime
, SQL_TYPE_TIME
);
532 void SAL_CALL
OPreparedStatement::setTimestamp(sal_Int32 nIndex
, const DateTime
& rTimestamp
)
535 aCTime
.tm_sec
= rTimestamp
.Seconds
;
536 aCTime
.tm_min
= rTimestamp
.Minutes
;
537 aCTime
.tm_hour
= rTimestamp
.Hours
;
538 aCTime
.tm_mday
= rTimestamp
.Day
;
539 aCTime
.tm_mon
= rTimestamp
.Month
- 1;
540 aCTime
.tm_year
= rTimestamp
.Year
- 1900;
542 ISC_TIMESTAMP aISCTimestamp
;
543 isc_encode_timestamp(&aCTime
, &aISCTimestamp
);
545 // As in previous function
546 aISCTimestamp
.timestamp_time
+= rTimestamp
.NanoSeconds
/ (1000000000 / ISC_TIME_SECONDS_PRECISION
);
548 setValue
< ISC_TIMESTAMP
>(nIndex
, aISCTimestamp
, SQL_TIMESTAMP
);
552 // void OPreparedStatement::set
553 void OPreparedStatement::openBlobForWriting(isc_blob_handle
& rBlobHandle
, ISC_QUAD
& rBlobId
)
557 aErr
= isc_create_blob2(m_statusVector
,
558 &m_pConnection
->getDBHandle(),
559 &m_pConnection
->getTransaction(),
562 0, // Blob parameter buffer length
563 nullptr); // Blob parameter buffer handle
567 evaluateStatusVector(m_statusVector
,
568 OUString("setBlob failed on " + m_sSqlStatement
),
574 void OPreparedStatement::closeBlobAfterWriting(isc_blob_handle
& rBlobHandle
)
578 aErr
= isc_close_blob(m_statusVector
,
582 evaluateStatusVector(m_statusVector
,
583 u
"isc_close_blob failed",
589 void SAL_CALL
OPreparedStatement::setClob(sal_Int32 nParameterIndex
, const Reference
< XClob
>& xClob
)
591 ::osl::MutexGuard
aGuard( m_aMutex
);
592 checkDisposed(OStatementCommonBase_Base::rBHelper
.bDisposed
);
594 #if SAL_TYPES_SIZEOFPOINTER == 8
595 isc_blob_handle aBlobHandle
= 0;
597 isc_blob_handle aBlobHandle
= nullptr;
601 openBlobForWriting(aBlobHandle
, aBlobId
);
604 // Max segment size is 2^16 == SAL_MAX_UINT16
605 // SAL_MAX_UINT16 / 4 is surely enough for UTF-8
606 // TODO apply max segment size to character encoding
607 sal_Int64 nCharWritten
= 1; // XClob is indexed from 1
609 sal_Int64 nLen
= xClob
->length();
610 while ( nLen
> nCharWritten
)
612 sal_Int64 nCharRemain
= nLen
- nCharWritten
;
613 constexpr sal_uInt16 MAX_SIZE
= SAL_MAX_UINT16
/ 4;
614 sal_uInt16 nWriteSize
= std::min
<sal_Int64
>(nCharRemain
, MAX_SIZE
);
615 OString sData
= OUStringToOString(
616 xClob
->getSubString(nCharWritten
, nWriteSize
),
617 RTL_TEXTENCODING_UTF8
);
618 aErr
= isc_put_segment( m_statusVector
,
622 nCharWritten
+= nWriteSize
;
628 // We need to make sure we close the Blob even if there are errors, hence evaluate
629 // errors after closing.
630 closeBlobAfterWriting(aBlobHandle
);
634 evaluateStatusVector(m_statusVector
,
635 u
"isc_put_segment failed",
640 setValue
< ISC_QUAD
>(nParameterIndex
, aBlobId
, SQL_BLOB
);
643 void OPreparedStatement::setClob( sal_Int32 nParameterIndex
, const OUString
& rStr
)
645 ::osl::MutexGuard
aGuard( m_aMutex
);
646 checkDisposed(OStatementCommonBase_Base::rBHelper
.bDisposed
);
647 checkParameterIndex(nParameterIndex
);
649 #if SAL_TYPES_SIZEOFPOINTER == 8
650 isc_blob_handle aBlobHandle
= 0;
652 isc_blob_handle aBlobHandle
= nullptr;
656 openBlobForWriting(aBlobHandle
, aBlobId
);
658 OString sData
= OUStringToOString(
660 RTL_TEXTENCODING_UTF8
);
661 ISC_STATUS aErr
= isc_put_segment( m_statusVector
,
666 // We need to make sure we close the Blob even if there are errors, hence evaluate
667 // errors after closing.
668 closeBlobAfterWriting(aBlobHandle
);
672 evaluateStatusVector(m_statusVector
,
673 u
"isc_put_segment failed",
678 setValue
< ISC_QUAD
>(nParameterIndex
, aBlobId
, SQL_BLOB
);
681 void SAL_CALL
OPreparedStatement::setBlob(sal_Int32 nParameterIndex
,
682 const Reference
< XBlob
>& xBlob
)
684 ::osl::MutexGuard
aGuard(m_aMutex
);
685 checkDisposed(OStatementCommonBase_Base::rBHelper
.bDisposed
);
686 checkParameterIndex(nParameterIndex
);
688 #if SAL_TYPES_SIZEOFPOINTER == 8
689 isc_blob_handle aBlobHandle
= 0;
691 isc_blob_handle aBlobHandle
= nullptr;
695 openBlobForWriting(aBlobHandle
, aBlobId
);
698 const sal_Int64 nBlobLen
= xBlob
->length();
701 // Max write size is 0xFFFF == SAL_MAX_UINT16
702 sal_uInt64 nDataWritten
= 0;
703 while (sal::static_int_cast
<sal_uInt64
>(nBlobLen
) > nDataWritten
)
705 sal_uInt64 nDataRemaining
= nBlobLen
- nDataWritten
;
706 sal_uInt16 nWriteSize
= std::min(nDataRemaining
, sal_uInt64(SAL_MAX_UINT16
));
707 aErr
= isc_put_segment(m_statusVector
,
710 reinterpret_cast<const char*>(xBlob
->getBytes(nDataWritten
, nWriteSize
).getConstArray()));
711 nDataWritten
+= nWriteSize
;
718 // We need to make sure we close the Blob even if there are errors, hence evaluate
719 // errors after closing.
720 closeBlobAfterWriting(aBlobHandle
);
724 evaluateStatusVector(m_statusVector
,
725 u
"isc_put_segment failed",
730 setValue
< ISC_QUAD
>(nParameterIndex
, aBlobId
, SQL_BLOB
);
734 void SAL_CALL
OPreparedStatement::setArray( sal_Int32 nIndex
, const Reference
< XArray
>& )
736 ::osl::MutexGuard
aGuard( m_aMutex
);
737 checkDisposed(OStatementCommonBase_Base::rBHelper
.bDisposed
);
738 checkParameterIndex(nIndex
);
742 void SAL_CALL
OPreparedStatement::setRef( sal_Int32 nIndex
, const Reference
< XRef
>& )
744 ::osl::MutexGuard
aGuard( m_aMutex
);
745 checkDisposed(OStatementCommonBase_Base::rBHelper
.bDisposed
);
746 checkParameterIndex(nIndex
);
750 void SAL_CALL
OPreparedStatement::setObjectWithInfo( sal_Int32 parameterIndex
, const Any
& x
, sal_Int32 sqlType
, sal_Int32 scale
)
752 checkDisposed(OStatementCommonBase_Base::rBHelper
.bDisposed
);
753 ::osl::MutexGuard
aGuard( m_aMutex
);
756 checkParameterIndex(parameterIndex
);
757 setParameterNull(parameterIndex
, false);
759 XSQLVAR
* pVar
= m_pInSqlda
->sqlvar
+ (parameterIndex
- 1);
760 int dType
= (pVar
->sqltype
& ~1); // drop null flag
762 if(sqlType
== DataType::DECIMAL
|| sqlType
== DataType::NUMERIC
)
768 // truncate and round to 'scale' number of decimal places
769 sValue
= OUString::number( std::floor((dbValue
* pow10Integer(scale
)) + .5) / pow10Integer(scale
) );
776 // fill in the number with nulls in fractional part.
777 // We need this because e.g. 0.450 != 0.045 despite
778 // their scale is equal
779 OUStringBuffer
sBuffer(15);
780 sBuffer
.append(sValue
);
781 if(sValue
.indexOf('.') != -1) // there is a dot
783 for(sal_Int32 i
=sValue
.copy(sValue
.indexOf('.')+1).getLength(); i
<scale
;i
++)
790 for (sal_Int32 i
=0; i
<scale
; i
++)
796 sValue
= sBuffer
.makeStringAndClear();
800 setValue
< sal_Int16
>(parameterIndex
,
801 static_cast<sal_Int16
>( toNumericWithoutDecimalPlace(sValue
) ),
806 setValue
< sal_Int32
>(parameterIndex
,
807 static_cast<sal_Int32
>( toNumericWithoutDecimalPlace(sValue
) ),
811 setValue
< sal_Int64
>(parameterIndex
,
812 toNumericWithoutDecimalPlace(sValue
),
816 SAL_WARN("connectivity.firebird",
817 "No Firebird sql type found for numeric or decimal types");
818 ::dbtools::setObjectWithInfo(this,parameterIndex
,x
,sqlType
,scale
);
823 ::dbtools::setObjectWithInfo(this,parameterIndex
,x
,sqlType
,scale
);
829 void SAL_CALL
OPreparedStatement::setObjectNull( sal_Int32 nIndex
, sal_Int32
, const OUString
& )
831 ::osl::MutexGuard
aGuard( m_aMutex
);
832 checkDisposed(OStatementCommonBase_Base::rBHelper
.bDisposed
);
833 checkParameterIndex(nIndex
);
837 void SAL_CALL
OPreparedStatement::setObject( sal_Int32 nIndex
, const Any
& )
839 ::osl::MutexGuard
aGuard( m_aMutex
);
840 checkDisposed(OStatementCommonBase_Base::rBHelper
.bDisposed
);
841 checkParameterIndex(nIndex
);
844 void SAL_CALL
OPreparedStatement::setBytes(sal_Int32 nParameterIndex
,
845 const Sequence
< sal_Int8
>& xBytes
)
847 ::osl::MutexGuard
aGuard(m_aMutex
);
848 checkDisposed(OStatementCommonBase_Base::rBHelper
.bDisposed
);
849 checkParameterIndex(nParameterIndex
);
851 XSQLVAR
* pVar
= m_pInSqlda
->sqlvar
+ (nParameterIndex
- 1);
852 int dType
= (pVar
->sqltype
& ~1); // drop flag bit for now
854 if( dType
== SQL_BLOB
)
856 #if SAL_TYPES_SIZEOFPOINTER == 8
857 isc_blob_handle aBlobHandle
= 0;
859 isc_blob_handle aBlobHandle
= nullptr;
863 openBlobForWriting(aBlobHandle
, aBlobId
);
866 const sal_Int32 nBytesLen
= xBytes
.getLength();
869 // Max write size is 0xFFFF == SAL_MAX_UINT16
870 sal_uInt32 nDataWritten
= 0;
871 while (sal::static_int_cast
<sal_uInt32
>(nBytesLen
) > nDataWritten
)
873 sal_uInt32 nDataRemaining
= nBytesLen
- nDataWritten
;
874 sal_uInt16 nWriteSize
= std::min(nDataRemaining
, sal_uInt32(SAL_MAX_UINT16
));
875 aErr
= isc_put_segment(m_statusVector
,
878 reinterpret_cast<const char*>(xBytes
.getConstArray()) + nDataWritten
);
879 nDataWritten
+= nWriteSize
;
886 // We need to make sure we close the Blob even if there are errors, hence evaluate
887 // errors after closing.
888 closeBlobAfterWriting(aBlobHandle
);
892 evaluateStatusVector(m_statusVector
,
893 u
"isc_put_segment failed",
898 setValue
< ISC_QUAD
>(nParameterIndex
, aBlobId
, SQL_BLOB
);
900 else if( dType
== SQL_VARYING
)
902 setParameterNull(nParameterIndex
, false);
903 const sal_Int32 nMaxSize
= 0xFFFF;
904 Sequence
<sal_Int8
> xBytesCopy(xBytes
);
905 if (xBytesCopy
.getLength() > nMaxSize
)
907 xBytesCopy
.realloc( nMaxSize
);
909 const auto nSize
= xBytesCopy
.getLength();
910 // 8000 corresponds to value from lcl_addDefaultParameters
911 // in dbaccess/source/filter/hsqldb/createparser.cxx
915 pVar
->sqldata
= static_cast<char *>(malloc(sizeof(char) * nSize
+ 2));
917 // First 2 bytes indicate string size
918 memcpy(pVar
->sqldata
, &nSize
, 2);
920 memcpy(pVar
->sqldata
+ 2, xBytesCopy
.getConstArray(), nSize
);
922 else if( dType
== SQL_TEXT
)
924 setParameterNull(nParameterIndex
, false);
925 memcpy(pVar
->sqldata
, xBytes
.getConstArray(), xBytes
.getLength() );
926 // Fill remainder with spaces
927 memset(pVar
->sqldata
+ xBytes
.getLength(), 0, pVar
->sqllen
- xBytes
.getLength());
931 ::dbtools::throwSQLException(
932 "Incorrect type for setBytes",
933 ::dbtools::StandardSQLState::INVALID_SQL_DATA_TYPE
,
939 void SAL_CALL
OPreparedStatement::setCharacterStream( sal_Int32 nIndex
, const Reference
< css::io::XInputStream
>&, sal_Int32
)
941 ::osl::MutexGuard
aGuard( m_aMutex
);
942 checkDisposed(OStatementCommonBase_Base::rBHelper
.bDisposed
);
943 checkParameterIndex(nIndex
);
947 void SAL_CALL
OPreparedStatement::setBinaryStream( sal_Int32 nIndex
, const Reference
< css::io::XInputStream
>&, sal_Int32
)
949 ::osl::MutexGuard
aGuard( m_aMutex
);
950 checkDisposed(OStatementCommonBase_Base::rBHelper
.bDisposed
);
951 checkParameterIndex(nIndex
);
955 void SAL_CALL
OPreparedStatement::clearParameters( )
959 // ---- Batch methods -- unsupported -----------------------------------------
960 void SAL_CALL
OPreparedStatement::clearBatch()
965 void SAL_CALL
OPreparedStatement::addBatch()
967 // Unsupported by firebird
970 Sequence
< sal_Int32
> SAL_CALL
OPreparedStatement::executeBatch()
972 // Unsupported by firebird
973 return Sequence
< sal_Int32
>();
976 void OPreparedStatement::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle
,const Any
& rValue
)
980 case PROPERTY_ID_RESULTSETCONCURRENCY
:
982 case PROPERTY_ID_RESULTSETTYPE
:
984 case PROPERTY_ID_FETCHDIRECTION
:
986 case PROPERTY_ID_USEBOOKMARKS
:
989 OStatementCommonBase::setFastPropertyValue_NoBroadcast(nHandle
,rValue
);
993 void OPreparedStatement::checkParameterIndex(sal_Int32 nParameterIndex
)
996 if ((nParameterIndex
== 0) || (nParameterIndex
> m_pInSqlda
->sqld
))
998 ::dbtools::throwSQLException(
999 "No column " + OUString::number(nParameterIndex
),
1000 ::dbtools::StandardSQLState::COLUMN_NOT_FOUND
,
1005 void OPreparedStatement::setParameterNull(sal_Int32 nParameterIndex
,
1008 XSQLVAR
* pVar
= m_pInSqlda
->sqlvar
+ (nParameterIndex
- 1);
1018 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */