1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20 #include "mysqlc_propertyids.hxx"
21 #include "mysqlc_general.hxx"
22 #include "mysqlc_resultset.hxx"
23 #include "mysqlc_resultsetmetadata.hxx"
24
25 #include <com/sun/star/beans/PropertyAttribute.hpp>
26 #include <com/sun/star/lang/DisposedException.hpp>
27 #include <com/sun/star/sdbc/DataType.hpp>
28 #include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
29 #include <com/sun/star/sdbc/ResultSetType.hpp>
30 #include <com/sun/star/sdbc/FetchDirection.hpp>
31 #include <com/sun/star/sdbcx/CompareBookmark.hpp>
32 #include <cppuhelper/supportsservice.hxx>
33 #include <cppuhelper/typeprovider.hxx>
34 #include <comphelper/seqstream.hxx>
35
36 #include <sal/log.hxx>
37
38 using namespace rtl;
39 #include <comphelper/string.hxx>
40
41 #include <cstdlib>
42
43 using namespace connectivity::mysqlc;
44 using namespace cppu;
45 using namespace com::sun::star;
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::sdbcx;
50 using namespace com::sun::star::container;
51 using namespace com::sun::star::io;
52 using namespace com::sun::star::uno;
53 using namespace com::sun::star::util;
54 using namespace ::comphelper;
55 using ::osl::MutexGuard;
56
57 #include <stdio.h>
58
59 namespace
60 {
61 // copied from string misc, it should be replaced when library is not an
62 // extension anymore
lcl_split(const OString & rStr,char cSeparator)63 std::vector<OString> lcl_split(const OString& rStr, char cSeparator)
64 {
65 std::vector<OString> vec;
66 sal_Int32 idx = 0;
67 do
68 {
69 OString kw = rStr.getToken(0, cSeparator, idx);
70 kw = kw.trim();
71 if (!kw.isEmpty())
72 {
73 vec.push_back(kw);
74 }
75 } while (idx >= 0);
76 return vec;
77 }
78 }
79
checkRowIndex()80 void OResultSet::checkRowIndex()
81 {
82 if (m_nRowPosition < 0 || m_nRowPosition >= m_nRowCount)
83 {
84 throw SQLException("Cursor position out of range", *this, OUString(), 1, Any());
85 }
86 }
87
checkNull(sal_Int32 column)88 bool OResultSet::checkNull(sal_Int32 column)
89 {
90 if (m_aRows[m_nRowPosition][column - 1].isEmpty())
91 {
92 m_bWasNull = true;
93 return true;
94 }
95 m_bWasNull = false;
96 return false;
97 }
98
getImplementationName()99 OUString SAL_CALL OResultSet::getImplementationName()
100 {
101 return "com.sun.star.sdbcx.mysqlc.ResultSet";
102 }
103
getSupportedServiceNames()104 uno::Sequence<OUString> SAL_CALL OResultSet::getSupportedServiceNames()
105 {
106 return { "com.sun.star.sdbc.ResultSet", "com.sun.star.sdbcx.ResultSet" };
107 }
108
supportsService(const OUString & _rServiceName)109 sal_Bool SAL_CALL OResultSet::supportsService(const OUString& _rServiceName)
110 {
111 return cppu::supportsService(this, _rServiceName);
112 }
113
OResultSet(OConnection & rConn,OCommonStatement * pStmt,MYSQL_RES * pResult,rtl_TextEncoding _encoding)114 OResultSet::OResultSet(OConnection& rConn, OCommonStatement* pStmt, MYSQL_RES* pResult,
115 rtl_TextEncoding _encoding)
116 : OResultSet_BASE(m_aMutex)
117 , OPropertySetHelper(OResultSet_BASE::rBHelper)
118 , m_pMysql(rConn.getMysqlConnection())
119 , m_aStatement(static_cast<OWeakObject*>(pStmt))
120 , m_pResult(pResult)
121 , m_encoding(_encoding)
122 {
123 m_xMetaData = new OResultSetMetaData(rConn, m_pResult);
124 }
125
ensureResultFetched()126 void OResultSet::ensureResultFetched()
127 {
128 if (!m_bResultFetched)
129 {
130 fetchResult();
131 }
132 }
133
ensureFieldInfoFetched()134 void OResultSet::ensureFieldInfoFetched()
135 {
136 if (m_bResultFetched)
137 return; // already fetched
138
139 // it works only if result set is produced via mysql_store_result
140 // TODO ensure that
141 m_nRowCount = mysql_num_rows(m_pResult);
142
143 if (!m_aFields.empty())
144 return;
145 unsigned nFieldCount = mysql_num_fields(m_pResult);
146 MYSQL_FIELD* pFields = mysql_fetch_fields(m_pResult);
147 m_aFields.reserve(nFieldCount);
148 for (unsigned i = 0; i < nFieldCount; ++i)
149 m_aFields.push_back(OUString{
150 pFields[i].name, static_cast<sal_Int32>(strlen(pFields[i].name)), m_encoding });
151 }
152
fetchResult()153 void OResultSet::fetchResult()
154 {
155 // Mysql C API does not allow simultaneously opened result sets, but sdbc does.
156 // Because of that we need to fetch all of the data ASAP
157 ensureFieldInfoFetched();
158
159 // fetch all the data
160 m_aRows.reserve(m_nRowCount);
161
162 for (sal_Int32 row = 0; row < m_nRowCount; ++row)
163 {
164 MYSQL_ROW data = mysql_fetch_row(m_pResult);
165 unsigned long* lengths = mysql_fetch_lengths(m_pResult);
166 m_aRows.push_back(DataFields{});
167 // MYSQL_ROW is char**, array of strings
168 for (std::size_t col = 0; col < m_aFields.size(); ++col)
169 {
170 m_aRows.back().push_back(OString{ data[col], static_cast<sal_Int32>(lengths[col]) });
171 }
172 }
173 unsigned errorNum = mysql_errno(m_pMysql);
174 if (errorNum)
175 mysqlc_sdbc_driver::throwSQLExceptionWithMsg(mysql_error(m_pMysql), errorNum, *this,
176 m_encoding);
177 m_bResultFetched = true;
178 mysql_free_result(m_pResult);
179 }
180
disposing()181 void OResultSet::disposing()
182 {
183 OPropertySetHelper::disposing();
184
185 MutexGuard aGuard(m_aMutex);
186
187 m_aStatement = nullptr;
188 m_xMetaData = nullptr;
189 }
190
queryInterface(const Type & rType)191 Any SAL_CALL OResultSet::queryInterface(const Type& rType)
192 {
193 Any aRet = OPropertySetHelper::queryInterface(rType);
194 if (!aRet.hasValue())
195 {
196 aRet = OResultSet_BASE::queryInterface(rType);
197 }
198 return aRet;
199 }
200
getTypes()201 uno::Sequence<Type> SAL_CALL OResultSet::getTypes()
202 {
203 OTypeCollection aTypes(cppu::UnoType<XMultiPropertySet>::get(),
204 cppu::UnoType<XFastPropertySet>::get(),
205 cppu::UnoType<XPropertySet>::get());
206
207 return concatSequences(aTypes.getTypes(), OResultSet_BASE::getTypes());
208 }
209
findColumn(const OUString & columnName)210 sal_Int32 SAL_CALL OResultSet::findColumn(const OUString& columnName)
211 {
212 MutexGuard aGuard(m_aMutex);
213 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
214 ensureFieldInfoFetched();
215
216 for (std::size_t i = 0; i < m_aFields.size(); ++i)
217 {
218 if (columnName.equalsIgnoreAsciiCase(m_aFields[i]))
219 return static_cast<sal_Int32>(i) + 1; // sdbc indexes from 1
220 }
221
222 throw SQLException("The column name '" + columnName + "' is not valid.", *this, "42S22", 0,
223 Any());
224 }
225
getBinaryStream(sal_Int32 column)226 uno::Reference<XInputStream> SAL_CALL OResultSet::getBinaryStream(sal_Int32 column)
227 {
228 MutexGuard aGuard(m_aMutex);
229 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
230 checkBordersAndEnsureFetched(column);
231 if (checkNull(column))
232 return nullptr;
233
234 OString sVal = m_aRows[m_nRowPosition][column - 1];
235 return new SequenceInputStream{ uno::Sequence<sal_Int8>(
236 reinterpret_cast<sal_Int8 const*>(sVal.getStr()), getDataLength(column)) };
237 }
238
getCharacterStream(sal_Int32 column)239 uno::Reference<XInputStream> SAL_CALL OResultSet::getCharacterStream(sal_Int32 column)
240 {
241 MutexGuard aGuard(m_aMutex);
242 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
243 checkBordersAndEnsureFetched(column);
244 mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::getCharacterStream",
245 *this);
246 return nullptr;
247 }
248
getBoolean(sal_Int32 column)249 sal_Bool SAL_CALL OResultSet::getBoolean(sal_Int32 column)
250 {
251 MutexGuard aGuard(m_aMutex);
252 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
253 checkBordersAndEnsureFetched(column);
254 if (checkNull(column))
255 return false;
256
257 OString sVal = m_aRows[m_nRowPosition][column - 1];
258 return sVal.toInt32() != 0;
259 }
260
getByte(sal_Int32 column)261 sal_Int8 SAL_CALL OResultSet::getByte(sal_Int32 column)
262 {
263 MutexGuard aGuard(m_aMutex);
264 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
265 checkBordersAndEnsureFetched(column);
266 if (checkNull(column))
267 return 0;
268
269 OString sVal = m_aRows[m_nRowPosition][column - 1];
270
271 return static_cast<sal_Int8>(sVal.toInt32());
272 }
273
getBytes(sal_Int32 column)274 uno::Sequence<sal_Int8> SAL_CALL OResultSet::getBytes(sal_Int32 column)
275 {
276 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
277 MutexGuard aGuard(m_aMutex);
278 checkBordersAndEnsureFetched(column);
279 OString sVal = m_aRows[m_nRowPosition][column - 1];
280 if (checkNull(column))
281 return uno::Sequence<sal_Int8>();
282
283 return uno::Sequence<sal_Int8>(reinterpret_cast<sal_Int8 const*>(sVal.getStr()),
284 getDataLength(column));
285 }
286
getDate(sal_Int32 column)287 Date SAL_CALL OResultSet::getDate(sal_Int32 column)
288 {
289 MutexGuard aGuard(m_aMutex);
290 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
291 checkBordersAndEnsureFetched(column);
292
293 Date d;
294
295 if (checkNull(column))
296 return d;
297
298 OString dateStr = m_aRows[m_nRowPosition][column - 1];
299
300 OString dateString(dateStr);
301 OString token;
302 sal_Int32 nIndex = 0, i = 0;
303 do
304 {
305 token = dateString.getToken(0, '-', nIndex);
306 switch (i)
307 {
308 case 0:
309 d.Year = static_cast<sal_uInt16>(token.toUInt32());
310 break;
311 case 1:
312 d.Month = static_cast<sal_uInt16>(token.toUInt32());
313 break;
314 case 2:
315 d.Day = static_cast<sal_uInt16>(token.toUInt32());
316 break;
317 default:;
318 }
319 i++;
320 } while (nIndex >= 0);
321 return d;
322 }
323
getDouble(sal_Int32 column)324 double SAL_CALL OResultSet::getDouble(sal_Int32 column)
325 {
326 MutexGuard aGuard(m_aMutex);
327 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
328 checkBordersAndEnsureFetched(column);
329
330 if (checkNull(column))
331 return 0.0;
332
333 OString sVal = m_aRows[m_nRowPosition][column - 1];
334 return sVal.toDouble();
335 }
336
getFloat(sal_Int32 column)337 float SAL_CALL OResultSet::getFloat(sal_Int32 column)
338 {
339 MutexGuard aGuard(m_aMutex);
340 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
341 checkBordersAndEnsureFetched(column);
342 if (checkNull(column))
343 return 0.0f;
344
345 OString sVal = m_aRows[m_nRowPosition][column - 1];
346 return sVal.toFloat();
347 }
348
getInt(sal_Int32 column)349 sal_Int32 SAL_CALL OResultSet::getInt(sal_Int32 column)
350 {
351 MutexGuard aGuard(m_aMutex);
352 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
353 checkBordersAndEnsureFetched(column);
354 if (checkNull(column))
355 return 0;
356
357 OString sVal = m_aRows[m_nRowPosition][column - 1];
358 return sVal.toInt32();
359 }
360
getRow()361 sal_Int32 SAL_CALL OResultSet::getRow()
362 {
363 MutexGuard aGuard(m_aMutex);
364 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
365
366 return m_nRowPosition + 1; // indexed from 1
367 }
368
getLong(sal_Int32 column)369 sal_Int64 SAL_CALL OResultSet::getLong(sal_Int32 column)
370 {
371 MutexGuard aGuard(m_aMutex);
372 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
373 checkBordersAndEnsureFetched(column);
374 if (checkNull(column))
375 return 0LL;
376
377 OString sVal = m_aRows[m_nRowPosition][column - 1];
378 return sVal.toInt64();
379 }
380
getMetaData()381 uno::Reference<XResultSetMetaData> SAL_CALL OResultSet::getMetaData()
382 {
383 MutexGuard aGuard(m_aMutex);
384 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
385 return m_xMetaData;
386 }
387
getArray(sal_Int32 column)388 uno::Reference<XArray> SAL_CALL OResultSet::getArray(sal_Int32 column)
389 {
390 MutexGuard aGuard(m_aMutex);
391 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
392 checkBordersAndEnsureFetched(column);
393
394 mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::getArray", *this);
395 return nullptr;
396 }
397
getClob(sal_Int32 column)398 uno::Reference<XClob> SAL_CALL OResultSet::getClob(sal_Int32 column)
399 {
400 MutexGuard aGuard(m_aMutex);
401 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
402 checkBordersAndEnsureFetched(column);
403
404 mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::getClob", *this);
405 return nullptr;
406 }
407
getBlob(sal_Int32 column)408 uno::Reference<XBlob> SAL_CALL OResultSet::getBlob(sal_Int32 column)
409 {
410 MutexGuard aGuard(m_aMutex);
411 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
412 checkBordersAndEnsureFetched(column);
413
414 mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::getBlob", *this);
415 return nullptr;
416 }
417
getRef(sal_Int32 column)418 uno::Reference<XRef> SAL_CALL OResultSet::getRef(sal_Int32 column)
419 {
420 MutexGuard aGuard(m_aMutex);
421 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
422 checkBordersAndEnsureFetched(column);
423
424 mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::getRef", *this);
425 return nullptr;
426 }
427
getObject(sal_Int32 column,const uno::Reference<XNameAccess> &)428 Any SAL_CALL OResultSet::getObject(sal_Int32 column,
429 const uno::Reference<XNameAccess>& /* typeMap */)
430 {
431 MutexGuard aGuard(m_aMutex);
432 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
433 checkBordersAndEnsureFetched(column);
434
435 mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::getObject", *this);
436 return Any();
437 }
438
getShort(sal_Int32 column)439 sal_Int16 SAL_CALL OResultSet::getShort(sal_Int32 column)
440 {
441 MutexGuard aGuard(m_aMutex);
442 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
443 checkBordersAndEnsureFetched(column);
444 if (checkNull(column))
445 return 0;
446
447 OString sVal = m_aRows[m_nRowPosition][column - 1];
448 return sVal.toInt32();
449 }
450
getString(sal_Int32 column)451 OUString SAL_CALL OResultSet::getString(sal_Int32 column)
452 {
453 MutexGuard aGuard(m_aMutex);
454 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
455 checkBordersAndEnsureFetched(column);
456 if (checkNull(column))
457 return rtl::OUString{};
458
459 OString sVal = m_aRows[m_nRowPosition][column - 1];
460 return OStringToOUString(sVal, m_encoding);
461 }
462
getTime(sal_Int32 column)463 Time SAL_CALL OResultSet::getTime(sal_Int32 column)
464 {
465 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
466 MutexGuard aGuard(m_aMutex);
467 checkBordersAndEnsureFetched(column);
468
469 Time t;
470 if (checkNull(column))
471 return t;
472
473 OString sVal = m_aRows[m_nRowPosition][column - 1];
474 OString timeString{ sVal.getStr(), getDataLength(column) };
475 OString token;
476 sal_Int32 nIndex, i = 0;
477
478 nIndex = timeString.indexOf(' ') + 1;
479 do
480 {
481 token = timeString.getToken(0, ':', nIndex);
482 switch (i)
483 {
484 case 0:
485 t.Hours = static_cast<sal_uInt16>(token.toUInt32());
486 break;
487 case 1:
488 t.Minutes = static_cast<sal_uInt16>(token.toUInt32());
489 break;
490 case 2:
491 t.Seconds = static_cast<sal_uInt16>(token.toUInt32());
492 break;
493 }
494 i++;
495 } while (nIndex >= 0);
496
497 return t;
498 }
499
getTimestamp(sal_Int32 column)500 DateTime SAL_CALL OResultSet::getTimestamp(sal_Int32 column)
501 {
502 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
503 MutexGuard aGuard(m_aMutex);
504 checkBordersAndEnsureFetched(column);
505
506 if (checkNull(column))
507 return DateTime{};
508
509 OString sVal = m_aRows[m_nRowPosition][column - 1];
510
511 // YY-MM-DD HH:MM:SS
512 std::vector<OString> dateAndTime
513 = lcl_split(OString{ sVal.getStr(), getDataLength(column) }, ' ');
514
515 auto dateParts = lcl_split(dateAndTime.at(0), '-');
516 auto timeParts = lcl_split(dateAndTime.at(1), ':');
517
518 if (dateParts.size() < 2 || timeParts.size() < 2)
519 throw SQLException("Timestamp has a wrong format", *this, OUString(), 1, Any());
520
521 DateTime dt;
522
523 dt.Year = dateParts.at(0).toUInt32();
524 dt.Month = dateParts.at(1).toUInt32();
525 dt.Day = dateParts.at(2).toUInt32();
526 dt.Hours = timeParts.at(0).toUInt32();
527 dt.Minutes = timeParts.at(1).toUInt32();
528 dt.Seconds = timeParts.at(2).toUInt32();
529 return dt;
530 }
531
isBeforeFirst()532 sal_Bool SAL_CALL OResultSet::isBeforeFirst()
533 {
534 MutexGuard aGuard(m_aMutex);
535 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
536
537 return m_nRowPosition < 0;
538 }
539
isAfterLast()540 sal_Bool SAL_CALL OResultSet::isAfterLast()
541 {
542 MutexGuard aGuard(m_aMutex);
543 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
544 ensureFieldInfoFetched();
545
546 return m_nRowPosition >= m_nRowCount;
547 }
548
isFirst()549 sal_Bool SAL_CALL OResultSet::isFirst()
550 {
551 MutexGuard aGuard(m_aMutex);
552 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
553 ensureFieldInfoFetched();
554
555 return m_nRowPosition == 0 && !isAfterLast();
556 }
557
isLast()558 sal_Bool SAL_CALL OResultSet::isLast()
559 {
560 MutexGuard aGuard(m_aMutex);
561 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
562 ensureFieldInfoFetched();
563
564 return m_nRowPosition == m_nRowCount - 1;
565 }
566
beforeFirst()567 void SAL_CALL OResultSet::beforeFirst()
568 {
569 MutexGuard aGuard(m_aMutex);
570 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
571 m_nRowPosition = -1;
572 }
573
afterLast()574 void SAL_CALL OResultSet::afterLast()
575 {
576 MutexGuard aGuard(m_aMutex);
577 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
578 ensureFieldInfoFetched();
579 m_nRowPosition = m_nRowCount;
580 }
581
close()582 void SAL_CALL OResultSet::close()
583 {
584 MutexGuard aGuard(m_aMutex);
585 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
586
587 m_pResult = nullptr;
588 dispose();
589 }
590
first()591 sal_Bool SAL_CALL OResultSet::first()
592 {
593 MutexGuard aGuard(m_aMutex);
594 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
595 m_nRowPosition = 0;
596
597 return true;
598 }
599
last()600 sal_Bool SAL_CALL OResultSet::last()
601 {
602 MutexGuard aGuard(m_aMutex);
603 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
604 ensureFieldInfoFetched();
605 m_nRowPosition = m_nRowCount - 1;
606
607 return true;
608 }
609
absolute(sal_Int32 row)610 sal_Bool SAL_CALL OResultSet::absolute(sal_Int32 row)
611 {
612 MutexGuard aGuard(m_aMutex);
613 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
614 ensureFieldInfoFetched();
615
616 sal_Int32 nToGo = row < 0 ? (m_nRowCount - 1) - row : row - 1;
617
618 if (nToGo >= m_nRowCount)
619 nToGo = m_nRowCount - 1;
620 if (nToGo < 0)
621 nToGo = 0;
622
623 m_nRowPosition = nToGo;
624
625 return true;
626 }
627
relative(sal_Int32 row)628 sal_Bool SAL_CALL OResultSet::relative(sal_Int32 row)
629 {
630 MutexGuard aGuard(m_aMutex);
631 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
632 ensureFieldInfoFetched();
633
634 if (row == 0)
635 return true;
636
637 sal_Int32 nToGo = m_nRowPosition + row;
638 if (nToGo >= m_nRowCount)
639 nToGo = m_nRowCount - 1;
640 if (nToGo < 0)
641 nToGo = 0;
642
643 m_nRowPosition = nToGo;
644
645 return true;
646 }
647
previous()648 sal_Bool SAL_CALL OResultSet::previous()
649 {
650 MutexGuard aGuard(m_aMutex);
651 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
652
653 if (m_nRowPosition == 0)
654 {
655 m_nRowPosition--;
656 return false;
657 }
658 else if (m_nRowPosition < 0)
659 {
660 return false;
661 }
662
663 m_nRowPosition--;
664 return true;
665 }
666
getStatement()667 uno::Reference<uno::XInterface> SAL_CALL OResultSet::getStatement()
668 {
669 MutexGuard aGuard(m_aMutex);
670 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
671
672 return m_aStatement.get();
673 }
674
rowDeleted()675 sal_Bool SAL_CALL OResultSet::rowDeleted()
676 {
677 MutexGuard aGuard(m_aMutex);
678 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
679
680 return false;
681 }
682
rowInserted()683 sal_Bool SAL_CALL OResultSet::rowInserted()
684 {
685 MutexGuard aGuard(m_aMutex);
686 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
687
688 return false;
689 }
690
rowUpdated()691 sal_Bool SAL_CALL OResultSet::rowUpdated()
692 {
693 MutexGuard aGuard(m_aMutex);
694 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
695
696 return false;
697 }
698
next()699 sal_Bool SAL_CALL OResultSet::next()
700 {
701 MutexGuard aGuard(m_aMutex);
702 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
703 ensureFieldInfoFetched();
704 if (m_nRowPosition + 1 > m_nRowCount) // afterlast
705 return false;
706 if (m_nRowPosition + 1 == m_nRowCount) // last
707 {
708 // return false but take it to afterlast anyway
709 ++m_nRowPosition;
710 return false;
711 }
712 ++m_nRowPosition;
713 return true;
714 }
715
wasNull()716 sal_Bool SAL_CALL OResultSet::wasNull()
717 {
718 MutexGuard aGuard(m_aMutex);
719 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
720
721 return m_bWasNull;
722 }
723
cancel()724 void SAL_CALL OResultSet::cancel()
725 {
726 MutexGuard aGuard(m_aMutex);
727 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
728 }
729
clearWarnings()730 void SAL_CALL OResultSet::clearWarnings() {}
731
getWarnings()732 Any SAL_CALL OResultSet::getWarnings() { return Any(); }
733
insertRow()734 void SAL_CALL OResultSet::insertRow()
735 {
736 MutexGuard aGuard(m_aMutex);
737 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
738 // you only have to implement this if you want to insert new rows
739 mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::insertRow", *this);
740 }
741
updateRow()742 void SAL_CALL OResultSet::updateRow()
743 {
744 MutexGuard aGuard(m_aMutex);
745 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
746
747 // only when you allow updates
748 mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateRow", *this);
749 }
750
deleteRow()751 void SAL_CALL OResultSet::deleteRow()
752 {
753 MutexGuard aGuard(m_aMutex);
754 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
755 mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::deleteRow", *this);
756 }
757
cancelRowUpdates()758 void SAL_CALL OResultSet::cancelRowUpdates()
759 {
760 MutexGuard aGuard(m_aMutex);
761 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
762 mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::cancelRowUpdates", *this);
763 }
764
moveToInsertRow()765 void SAL_CALL OResultSet::moveToInsertRow()
766 {
767 MutexGuard aGuard(m_aMutex);
768 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
769
770 // only when you allow insert's
771 mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::moveToInsertRow", *this);
772 }
773
moveToCurrentRow()774 void SAL_CALL OResultSet::moveToCurrentRow()
775 {
776 MutexGuard aGuard(m_aMutex);
777 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
778 }
779
updateNull(sal_Int32 column)780 void SAL_CALL OResultSet::updateNull(sal_Int32 column)
781 {
782 MutexGuard aGuard(m_aMutex);
783 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
784 checkColumnIndex(column);
785 checkRowIndex();
786 mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateNull", *this);
787 }
788
updateBoolean(sal_Int32 column,sal_Bool)789 void SAL_CALL OResultSet::updateBoolean(sal_Int32 column, sal_Bool /* x */)
790 {
791 MutexGuard aGuard(m_aMutex);
792 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
793 checkColumnIndex(column);
794 checkRowIndex();
795 mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateBoolean", *this);
796 }
797
updateByte(sal_Int32 column,sal_Int8)798 void SAL_CALL OResultSet::updateByte(sal_Int32 column, sal_Int8 /* x */)
799 {
800 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
801 MutexGuard aGuard(m_aMutex);
802 checkColumnIndex(column);
803 checkRowIndex();
804 mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateByte", *this);
805 }
806
updateShort(sal_Int32 column,sal_Int16)807 void SAL_CALL OResultSet::updateShort(sal_Int32 column, sal_Int16 /* x */)
808 {
809 MutexGuard aGuard(m_aMutex);
810 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
811 checkColumnIndex(column);
812 checkRowIndex();
813 mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateShort", *this);
814 }
815
updateInt(sal_Int32 column,sal_Int32)816 void SAL_CALL OResultSet::updateInt(sal_Int32 column, sal_Int32 /* x */)
817 {
818 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
819 MutexGuard aGuard(m_aMutex);
820 checkColumnIndex(column);
821 checkRowIndex();
822 mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateInt", *this);
823 }
824
updateLong(sal_Int32 column,sal_Int64)825 void SAL_CALL OResultSet::updateLong(sal_Int32 column, sal_Int64 /* x */)
826 {
827 MutexGuard aGuard(m_aMutex);
828 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
829 checkColumnIndex(column);
830 checkRowIndex();
831 mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateLong", *this);
832 }
833
updateFloat(sal_Int32 column,float)834 void SAL_CALL OResultSet::updateFloat(sal_Int32 column, float /* x */)
835 {
836 MutexGuard aGuard(m_aMutex);
837 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
838 checkColumnIndex(column);
839 checkRowIndex();
840 mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateFloat", *this);
841 }
842
updateDouble(sal_Int32 column,double)843 void SAL_CALL OResultSet::updateDouble(sal_Int32 column, double /* x */)
844 {
845 MutexGuard aGuard(m_aMutex);
846 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
847 checkColumnIndex(column);
848 checkRowIndex();
849 mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateDouble", *this);
850 }
851
updateString(sal_Int32 column,const OUString &)852 void SAL_CALL OResultSet::updateString(sal_Int32 column, const OUString& /* x */)
853 {
854 MutexGuard aGuard(m_aMutex);
855 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
856 checkColumnIndex(column);
857 checkRowIndex();
858 mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateString", *this);
859 }
860
updateBytes(sal_Int32 column,const uno::Sequence<sal_Int8> &)861 void SAL_CALL OResultSet::updateBytes(sal_Int32 column, const uno::Sequence<sal_Int8>& /* x */)
862 {
863 MutexGuard aGuard(m_aMutex);
864 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
865 checkColumnIndex(column);
866 checkRowIndex();
867 mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateBytes", *this);
868 }
869
updateDate(sal_Int32 column,const Date &)870 void SAL_CALL OResultSet::updateDate(sal_Int32 column, const Date& /* x */)
871 {
872 MutexGuard aGuard(m_aMutex);
873 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
874 checkColumnIndex(column);
875 checkRowIndex();
876 mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateDate", *this);
877 }
878
updateTime(sal_Int32 column,const Time &)879 void SAL_CALL OResultSet::updateTime(sal_Int32 column, const Time& /* x */)
880 {
881 MutexGuard aGuard(m_aMutex);
882 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
883 checkColumnIndex(column);
884 checkRowIndex();
885 mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateTime", *this);
886 }
887
updateTimestamp(sal_Int32 column,const DateTime &)888 void SAL_CALL OResultSet::updateTimestamp(sal_Int32 column, const DateTime& /* x */)
889 {
890 MutexGuard aGuard(m_aMutex);
891 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
892 checkColumnIndex(column);
893 checkRowIndex();
894 mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateTimestamp", *this);
895 }
896
updateBinaryStream(sal_Int32 column,const uno::Reference<XInputStream> &,sal_Int32)897 void SAL_CALL OResultSet::updateBinaryStream(sal_Int32 column,
898 const uno::Reference<XInputStream>& /* x */,
899 sal_Int32 /* length */)
900 {
901 MutexGuard aGuard(m_aMutex);
902 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
903 checkColumnIndex(column);
904 checkRowIndex();
905 mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateBinaryStream",
906 *this);
907 }
908
updateCharacterStream(sal_Int32 column,const uno::Reference<XInputStream> &,sal_Int32)909 void SAL_CALL OResultSet::updateCharacterStream(sal_Int32 column,
910 const uno::Reference<XInputStream>& /* x */,
911 sal_Int32 /* length */)
912 {
913 MutexGuard aGuard(m_aMutex);
914 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
915 checkColumnIndex(column);
916 checkRowIndex();
917 mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateCharacterStream",
918 *this);
919 }
920
refreshRow()921 void SAL_CALL OResultSet::refreshRow()
922 {
923 MutexGuard aGuard(m_aMutex);
924 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
925 mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::refreshRow", *this);
926 }
927
updateObject(sal_Int32 column,const Any &)928 void SAL_CALL OResultSet::updateObject(sal_Int32 column, const Any& /* x */)
929 {
930 MutexGuard aGuard(m_aMutex);
931 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
932 checkColumnIndex(column);
933 checkRowIndex();
934 mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateObject", *this);
935 }
936
updateNumericObject(sal_Int32 column,const Any &,sal_Int32)937 void SAL_CALL OResultSet::updateNumericObject(sal_Int32 column, const Any& /* x */,
938 sal_Int32 /* scale */)
939 {
940 MutexGuard aGuard(m_aMutex);
941 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
942 checkColumnIndex(column);
943 checkRowIndex();
944 mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateNumericObject",
945 *this);
946 }
947
948 // XRowLocate
getBookmark()949 Any SAL_CALL OResultSet::getBookmark()
950 {
951 MutexGuard aGuard(m_aMutex);
952 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
953
954 // if you don't want to support bookmark you must remove the XRowLocate interface
955 mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::getBookmark", *this);
956
957 return Any();
958 }
959
moveToBookmark(const Any &)960 sal_Bool SAL_CALL OResultSet::moveToBookmark(const Any& /* bookmark */)
961 {
962 MutexGuard aGuard(m_aMutex);
963 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
964
965 return false;
966 }
967
moveRelativeToBookmark(const Any &,sal_Int32)968 sal_Bool SAL_CALL OResultSet::moveRelativeToBookmark(const Any& /* bookmark */,
969 sal_Int32 /* rows */)
970 {
971 MutexGuard aGuard(m_aMutex);
972 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
973
974 mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::moveRelativeToBookmark",
975 *this);
976 return false;
977 }
978
compareBookmarks(const Any &,const Any &)979 sal_Int32 SAL_CALL OResultSet::compareBookmarks(const Any& /* n1 */, const Any& /* n2 */)
980 {
981 MutexGuard aGuard(m_aMutex);
982 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
983
984 mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::compareBookmarks", *this);
985
986 return CompareBookmark::NOT_EQUAL;
987 }
988
hasOrderedBookmarks()989 sal_Bool SAL_CALL OResultSet::hasOrderedBookmarks() { return false; }
990
hashBookmark(const Any &)991 sal_Int32 SAL_CALL OResultSet::hashBookmark(const Any& /* bookmark */)
992 {
993 mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::hashBookmark", *this);
994 return 0;
995 }
996
997 // XDeleteRows
deleteRows(const uno::Sequence<Any> &)998 uno::Sequence<sal_Int32> SAL_CALL OResultSet::deleteRows(const uno::Sequence<Any>& /* rows */)
999 {
1000 MutexGuard aGuard(m_aMutex);
1001 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
1002
1003 mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::deleteRows", *this);
1004 return uno::Sequence<sal_Int32>();
1005 }
1006
createArrayHelper() const1007 IPropertyArrayHelper* OResultSet::createArrayHelper() const
1008 {
1009 uno::Sequence<Property> aProps(5);
1010 Property* pProperties = aProps.getArray();
1011 sal_Int32 nPos = 0;
1012 pProperties[nPos++] = Property("FetchDirection", PROPERTY_ID_FETCHDIRECTION,
1013 cppu::UnoType<sal_Int32>::get(), 0);
1014 pProperties[nPos++]
1015 = Property("FetchSize", PROPERTY_ID_FETCHSIZE, cppu::UnoType<sal_Int32>::get(), 0);
1016 pProperties[nPos++] = Property("IsBookmarkable", PROPERTY_ID_ISBOOKMARKABLE,
1017 cppu::UnoType<bool>::get(), PropertyAttribute::READONLY);
1018 pProperties[nPos++] = Property("ResultSetConcurrency", PROPERTY_ID_RESULTSETCONCURRENCY,
1019 cppu::UnoType<sal_Int32>::get(), PropertyAttribute::READONLY);
1020 pProperties[nPos++] = Property("ResultSetType", PROPERTY_ID_RESULTSETTYPE,
1021 cppu::UnoType<sal_Int32>::get(), PropertyAttribute::READONLY);
1022
1023 return new OPropertyArrayHelper(aProps);
1024 }
1025
getInfoHelper()1026 IPropertyArrayHelper& OResultSet::getInfoHelper() { return *getArrayHelper(); }
1027
convertFastPropertyValue(Any &,Any &,sal_Int32 nHandle,const Any &)1028 sal_Bool OResultSet::convertFastPropertyValue(Any& /* rConvertedValue */, Any& /* rOldValue */,
1029 sal_Int32 nHandle, const Any& /* rValue */)
1030 {
1031 switch (nHandle)
1032 {
1033 case PROPERTY_ID_ISBOOKMARKABLE:
1034 case PROPERTY_ID_CURSORNAME:
1035 case PROPERTY_ID_RESULTSETCONCURRENCY:
1036 case PROPERTY_ID_RESULTSETTYPE:
1037 throw css::lang::IllegalArgumentException();
1038 case PROPERTY_ID_FETCHDIRECTION:
1039 case PROPERTY_ID_FETCHSIZE:
1040 default:;
1041 }
1042 return false;
1043 }
1044
setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any &)1045 void OResultSet::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle, const Any& /* rValue */)
1046 {
1047 switch (nHandle)
1048 {
1049 case PROPERTY_ID_ISBOOKMARKABLE:
1050 case PROPERTY_ID_CURSORNAME:
1051 case PROPERTY_ID_RESULTSETCONCURRENCY:
1052 case PROPERTY_ID_RESULTSETTYPE:
1053 throw uno::Exception("cannot set prop " + OUString::number(nHandle), nullptr);
1054 case PROPERTY_ID_FETCHDIRECTION:
1055 break;
1056 case PROPERTY_ID_FETCHSIZE:
1057 break;
1058 default:;
1059 }
1060 }
1061
getFastPropertyValue(Any & _rValue,sal_Int32 nHandle) const1062 void OResultSet::getFastPropertyValue(Any& _rValue, sal_Int32 nHandle) const
1063 {
1064 switch (nHandle)
1065 {
1066 case PROPERTY_ID_ISBOOKMARKABLE:
1067 _rValue <<= false;
1068 break;
1069 case PROPERTY_ID_CURSORNAME:
1070 break;
1071 case PROPERTY_ID_RESULTSETCONCURRENCY:
1072 _rValue <<= ResultSetConcurrency::READ_ONLY;
1073 break;
1074 case PROPERTY_ID_RESULTSETTYPE:
1075 _rValue <<= ResultSetType::SCROLL_INSENSITIVE;
1076 break;
1077 case PROPERTY_ID_FETCHDIRECTION:
1078 _rValue <<= FetchDirection::FORWARD;
1079 break;
1080 case PROPERTY_ID_FETCHSIZE:
1081 _rValue <<= sal_Int32(50);
1082 break;
1083 ;
1084 default:;
1085 }
1086 }
1087
acquire()1088 void SAL_CALL OResultSet::acquire() throw() { OResultSet_BASE::acquire(); }
1089
release()1090 void SAL_CALL OResultSet::release() throw() { OResultSet_BASE::release(); }
1091
getPropertySetInfo()1092 css::uno::Reference<css::beans::XPropertySetInfo> SAL_CALL OResultSet::getPropertySetInfo()
1093 {
1094 return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
1095 }
1096
checkColumnIndex(sal_Int32 index)1097 void OResultSet::checkColumnIndex(sal_Int32 index)
1098 {
1099 if (index < 1 || index > static_cast<int>(m_aFields.size()))
1100 {
1101 /* static object for efficiency or thread safety is a problem ? */
1102 throw SQLException("index out of range", *this, OUString(), 1, Any());
1103 }
1104 }
1105
checkBordersAndEnsureFetched(sal_Int32 index)1106 void OResultSet::checkBordersAndEnsureFetched(sal_Int32 index)
1107 {
1108 ensureResultFetched();
1109 checkColumnIndex(index);
1110 checkRowIndex();
1111 }
1112
1113 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1114