1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 "mysqlc_general.hxx"
21 #include "mysqlc_prepared_resultset.hxx"
22 #include "mysqlc_preparedstatement.hxx"
23 #include "mysqlc_propertyids.hxx"
24 #include "mysqlc_resultsetmetadata.hxx"
26 #include <sal/log.hxx>
28 #include <com/sun/star/lang/DisposedException.hpp>
29 #include <com/sun/star/sdbc/DataType.hpp>
30 #include <cppuhelper/typeprovider.hxx>
34 using namespace connectivity::mysqlc
;
35 using namespace com::sun::star::uno
;
36 using namespace com::sun::star::lang
;
37 using namespace com::sun::star::beans
;
38 using namespace com::sun::star::sdbc
;
39 using namespace com::sun::star::container
;
40 using namespace com::sun::star::io
;
41 using namespace com::sun::star::util
;
42 using ::osl::MutexGuard
;
44 OUString
OPreparedStatement::getImplementationName()
46 return OUString("com.sun.star.sdbcx.mysqlc.PreparedStatement");
49 css::uno::Sequence
<OUString
> OPreparedStatement::getSupportedServiceNames()
51 css::uno::Sequence
<OUString
> s(1);
52 s
[0] = "com.sun.star.sdbc.PreparedStatement";
56 sal_Bool
OPreparedStatement::supportsService(OUString
const& ServiceName
)
58 return cppu::supportsService(this, ServiceName
);
61 OPreparedStatement::OPreparedStatement(OConnection
* _pConnection
, MYSQL_STMT
* pStmt
)
62 : OCommonStatement(_pConnection
)
65 m_paramCount
= mysql_stmt_param_count(m_pStmt
);
66 m_binds
.reserve(m_paramCount
);
67 m_bindMetas
.reserve(m_paramCount
);
68 for (unsigned i
= 0; i
< m_paramCount
; ++i
)
71 memset(&bind
, 0, sizeof(MYSQL_BIND
));
72 m_binds
.push_back(bind
);
73 m_bindMetas
.push_back(BindMetaData
{});
74 m_binds
.back().is_null
= &m_bindMetas
.back().is_null
;
75 m_binds
.back().length
= &m_bindMetas
.back().length
;
76 m_binds
.back().buffer
= nullptr;
80 OPreparedStatement::~OPreparedStatement() {}
82 void SAL_CALL
OPreparedStatement::acquire() throw() { OCommonStatement::acquire(); }
84 void SAL_CALL
OPreparedStatement::release() throw() { OCommonStatement::release(); }
86 Any SAL_CALL
OPreparedStatement::queryInterface(const Type
& rType
)
88 Any aRet
= OCommonStatement::queryInterface(rType
);
91 aRet
= OPreparedStatement_BASE::queryInterface(rType
);
96 Sequence
<Type
> SAL_CALL
OPreparedStatement::getTypes()
98 return concatSequences(OPreparedStatement_BASE::getTypes(), OCommonStatement::getTypes());
101 Reference
<XResultSetMetaData
> SAL_CALL
OPreparedStatement::getMetaData()
103 MutexGuard
aGuard(m_aMutex
);
104 checkDisposed(OPreparedStatement::rBHelper
.bDisposed
);
106 if (!m_xMetaData
.is())
108 MYSQL_RES
* pRes
= mysql_stmt_result_metadata(m_pStmt
);
109 // TODO warning or error if no meta data.
110 m_xMetaData
= new OResultSetMetaData(*m_xConnection
, pRes
);
115 void SAL_CALL
OPreparedStatement::close()
117 MutexGuard
aGuard(m_aMutex
);
118 checkDisposed(OPreparedStatement::rBHelper
.bDisposed
);
120 if (mysql_stmt_close(m_pStmt
))
122 SAL_WARN("connectivity.mysqlc", "failed to close mysql prepared statement");
124 m_pStmt
= nullptr; // it's deallocated already
127 OCommonStatement::close();
130 sal_Bool SAL_CALL
OPreparedStatement::execute()
132 MutexGuard
aGuard(m_aMutex
);
133 checkDisposed(OPreparedStatement::rBHelper
.bDisposed
);
135 if (!m_binds
.empty() && mysql_stmt_bind_param(m_pStmt
, m_binds
.data()))
137 MYSQL
* pMysql
= m_xConnection
->getMysqlConnection();
138 mysqlc_sdbc_driver::throwSQLExceptionWithMsg(mysql_stmt_error(m_pStmt
), mysql_errno(pMysql
),
139 *this, m_xConnection
->getConnectionEncoding());
142 int nFail
= mysql_stmt_execute(m_pStmt
);
145 MYSQL
* pMysql
= m_xConnection
->getMysqlConnection();
146 mysqlc_sdbc_driver::throwSQLExceptionWithMsg(mysql_stmt_error(m_pStmt
), mysql_errno(pMysql
),
147 *this, m_xConnection
->getConnectionEncoding());
153 sal_Int32 SAL_CALL
OPreparedStatement::executeUpdate()
155 MutexGuard
aGuard(m_aMutex
);
156 checkDisposed(OPreparedStatement::rBHelper
.bDisposed
);
158 if (!m_binds
.empty() && mysql_stmt_bind_param(m_pStmt
, m_binds
.data()))
160 MYSQL
* pMysql
= m_xConnection
->getMysqlConnection();
161 mysqlc_sdbc_driver::throwSQLExceptionWithMsg(mysql_stmt_error(m_pStmt
), mysql_errno(pMysql
),
162 *this, m_xConnection
->getConnectionEncoding());
165 int nFail
= mysql_stmt_execute(m_pStmt
);
169 MYSQL
* pMysql
= m_xConnection
->getMysqlConnection();
170 mysqlc_sdbc_driver::throwSQLExceptionWithMsg(mysql_stmt_error(m_pStmt
), mysql_errno(pMysql
),
171 *this, m_xConnection
->getConnectionEncoding());
174 sal_Int32 affectedRows
= mysql_stmt_affected_rows(m_pStmt
);
178 void SAL_CALL
OPreparedStatement::setString(sal_Int32 parameter
, const OUString
& x
)
180 MutexGuard
aGuard(m_aMutex
);
181 checkDisposed(OPreparedStatement::rBHelper
.bDisposed
);
182 checkParameterIndex(parameter
);
184 OString
stringie(OUStringToOString(x
, m_xConnection
->getConnectionEncoding()));
185 const sal_Int32 nIndex
= parameter
- 1;
186 m_binds
[nIndex
].buffer_type
= MYSQL_TYPE_STRING
;
187 mysqlc_sdbc_driver::resetSqlVar(&m_binds
[nIndex
].buffer
, stringie
.getStr(), MYSQL_TYPE_STRING
,
188 stringie
.getLength());
189 m_bindMetas
[nIndex
].is_null
= 0;
190 m_bindMetas
[nIndex
].length
= stringie
.getLength();
193 Reference
<XConnection
> SAL_CALL
OPreparedStatement::getConnection()
195 MutexGuard
aGuard(m_aMutex
);
196 checkDisposed(OPreparedStatement::rBHelper
.bDisposed
);
198 return m_xConnection
.get();
201 Reference
<XResultSet
> SAL_CALL
OPreparedStatement::executeQuery()
203 MutexGuard
aGuard(m_aMutex
);
204 checkDisposed(OPreparedStatement::rBHelper
.bDisposed
);
206 if (!m_binds
.empty() && mysql_stmt_bind_param(m_pStmt
, m_binds
.data()))
208 MYSQL
* pMysql
= m_xConnection
->getMysqlConnection();
209 mysqlc_sdbc_driver::throwSQLExceptionWithMsg(mysql_stmt_error(m_pStmt
), mysql_errno(pMysql
),
210 *this, m_xConnection
->getConnectionEncoding());
213 int nFail
= mysql_stmt_execute(m_pStmt
);
217 MYSQL
* pMysql
= m_xConnection
->getMysqlConnection();
218 mysqlc_sdbc_driver::throwSQLExceptionWithMsg(mysql_stmt_error(m_pStmt
), mysql_errno(pMysql
),
219 *this, m_xConnection
->getConnectionEncoding());
222 Reference
<XResultSet
> xResultSet
= new OPreparedResultSet(*m_xConnection
, this, m_pStmt
);
226 void SAL_CALL
OPreparedStatement::setBoolean(sal_Int32 parameter
, sal_Bool x
)
228 MutexGuard
aGuard(m_aMutex
);
229 checkDisposed(OPreparedStatement::rBHelper
.bDisposed
);
230 checkParameterIndex(parameter
);
232 const sal_Int32 nIndex
= parameter
- 1;
233 m_binds
[nIndex
].buffer_type
= MYSQL_TYPE_TINY
;
234 mysqlc_sdbc_driver::resetSqlVar(&m_binds
[nIndex
].buffer
, &x
, MYSQL_TYPE_TINY
);
235 m_bindMetas
[nIndex
].is_null
= 0;
238 void SAL_CALL
OPreparedStatement::setByte(sal_Int32 parameter
, sal_Int8 x
)
240 MutexGuard
aGuard(m_aMutex
);
241 checkDisposed(OPreparedStatement::rBHelper
.bDisposed
);
242 checkParameterIndex(parameter
);
244 const sal_Int32 nIndex
= parameter
- 1;
245 m_binds
[nIndex
].buffer_type
= MYSQL_TYPE_TINY
;
246 mysqlc_sdbc_driver::resetSqlVar(&m_binds
[nIndex
].buffer
, &x
, MYSQL_TYPE_TINY
);
247 m_bindMetas
[nIndex
].is_null
= 0;
250 void SAL_CALL
OPreparedStatement::setDate(sal_Int32 parameter
, const Date
& aData
)
252 MutexGuard
aGuard(m_aMutex
);
253 checkDisposed(OPreparedStatement::rBHelper
.bDisposed
);
254 checkParameterIndex(parameter
);
258 my_time
.year
= aData
.Year
;
259 my_time
.month
= aData
.Month
;
260 my_time
.day
= aData
.Day
;
262 const sal_Int32 nIndex
= parameter
- 1;
263 m_binds
[nIndex
].buffer_type
= MYSQL_TYPE_DATE
;
264 mysqlc_sdbc_driver::resetSqlVar(&m_binds
[nIndex
].buffer
, &my_time
, MYSQL_TYPE_DATE
);
265 m_bindMetas
[nIndex
].is_null
= 0;
268 void SAL_CALL
OPreparedStatement::setTime(sal_Int32 parameter
, const Time
& aVal
)
270 MutexGuard
aGuard(m_aMutex
);
271 checkDisposed(OPreparedStatement::rBHelper
.bDisposed
);
272 checkParameterIndex(parameter
);
276 my_time
.hour
= aVal
.Hours
;
277 my_time
.minute
= aVal
.Minutes
;
278 my_time
.second
= aVal
.Seconds
;
280 const sal_Int32 nIndex
= parameter
- 1;
281 m_binds
[nIndex
].buffer_type
= MYSQL_TYPE_TIME
;
282 mysqlc_sdbc_driver::resetSqlVar(&m_binds
[nIndex
].buffer
, &my_time
, MYSQL_TYPE_TIME
);
283 m_bindMetas
[nIndex
].is_null
= 0;
286 void SAL_CALL
OPreparedStatement::setTimestamp(sal_Int32 parameter
, const DateTime
& aVal
)
288 MutexGuard
aGuard(m_aMutex
);
289 checkDisposed(OPreparedStatement::rBHelper
.bDisposed
);
290 checkParameterIndex(parameter
);
293 memset(&my_time
, 0, sizeof(MYSQL_TIME
));
295 my_time
.hour
= aVal
.Hours
;
296 my_time
.minute
= aVal
.Minutes
;
297 my_time
.second
= aVal
.Seconds
;
298 my_time
.year
= aVal
.Year
;
299 my_time
.month
= aVal
.Month
;
300 my_time
.day
= aVal
.Day
;
302 const sal_Int32 nIndex
= parameter
- 1;
303 m_binds
[nIndex
].buffer_type
= MYSQL_TYPE_DATETIME
;
304 mysqlc_sdbc_driver::resetSqlVar(&m_binds
[nIndex
].buffer
, &my_time
, MYSQL_TYPE_DATETIME
);
305 m_bindMetas
[nIndex
].is_null
= 0;
308 void SAL_CALL
OPreparedStatement::setDouble(sal_Int32 parameter
, double x
)
310 MutexGuard
aGuard(m_aMutex
);
311 checkDisposed(OPreparedStatement::rBHelper
.bDisposed
);
312 checkParameterIndex(parameter
);
314 const sal_Int32 nIndex
= parameter
- 1;
315 m_binds
[nIndex
].buffer_type
= MYSQL_TYPE_DOUBLE
;
316 mysqlc_sdbc_driver::resetSqlVar(&m_binds
[nIndex
].buffer
, &x
, MYSQL_TYPE_DOUBLE
);
317 m_bindMetas
[nIndex
].is_null
= 0;
320 void SAL_CALL
OPreparedStatement::setFloat(sal_Int32 parameter
, float x
)
322 MutexGuard
aGuard(m_aMutex
);
323 checkDisposed(OPreparedStatement::rBHelper
.bDisposed
);
324 checkParameterIndex(parameter
);
326 const sal_Int32 nIndex
= parameter
- 1;
327 m_binds
[nIndex
].buffer_type
= MYSQL_TYPE_FLOAT
;
328 mysqlc_sdbc_driver::resetSqlVar(&m_binds
[nIndex
].buffer
, &x
, MYSQL_TYPE_FLOAT
);
329 m_bindMetas
[nIndex
].is_null
= 0;
332 void SAL_CALL
OPreparedStatement::setInt(sal_Int32 parameter
, sal_Int32 x
)
334 MutexGuard
aGuard(m_aMutex
);
335 checkDisposed(OPreparedStatement::rBHelper
.bDisposed
);
336 checkParameterIndex(parameter
);
338 const sal_Int32 nIndex
= parameter
- 1;
339 m_binds
[nIndex
].buffer_type
= MYSQL_TYPE_LONG
;
340 mysqlc_sdbc_driver::resetSqlVar(&m_binds
[nIndex
].buffer
, &x
, MYSQL_TYPE_LONG
);
341 m_bindMetas
[nIndex
].is_null
= 0;
344 void SAL_CALL
OPreparedStatement::setLong(sal_Int32 parameter
, sal_Int64 aVal
)
346 MutexGuard
aGuard(m_aMutex
);
347 checkDisposed(OPreparedStatement::rBHelper
.bDisposed
);
348 checkParameterIndex(parameter
);
350 const sal_Int32 nIndex
= parameter
- 1;
351 m_binds
[nIndex
].buffer_type
= MYSQL_TYPE_LONGLONG
;
352 mysqlc_sdbc_driver::resetSqlVar(&m_binds
[nIndex
].buffer
, &aVal
, MYSQL_TYPE_LONGLONG
);
353 m_bindMetas
[nIndex
].is_null
= 0;
356 void SAL_CALL
OPreparedStatement::setNull(sal_Int32 parameter
, sal_Int32
/*sqlType*/)
358 MutexGuard
aGuard(m_aMutex
);
359 checkDisposed(OPreparedStatement::rBHelper
.bDisposed
);
360 checkParameterIndex(parameter
);
362 const sal_Int32 nIndex
= parameter
- 1;
363 m_bindMetas
[nIndex
].is_null
= 1;
364 free(m_binds
[nIndex
].buffer
);
365 m_binds
[nIndex
].buffer
= nullptr;
368 void SAL_CALL
OPreparedStatement::setClob(sal_Int32 parameter
, const Reference
<XClob
>& /* x */)
370 MutexGuard
aGuard(m_aMutex
);
371 checkDisposed(OPreparedStatement::rBHelper
.bDisposed
);
372 checkParameterIndex(parameter
);
374 mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedStatement::setClob", *this);
377 void SAL_CALL
OPreparedStatement::setBlob(sal_Int32 parameter
, const Reference
<XBlob
>& /* x */)
379 MutexGuard
aGuard(m_aMutex
);
380 checkDisposed(OPreparedStatement::rBHelper
.bDisposed
);
381 checkParameterIndex(parameter
);
383 mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedStatement::setBlob", *this);
386 void SAL_CALL
OPreparedStatement::setArray(sal_Int32 parameter
, const Reference
<XArray
>& /* x */)
388 MutexGuard
aGuard(m_aMutex
);
389 checkDisposed(OPreparedStatement::rBHelper
.bDisposed
);
390 checkParameterIndex(parameter
);
392 mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedStatement::setArray", *this);
395 void SAL_CALL
OPreparedStatement::setRef(sal_Int32 parameter
, const Reference
<XRef
>& /* x */)
397 MutexGuard
aGuard(m_aMutex
);
398 checkDisposed(OPreparedStatement::rBHelper
.bDisposed
);
399 checkParameterIndex(parameter
);
401 mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedStatement::setRef", *this);
404 void SAL_CALL
OPreparedStatement::setObjectWithInfo(sal_Int32 parameterIndex
, const Any
& value
,
405 sal_Int32 targetSqlType
, sal_Int32
/* scale */)
407 checkDisposed(OPreparedStatement::rBHelper
.bDisposed
);
408 MutexGuard
aGuard(m_aMutex
);
409 checkParameterIndex(parameterIndex
);
411 const sal_Int32 nIndex
= parameterIndex
- 1;
412 if (!value
.hasValue())
414 free(m_binds
[nIndex
].buffer
);
415 m_binds
[nIndex
].buffer
= nullptr;
416 m_bindMetas
[parameterIndex
- 1].is_null
= 1;
420 switch (targetSqlType
)
422 case DataType::DECIMAL
:
423 case DataType::NUMERIC
:
427 if (value
>>= nValue
)
429 setDouble(parameterIndex
, nValue
);
432 else if (value
>>= sValue
)
435 = OUStringToOString(sValue
, getOwnConnection()->getConnectionEncoding());
436 std::stringstream sStream
{ sAscii
.getStr() };
438 m_binds
[nIndex
].buffer_type
= MYSQL_TYPE_DOUBLE
;
439 mysqlc_sdbc_driver::resetSqlVar(&m_binds
[nIndex
].buffer
, &nValue
, MYSQL_TYPE_DOUBLE
,
441 m_bindMetas
[nIndex
].is_null
= 0;
451 mysqlc_sdbc_driver::throwInvalidArgumentException(
452 "OPreparedStatement::setObjectWithInfo", *this);
457 void SAL_CALL
OPreparedStatement::setObjectNull(sal_Int32 parameter
, sal_Int32
/* sqlType */,
458 const OUString
& /* typeName */)
460 MutexGuard
aGuard(m_aMutex
);
461 checkDisposed(OPreparedStatement::rBHelper
.bDisposed
);
462 checkParameterIndex(parameter
);
464 mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedStatement::setObjectNull",
468 void SAL_CALL
OPreparedStatement::setObject(sal_Int32 parameter
, const Any
& /* x */)
470 MutexGuard
aGuard(m_aMutex
);
471 checkDisposed(OPreparedStatement::rBHelper
.bDisposed
);
472 checkParameterIndex(parameter
);
474 mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedStatement::setObject", *this);
477 void SAL_CALL
OPreparedStatement::setShort(sal_Int32 parameter
, sal_Int16 x
)
479 MutexGuard
aGuard(m_aMutex
);
480 checkDisposed(OPreparedStatement::rBHelper
.bDisposed
);
481 checkParameterIndex(parameter
);
483 const sal_Int32 nIndex
= parameter
- 1;
484 m_binds
[nIndex
].buffer_type
= MYSQL_TYPE_SHORT
;
485 mysqlc_sdbc_driver::resetSqlVar(&m_binds
[nIndex
].buffer
, &x
, MYSQL_TYPE_SHORT
);
486 m_bindMetas
[nIndex
].is_null
= 0;
489 void SAL_CALL
OPreparedStatement::setBytes(sal_Int32 parameter
, const Sequence
<sal_Int8
>& x
)
491 MutexGuard
aGuard(m_aMutex
);
492 checkDisposed(OPreparedStatement::rBHelper
.bDisposed
);
493 checkParameterIndex(parameter
);
495 const sal_Int32 nIndex
= parameter
- 1;
496 m_binds
[nIndex
].buffer_type
= MYSQL_TYPE_BLOB
; // FIXME
497 mysqlc_sdbc_driver::resetSqlVar(&m_binds
[nIndex
].buffer
, &x
, MYSQL_TYPE_BLOB
);
498 m_bindMetas
[nIndex
].is_null
= 0;
501 void SAL_CALL
OPreparedStatement::setCharacterStream(sal_Int32 parameter
,
502 const Reference
<XInputStream
>& /* x */,
503 sal_Int32
/* length */)
505 MutexGuard
aGuard(m_aMutex
);
506 checkDisposed(OPreparedStatement::rBHelper
.bDisposed
);
507 checkParameterIndex(parameter
);
509 mysqlc_sdbc_driver::throwFeatureNotImplementedException(
510 "OPreparedStatement::setCharacterStream", *this);
513 void SAL_CALL
OPreparedStatement::setBinaryStream(sal_Int32 parameter
,
514 const Reference
<XInputStream
>& /* x */,
515 sal_Int32
/* length */)
517 MutexGuard
aGuard(m_aMutex
);
518 checkDisposed(OPreparedStatement::rBHelper
.bDisposed
);
519 checkParameterIndex(parameter
);
521 mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedStatement::setBinaryStream",
525 void SAL_CALL
OPreparedStatement::clearParameters()
527 MutexGuard
aGuard(m_aMutex
);
528 checkDisposed(OPreparedStatement::rBHelper
.bDisposed
);
530 for (size_t i
= 0; i
< m_binds
.size(); ++i
)
532 m_bindMetas
[i
].is_null
= 1;
533 free(m_binds
[i
].buffer
);
534 m_binds
[i
].buffer
= nullptr;
538 void SAL_CALL
OPreparedStatement::clearBatch()
540 mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedStatement::clearBatch",
544 void SAL_CALL
OPreparedStatement::addBatch()
546 mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedStatement::addBatch", *this);
549 Sequence
<sal_Int32
> SAL_CALL
OPreparedStatement::executeBatch()
551 Sequence
<sal_Int32
> aRet
= Sequence
<sal_Int32
>();
555 void OPreparedStatement::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle
, const Any
& rValue
)
559 case PROPERTY_ID_RESULTSETCONCURRENCY
:
561 case PROPERTY_ID_RESULTSETTYPE
:
563 case PROPERTY_ID_FETCHDIRECTION
:
565 case PROPERTY_ID_USEBOOKMARKS
:
568 /* XXX: Recursion ?? */
569 OPreparedStatement::setFastPropertyValue_NoBroadcast(nHandle
, rValue
);
573 void OPreparedStatement::checkParameterIndex(sal_Int32 column
)
575 if (column
< 1 || column
> static_cast<sal_Int32
>(m_paramCount
))
577 throw SQLException("Parameter index out of range", *this, OUString(), 1, Any());
581 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */