bump product version to 7.2.5.1
[LibreOffice.git] / connectivity / source / drivers / mysqlc / mysqlc_preparedstatement.cxx
bloba50b14bbb3b48961cdb33b505e5b28ae6a82429a
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
30 #include <stdio.h>
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)
59 , m_pStmt(pStmt)
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);
83 if (!aRet.hasValue())
85 aRet = OPreparedStatement_BASE::queryInterface(rType);
87 return aRet;
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);
106 return m_xMetaData;
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
119 clearWarnings();
120 clearParameters();
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);
138 if (nFail != 0)
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());
146 return !nFail;
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);
164 if (nFail != 0)
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);
173 return affectedRows;
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);
214 if (nFail != 0)
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);
223 return xResultSet;
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;
416 return;
419 switch (targetSqlType)
421 case DataType::DECIMAL:
422 case DataType::NUMERIC:
424 double nValue(0.0);
425 OUString sValue;
426 if (value >>= nValue)
428 setDouble(parameterIndex, nValue);
429 break;
431 else if (value >>= sValue)
433 OString sAscii
434 = OUStringToOString(sValue, getOwnConnection()->getConnectionEncoding());
435 std::stringstream sStream{ sAscii.getStr() };
436 sStream >> nValue;
437 m_binds[nIndex].buffer_type = MYSQL_TYPE_DOUBLE;
438 mysqlc_sdbc_driver::resetSqlVar(&m_binds[nIndex].buffer, &nValue, MYSQL_TYPE_DOUBLE,
439 sValue.getLength());
440 m_bindMetas[nIndex].is_null = false;
441 break;
444 [[fallthrough]];
447 // TODO other types
449 default:
450 mysqlc_sdbc_driver::throwInvalidArgumentException(
451 "OPreparedStatement::setObjectWithInfo", *this);
452 break;
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",
464 *this);
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",
521 *this);
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()
538 // {
539 // mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedStatement::clearBatch",
540 // *this);
541 // }
543 // void SAL_CALL OPreparedStatement::addBatch()
544 // {
545 // mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedStatement::addBatch", *this);
546 // }
548 // Sequence<sal_Int32> SAL_CALL OPreparedStatement::executeBatch() {
549 // mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedStatement::executeBatch", *this);
550 // }
552 void OPreparedStatement::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle, const Any& rValue)
554 switch (nHandle)
556 case PROPERTY_ID_RESULTSETCONCURRENCY:
557 break;
558 case PROPERTY_ID_RESULTSETTYPE:
559 break;
560 case PROPERTY_ID_FETCHDIRECTION:
561 break;
562 case PROPERTY_ID_USEBOOKMARKS:
563 break;
564 default:
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: */