bump product version to 6.3.0.0.beta1
[LibreOffice.git] / connectivity / source / drivers / mysqlc / mysqlc_preparedstatement.cxx
blobe8c2fcda8a695a177e39ddbd72118429126f4371
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/lang/DisposedException.hpp>
29 #include <com/sun/star/sdbc/DataType.hpp>
30 #include <cppuhelper/typeprovider.hxx>
32 #include <stdio.h>
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";
53 return s;
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)
63 , m_pStmt(pStmt)
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)
70 MYSQL_BIND bind;
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);
89 if (!aRet.hasValue())
91 aRet = OPreparedStatement_BASE::queryInterface(rType);
93 return aRet;
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);
112 return m_xMetaData;
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
125 clearWarnings();
126 clearParameters();
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);
143 if (nFail != 0)
145 MYSQL* pMysql = m_xConnection->getMysqlConnection();
146 mysqlc_sdbc_driver::throwSQLExceptionWithMsg(mysql_stmt_error(m_pStmt), mysql_errno(pMysql),
147 *this, m_xConnection->getConnectionEncoding());
150 return !nFail;
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);
167 if (nFail != 0)
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);
175 return affectedRows;
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);
215 if (nFail != 0)
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);
223 return xResultSet;
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);
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 = 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);
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 = 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);
292 MYSQL_TIME my_time;
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;
417 return;
420 switch (targetSqlType)
422 case DataType::DECIMAL:
423 case DataType::NUMERIC:
425 double nValue(0.0);
426 OUString sValue;
427 if (value >>= nValue)
429 setDouble(parameterIndex, nValue);
430 break;
432 else if (value >>= sValue)
434 OString sAscii
435 = OUStringToOString(sValue, getOwnConnection()->getConnectionEncoding());
436 std::stringstream sStream{ sAscii.getStr() };
437 sStream >> nValue;
438 m_binds[nIndex].buffer_type = MYSQL_TYPE_DOUBLE;
439 mysqlc_sdbc_driver::resetSqlVar(&m_binds[nIndex].buffer, &nValue, MYSQL_TYPE_DOUBLE,
440 sValue.getLength());
441 m_bindMetas[nIndex].is_null = 0;
442 break;
445 [[fallthrough]];
448 // TODO other types
450 default:
451 mysqlc_sdbc_driver::throwInvalidArgumentException(
452 "OPreparedStatement::setObjectWithInfo", *this);
453 break;
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",
465 *this);
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",
522 *this);
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",
541 *this);
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>();
552 return aRet;
555 void OPreparedStatement::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle, const Any& rValue)
557 switch (nHandle)
559 case PROPERTY_ID_RESULTSETCONCURRENCY:
560 break;
561 case PROPERTY_ID_RESULTSETTYPE:
562 break;
563 case PROPERTY_ID_FETCHDIRECTION:
564 break;
565 case PROPERTY_ID_USEBOOKMARKS:
566 break;
567 default:
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: */