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/sdbc/DataType.hpp>
32 using namespace connectivity::mysqlc
;
33 using namespace com::sun::star::uno
;
34 using namespace com::sun::star::lang
;
35 using namespace com::sun::star::beans
;
36 using namespace com::sun::star::sdbc
;
37 using namespace com::sun::star::container
;
38 using namespace com::sun::star::io
;
39 using namespace com::sun::star::util
;
40 using ::osl::MutexGuard
;
42 OUString
OPreparedStatement::getImplementationName()
44 return "com.sun.star.sdbcx.mysqlc.PreparedStatement";
47 css::uno::Sequence
<OUString
> OPreparedStatement::getSupportedServiceNames()
49 return { "com.sun.star.sdbc.PreparedStatement" };
52 sal_Bool
OPreparedStatement::supportsService(OUString
const& ServiceName
)
54 return cppu::supportsService(this, ServiceName
);
57 OPreparedStatement::OPreparedStatement(OConnection
* _pConnection
, MYSQL_STMT
* pStmt
)
58 : OCommonStatement(_pConnection
)
61 m_paramCount
= mysql_stmt_param_count(m_pStmt
);
62 m_binds
.reserve(m_paramCount
);
63 m_bindMetas
.reserve(m_paramCount
);
64 for (unsigned i
= 0; i
< m_paramCount
; ++i
)
66 m_binds
.push_back(MYSQL_BIND
{});
67 m_bindMetas
.push_back(BindMetaData
{});
68 m_binds
.back().is_null
= &m_bindMetas
.back().is_null
;
69 m_binds
.back().length
= &m_bindMetas
.back().length
;
70 m_binds
.back().buffer
= nullptr;
74 OPreparedStatement::~OPreparedStatement() {}
76 void SAL_CALL
OPreparedStatement::acquire() noexcept
{ OCommonStatement::acquire(); }
78 void SAL_CALL
OPreparedStatement::release() noexcept
{ OCommonStatement::release(); }
80 Any SAL_CALL
OPreparedStatement::queryInterface(const Type
& rType
)
82 Any aRet
= OCommonStatement::queryInterface(rType
);
85 aRet
= OPreparedStatement_BASE::queryInterface(rType
);
90 Sequence
<Type
> SAL_CALL
OPreparedStatement::getTypes()
92 return concatSequences(OPreparedStatement_BASE::getTypes(), OCommonStatement::getTypes());
95 Reference
<XResultSetMetaData
> SAL_CALL
OPreparedStatement::getMetaData()
97 MutexGuard
aGuard(m_aMutex
);
98 checkDisposed(rBHelper
.bDisposed
);
100 if (!m_xMetaData
.is())
102 MYSQL_RES
* pRes
= mysql_stmt_result_metadata(m_pStmt
);
103 // TODO warning or error if no meta data.
104 m_xMetaData
= new OResultSetMetaData(*m_xConnection
, pRes
);
109 void SAL_CALL
OPreparedStatement::close()
111 MutexGuard
aGuard(m_aMutex
);
112 checkDisposed(rBHelper
.bDisposed
);
114 if (mysql_stmt_close(m_pStmt
))
116 SAL_WARN("connectivity.mysqlc", "failed to close mysql prepared statement");
118 m_pStmt
= nullptr; // it's deallocated already
121 OCommonStatement::close();
124 sal_Bool SAL_CALL
OPreparedStatement::execute()
126 MutexGuard
aGuard(m_aMutex
);
127 checkDisposed(rBHelper
.bDisposed
);
129 if (!m_binds
.empty() && mysql_stmt_bind_param(m_pStmt
, m_binds
.data()))
131 MYSQL
* pMysql
= m_xConnection
->getMysqlConnection();
132 mysqlc_sdbc_driver::throwSQLExceptionWithMsg(mysql_stmt_error(m_pStmt
),
133 mysql_sqlstate(pMysql
), mysql_errno(pMysql
),
134 *this, m_xConnection
->getConnectionEncoding());
137 int nFail
= mysql_stmt_execute(m_pStmt
);
140 MYSQL
* pMysql
= m_xConnection
->getMysqlConnection();
141 mysqlc_sdbc_driver::throwSQLExceptionWithMsg(mysql_stmt_error(m_pStmt
),
142 mysql_sqlstate(pMysql
), mysql_errno(pMysql
),
143 *this, m_xConnection
->getConnectionEncoding());
149 sal_Int32 SAL_CALL
OPreparedStatement::executeUpdate()
151 MutexGuard
aGuard(m_aMutex
);
152 checkDisposed(rBHelper
.bDisposed
);
154 if (!m_binds
.empty() && mysql_stmt_bind_param(m_pStmt
, m_binds
.data()))
156 MYSQL
* pMysql
= m_xConnection
->getMysqlConnection();
157 mysqlc_sdbc_driver::throwSQLExceptionWithMsg(mysql_stmt_error(m_pStmt
),
158 mysql_sqlstate(pMysql
), mysql_errno(pMysql
),
159 *this, m_xConnection
->getConnectionEncoding());
162 int nFail
= mysql_stmt_execute(m_pStmt
);
166 MYSQL
* pMysql
= m_xConnection
->getMysqlConnection();
167 mysqlc_sdbc_driver::throwSQLExceptionWithMsg(mysql_stmt_error(m_pStmt
),
168 mysql_sqlstate(pMysql
), mysql_errno(pMysql
),
169 *this, m_xConnection
->getConnectionEncoding());
172 sal_Int32 affectedRows
= mysql_stmt_affected_rows(m_pStmt
);
176 void SAL_CALL
OPreparedStatement::setString(sal_Int32 parameter
, const OUString
& x
)
178 MutexGuard
aGuard(m_aMutex
);
179 checkDisposed(rBHelper
.bDisposed
);
180 checkParameterIndex(parameter
);
182 OString
stringie(OUStringToOString(x
, m_xConnection
->getConnectionEncoding()));
183 const sal_Int32 nIndex
= parameter
- 1;
184 m_binds
[nIndex
].buffer_type
= MYSQL_TYPE_STRING
;
185 mysqlc_sdbc_driver::resetSqlVar(&m_binds
[nIndex
].buffer
, stringie
.getStr(), MYSQL_TYPE_STRING
,
186 stringie
.getLength());
187 m_bindMetas
[nIndex
].is_null
= false;
188 m_bindMetas
[nIndex
].length
= stringie
.getLength();
191 Reference
<XConnection
> SAL_CALL
OPreparedStatement::getConnection()
193 MutexGuard
aGuard(m_aMutex
);
194 checkDisposed(rBHelper
.bDisposed
);
196 return m_xConnection
;
199 Reference
<XResultSet
> SAL_CALL
OPreparedStatement::executeQuery()
201 MutexGuard
aGuard(m_aMutex
);
202 checkDisposed(rBHelper
.bDisposed
);
204 if (!m_binds
.empty() && mysql_stmt_bind_param(m_pStmt
, m_binds
.data()))
206 MYSQL
* pMysql
= m_xConnection
->getMysqlConnection();
207 mysqlc_sdbc_driver::throwSQLExceptionWithMsg(mysql_stmt_error(m_pStmt
),
208 mysql_sqlstate(pMysql
), mysql_errno(pMysql
),
209 *this, m_xConnection
->getConnectionEncoding());
212 int nFail
= mysql_stmt_execute(m_pStmt
);
216 MYSQL
* pMysql
= m_xConnection
->getMysqlConnection();
217 mysqlc_sdbc_driver::throwSQLExceptionWithMsg(mysql_stmt_error(m_pStmt
),
218 mysql_sqlstate(pMysql
), 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(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
= false;
238 void SAL_CALL
OPreparedStatement::setByte(sal_Int32 parameter
, sal_Int8 x
)
240 MutexGuard
aGuard(m_aMutex
);
241 checkDisposed(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
= false;
250 void SAL_CALL
OPreparedStatement::setDate(sal_Int32 parameter
, const Date
& aData
)
252 MutexGuard
aGuard(m_aMutex
);
253 checkDisposed(rBHelper
.bDisposed
);
254 checkParameterIndex(parameter
);
256 MYSQL_TIME my_time
= {};
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
= false;
268 void SAL_CALL
OPreparedStatement::setTime(sal_Int32 parameter
, const Time
& aVal
)
270 MutexGuard
aGuard(m_aMutex
);
271 checkDisposed(rBHelper
.bDisposed
);
272 checkParameterIndex(parameter
);
274 MYSQL_TIME my_time
= {};
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
= false;
286 void SAL_CALL
OPreparedStatement::setTimestamp(sal_Int32 parameter
, const DateTime
& aVal
)
288 MutexGuard
aGuard(m_aMutex
);
289 checkDisposed(rBHelper
.bDisposed
);
290 checkParameterIndex(parameter
);
292 MYSQL_TIME my_time
= {};
294 my_time
.hour
= aVal
.Hours
;
295 my_time
.minute
= aVal
.Minutes
;
296 my_time
.second
= aVal
.Seconds
;
297 my_time
.year
= aVal
.Year
;
298 my_time
.month
= aVal
.Month
;
299 my_time
.day
= aVal
.Day
;
301 const sal_Int32 nIndex
= parameter
- 1;
302 m_binds
[nIndex
].buffer_type
= MYSQL_TYPE_DATETIME
;
303 mysqlc_sdbc_driver::resetSqlVar(&m_binds
[nIndex
].buffer
, &my_time
, MYSQL_TYPE_DATETIME
);
304 m_bindMetas
[nIndex
].is_null
= false;
307 void SAL_CALL
OPreparedStatement::setDouble(sal_Int32 parameter
, double x
)
309 MutexGuard
aGuard(m_aMutex
);
310 checkDisposed(rBHelper
.bDisposed
);
311 checkParameterIndex(parameter
);
313 const sal_Int32 nIndex
= parameter
- 1;
314 m_binds
[nIndex
].buffer_type
= MYSQL_TYPE_DOUBLE
;
315 mysqlc_sdbc_driver::resetSqlVar(&m_binds
[nIndex
].buffer
, &x
, MYSQL_TYPE_DOUBLE
);
316 m_bindMetas
[nIndex
].is_null
= false;
319 void SAL_CALL
OPreparedStatement::setFloat(sal_Int32 parameter
, float x
)
321 MutexGuard
aGuard(m_aMutex
);
322 checkDisposed(rBHelper
.bDisposed
);
323 checkParameterIndex(parameter
);
325 const sal_Int32 nIndex
= parameter
- 1;
326 m_binds
[nIndex
].buffer_type
= MYSQL_TYPE_FLOAT
;
327 mysqlc_sdbc_driver::resetSqlVar(&m_binds
[nIndex
].buffer
, &x
, MYSQL_TYPE_FLOAT
);
328 m_bindMetas
[nIndex
].is_null
= false;
331 void SAL_CALL
OPreparedStatement::setInt(sal_Int32 parameter
, sal_Int32 x
)
333 MutexGuard
aGuard(m_aMutex
);
334 checkDisposed(rBHelper
.bDisposed
);
335 checkParameterIndex(parameter
);
337 const sal_Int32 nIndex
= parameter
- 1;
338 m_binds
[nIndex
].buffer_type
= MYSQL_TYPE_LONG
;
339 mysqlc_sdbc_driver::resetSqlVar(&m_binds
[nIndex
].buffer
, &x
, MYSQL_TYPE_LONG
);
340 m_bindMetas
[nIndex
].is_null
= false;
343 void SAL_CALL
OPreparedStatement::setLong(sal_Int32 parameter
, sal_Int64 aVal
)
345 MutexGuard
aGuard(m_aMutex
);
346 checkDisposed(rBHelper
.bDisposed
);
347 checkParameterIndex(parameter
);
349 const sal_Int32 nIndex
= parameter
- 1;
350 m_binds
[nIndex
].buffer_type
= MYSQL_TYPE_LONGLONG
;
351 mysqlc_sdbc_driver::resetSqlVar(&m_binds
[nIndex
].buffer
, &aVal
, MYSQL_TYPE_LONGLONG
);
352 m_bindMetas
[nIndex
].is_null
= false;
355 void SAL_CALL
OPreparedStatement::setNull(sal_Int32 parameter
, sal_Int32
/*sqlType*/)
357 MutexGuard
aGuard(m_aMutex
);
358 checkDisposed(rBHelper
.bDisposed
);
359 checkParameterIndex(parameter
);
361 const sal_Int32 nIndex
= parameter
- 1;
362 m_bindMetas
[nIndex
].is_null
= true;
363 free(m_binds
[nIndex
].buffer
);
364 m_binds
[nIndex
].buffer
= nullptr;
367 void SAL_CALL
OPreparedStatement::setClob(sal_Int32 parameter
, const Reference
<XClob
>& /* x */)
369 MutexGuard
aGuard(m_aMutex
);
370 checkDisposed(rBHelper
.bDisposed
);
371 checkParameterIndex(parameter
);
373 mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedStatement::setClob", *this);
376 void SAL_CALL
OPreparedStatement::setBlob(sal_Int32 parameter
, const Reference
<XBlob
>& /* x */)
378 MutexGuard
aGuard(m_aMutex
);
379 checkDisposed(rBHelper
.bDisposed
);
380 checkParameterIndex(parameter
);
382 mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedStatement::setBlob", *this);
385 void SAL_CALL
OPreparedStatement::setArray(sal_Int32 parameter
, const Reference
<XArray
>& /* x */)
387 MutexGuard
aGuard(m_aMutex
);
388 checkDisposed(rBHelper
.bDisposed
);
389 checkParameterIndex(parameter
);
391 mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedStatement::setArray", *this);
394 void SAL_CALL
OPreparedStatement::setRef(sal_Int32 parameter
, const Reference
<XRef
>& /* x */)
396 MutexGuard
aGuard(m_aMutex
);
397 checkDisposed(rBHelper
.bDisposed
);
398 checkParameterIndex(parameter
);
400 mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedStatement::setRef", *this);
403 void SAL_CALL
OPreparedStatement::setObjectWithInfo(sal_Int32 parameterIndex
, const Any
& value
,
404 sal_Int32 targetSqlType
, sal_Int32
/* scale */)
406 checkDisposed(rBHelper
.bDisposed
);
407 MutexGuard
aGuard(m_aMutex
);
408 checkParameterIndex(parameterIndex
);
410 const sal_Int32 nIndex
= parameterIndex
- 1;
411 if (!value
.hasValue())
413 free(m_binds
[nIndex
].buffer
);
414 m_binds
[nIndex
].buffer
= nullptr;
415 m_bindMetas
[parameterIndex
- 1].is_null
= true;
419 switch (targetSqlType
)
421 case DataType::DECIMAL
:
422 case DataType::NUMERIC
:
426 if (value
>>= nValue
)
428 setDouble(parameterIndex
, nValue
);
431 else if (value
>>= sValue
)
434 = OUStringToOString(sValue
, getOwnConnection()->getConnectionEncoding());
435 std::stringstream sStream
{ sAscii
.getStr() };
437 m_binds
[nIndex
].buffer_type
= MYSQL_TYPE_DOUBLE
;
438 mysqlc_sdbc_driver::resetSqlVar(&m_binds
[nIndex
].buffer
, &nValue
, MYSQL_TYPE_DOUBLE
,
440 m_bindMetas
[nIndex
].is_null
= false;
450 mysqlc_sdbc_driver::throwInvalidArgumentException(
451 "OPreparedStatement::setObjectWithInfo", *this);
456 void SAL_CALL
OPreparedStatement::setObjectNull(sal_Int32 parameter
, sal_Int32
/* sqlType */,
457 const OUString
& /* typeName */)
459 MutexGuard
aGuard(m_aMutex
);
460 checkDisposed(rBHelper
.bDisposed
);
461 checkParameterIndex(parameter
);
463 mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedStatement::setObjectNull",
467 void SAL_CALL
OPreparedStatement::setObject(sal_Int32 parameter
, const Any
& /* x */)
469 MutexGuard
aGuard(m_aMutex
);
470 checkDisposed(rBHelper
.bDisposed
);
471 checkParameterIndex(parameter
);
473 mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedStatement::setObject", *this);
476 void SAL_CALL
OPreparedStatement::setShort(sal_Int32 parameter
, sal_Int16 x
)
478 MutexGuard
aGuard(m_aMutex
);
479 checkDisposed(rBHelper
.bDisposed
);
480 checkParameterIndex(parameter
);
482 const sal_Int32 nIndex
= parameter
- 1;
483 m_binds
[nIndex
].buffer_type
= MYSQL_TYPE_SHORT
;
484 mysqlc_sdbc_driver::resetSqlVar(&m_binds
[nIndex
].buffer
, &x
, MYSQL_TYPE_SHORT
);
485 m_bindMetas
[nIndex
].is_null
= false;
488 void SAL_CALL
OPreparedStatement::setBytes(sal_Int32 parameter
, const Sequence
<sal_Int8
>& x
)
490 MutexGuard
aGuard(m_aMutex
);
491 checkDisposed(rBHelper
.bDisposed
);
492 checkParameterIndex(parameter
);
494 const sal_Int32 nIndex
= parameter
- 1;
495 m_binds
[nIndex
].buffer_type
= MYSQL_TYPE_BLOB
; // FIXME
496 mysqlc_sdbc_driver::resetSqlVar(&m_binds
[nIndex
].buffer
, &x
, MYSQL_TYPE_BLOB
);
497 m_bindMetas
[nIndex
].is_null
= false;
500 void SAL_CALL
OPreparedStatement::setCharacterStream(sal_Int32 parameter
,
501 const Reference
<XInputStream
>& /* x */,
502 sal_Int32
/* length */)
504 MutexGuard
aGuard(m_aMutex
);
505 checkDisposed(rBHelper
.bDisposed
);
506 checkParameterIndex(parameter
);
508 mysqlc_sdbc_driver::throwFeatureNotImplementedException(
509 "OPreparedStatement::setCharacterStream", *this);
512 void SAL_CALL
OPreparedStatement::setBinaryStream(sal_Int32 parameter
,
513 const Reference
<XInputStream
>& /* x */,
514 sal_Int32
/* length */)
516 MutexGuard
aGuard(m_aMutex
);
517 checkDisposed(rBHelper
.bDisposed
);
518 checkParameterIndex(parameter
);
520 mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedStatement::setBinaryStream",
524 void SAL_CALL
OPreparedStatement::clearParameters()
526 MutexGuard
aGuard(m_aMutex
);
527 checkDisposed(rBHelper
.bDisposed
);
529 for (size_t i
= 0; i
< m_binds
.size(); ++i
)
531 m_bindMetas
[i
].is_null
= true;
532 free(m_binds
[i
].buffer
);
533 m_binds
[i
].buffer
= nullptr;
537 // void SAL_CALL OPreparedStatement::clearBatch()
539 // mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedStatement::clearBatch",
543 // void SAL_CALL OPreparedStatement::addBatch()
545 // mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedStatement::addBatch", *this);
548 // Sequence<sal_Int32> SAL_CALL OPreparedStatement::executeBatch() {
549 // mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedStatement::executeBatch", *this);
552 void OPreparedStatement::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle
, const Any
& rValue
)
556 case PROPERTY_ID_RESULTSETCONCURRENCY
:
558 case PROPERTY_ID_RESULTSETTYPE
:
560 case PROPERTY_ID_FETCHDIRECTION
:
562 case PROPERTY_ID_USEBOOKMARKS
:
565 /* XXX: Recursion ?? */
566 OPreparedStatement::setFastPropertyValue_NoBroadcast(nHandle
, rValue
);
570 void OPreparedStatement::checkParameterIndex(sal_Int32 column
)
572 if (column
< 1 || column
> static_cast<sal_Int32
>(m_paramCount
))
574 throw SQLException("Parameter index out of range", *this, OUString(), 1, Any());
578 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */