Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qsql_mimer.cpp
Go to the documentation of this file.
1// Copyright (C) 2022 The Qt Company Ltd.
2// Copyright (C) 2022 Mimer Information Technology
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4#include <qcoreapplication.h>
5#include <qvariant.h>
6#include <qmetatype.h>
7#include <qdatetime.h>
8#include <qloggingcategory.h>
9#include <qsqlerror.h>
10#include <qsqlfield.h>
11#include <qsqlindex.h>
12#include <qsqlrecord.h>
13#include <qsqlquery.h>
14#include <qsocketnotifier.h>
15#include <qstringlist.h>
16#include <qlocale.h>
17#if defined(Q_OS_WIN32)
18# include <QtCore/qt_windows.h>
19#endif
20#include <QtSql/private/qsqlresult_p.h>
21#include <QtSql/private/qsqldriver_p.h>
22#include "qsql_mimer.h"
23
24#define MIMER_DEFAULT_DATATYPE 1000
25
26Q_DECLARE_OPAQUE_POINTER(MimerSession)
27Q_DECLARE_METATYPE(MimerSession)
28
29Q_DECLARE_OPAQUE_POINTER(MimerStatement)
30Q_DECLARE_METATYPE(MimerStatement)
31
33
34static Q_LOGGING_CATEGORY(lcMimer, "qt.sql.mimer")
35
36enum class MimerColumnTypes {
37 Binary,
38 Clob,
39 Blob,
40 String,
41 Int,
42 Numeric,
43 Long,
44 Float,
45 Double,
46 Boolean,
47 Uuid,
48 Date,
49 Time,
52};
53
54using namespace Qt::StringLiterals;
55
57
58class QMimerSQLResult final : public QSqlResult
59{
60 Q_DECLARE_PRIVATE(QMimerSQLResult)
61public:
63 virtual ~QMimerSQLResult() override;
64 QVariant handle() const override;
65 static constexpr int genericError = -1;
66 static constexpr int lobChunkMaxSizeSet = 1048500;
67 static constexpr int lobChunkMaxSizeFetch = 65536;
68 static constexpr int maxStackStringSize = 200;
69 static constexpr int maxTimeStringSize = 18;
70 static constexpr int maxDateStringSize = 10;
71 static constexpr int maxTimestampStringSize = 29;
72
73private:
74 void cleanup();
75 bool fetch(int i) override;
76 bool fetchFirst() override;
77 bool fetchLast() override;
78 bool fetchNext() override;
79 QVariant data(int i) override;
80 bool isNull(int index) override;
81 bool reset(const QString &query) override;
82 int size() override;
83 int numRowsAffected() override;
84 QSqlRecord record() const override;
85 bool prepare(const QString &query) override;
86 bool execBatch(bool arrayBind = false) override;
87 bool exec() override;
88 qint64 currentRow();
89 QVariant lastInsertId() const override;
90};
91
93{
94 Q_DECLARE_PUBLIC(QMimerSQLDriver)
95public:
97 MimerSession sessionhandle;
100 void splitTableQualifier(const QString &qualifier, QString *schema, QString *table) const;
101};
102
135
136static QSqlError qMakeError(const QString &err, const int errCode, QSqlError::ErrorType type,
138{
139 QString msg;
140 if (p) {
141 size_t str_len;
142 int e_code;
143 int rc;
144 str_len = (rc = MimerGetError(p->sessionhandle, &e_code, NULL, 0)) + 1;
145 if (!MIMER_SUCCEEDED(rc)) {
146 msg = QCoreApplication::translate("QMimerSQL", "No Mimer SQL error for code %1")
147 .arg(errCode);
148 } else {
149 QVarLengthArray<wchar_t> tmp_buff((qsizetype)str_len);
150 if (!MIMER_SUCCEEDED(
151 rc = MimerGetError(p->sessionhandle, &e_code, tmp_buff.data(), str_len)))
152 msg = QCoreApplication::translate("QMimerSQL", "No Mimer SQL error for code %1")
153 .arg(errCode);
154 else
155 msg = QString::fromWCharArray(tmp_buff.data());
156 }
157 } else {
158 msg = QCoreApplication::translate("QMimerSQL", "Generic Mimer SQL error");
159 }
160
161 return QSqlError("QMIMER: "_L1 + err, msg, type, QString::number(errCode));
162}
163
164static QString msgCouldNotGet(const char *type, int column)
165{
166 //: Data type, column
167 return QCoreApplication::translate("QMimerSQLResult",
168 "Could not get %1, column %2").arg(QLatin1StringView(type)).arg(column);
169}
170
171static QString msgCouldNotSet(const char *type, int column)
172{
173 //: Data type, parameter
174 return QCoreApplication::translate("QMimerSQLResult",
175 "Could not set %1, parameter %2").arg(QLatin1StringView(type)).arg(column);
176}
177
181
182QMimerSQLDriver::QMimerSQLDriver(MimerSession *conn, QObject *parent)
183 : QSqlDriver(*new QMimerSQLDriverPrivate, parent)
184{
185 Q_D(QMimerSQLDriver);
186 if (conn)
187 d->sessionhandle = *conn;
188}
189
194
201
203{
204 cleanup();
205}
206
207static MimerColumnTypes mimerMapColumnTypes(int32_t t)
208{
209 switch (t) {
210 case MIMER_BINARY:
211 case MIMER_BINARY_VARYING:
212 return MimerColumnTypes::Binary;
213 case MIMER_BLOB:
214 case MIMER_NATIVE_BLOB:
215 return MimerColumnTypes::Blob;
216 case MIMER_CLOB:
217 case MIMER_NCLOB:
218 case MIMER_NATIVE_CLOB:
219 case MIMER_NATIVE_NCLOB:
220 return MimerColumnTypes::Clob;
221 case MIMER_DATE:
222 return MimerColumnTypes::Date;
223 case MIMER_TIME:
224 return MimerColumnTypes::Time;
225 case MIMER_TIMESTAMP:
226 return MimerColumnTypes::Timestamp;
227 case MIMER_INTERVAL_DAY:
228 case MIMER_INTERVAL_DAY_TO_HOUR:
229 case MIMER_INTERVAL_DAY_TO_MINUTE:
230 case MIMER_INTERVAL_DAY_TO_SECOND:
231 case MIMER_INTERVAL_HOUR:
232 case MIMER_INTERVAL_HOUR_TO_MINUTE:
233 case MIMER_INTERVAL_HOUR_TO_SECOND:
234 case MIMER_INTERVAL_MINUTE:
235 case MIMER_INTERVAL_MINUTE_TO_SECOND:
236 case MIMER_INTERVAL_MONTH:
237 case MIMER_INTERVAL_SECOND:
238 case MIMER_INTERVAL_YEAR:
239 case MIMER_INTERVAL_YEAR_TO_MONTH:
240 case MIMER_NCHAR:
241 case MIMER_CHARACTER:
242 case MIMER_CHARACTER_VARYING:
243 case MIMER_NCHAR_VARYING:
244 case MIMER_UTF8:
246 return MimerColumnTypes::String;
247 case MIMER_INTEGER:
248 case MIMER_DECIMAL:
249 case MIMER_FLOAT:
250 return MimerColumnTypes::Numeric;
251 case MIMER_BOOLEAN:
252 return MimerColumnTypes::Boolean;
253 case MIMER_T_BIGINT:
254 case MIMER_T_UNSIGNED_BIGINT:
255 case MIMER_NATIVE_BIGINT_NULLABLE:
256 case MIMER_NATIVE_BIGINT:
257 return MimerColumnTypes::Long;
258 case MIMER_NATIVE_REAL_NULLABLE:
259 case MIMER_NATIVE_REAL:
260 case MIMER_T_REAL:
261 return MimerColumnTypes::Float;
262 case MIMER_T_FLOAT:
263 case MIMER_NATIVE_DOUBLE_NULLABLE:
264 case MIMER_NATIVE_DOUBLE:
265 case MIMER_T_DOUBLE:
266 return MimerColumnTypes::Double;
267 case MIMER_NATIVE_INTEGER:
268 case MIMER_NATIVE_INTEGER_NULLABLE:
269 case MIMER_NATIVE_SMALLINT_NULLABLE:
270 case MIMER_NATIVE_SMALLINT:
271 case MIMER_T_INTEGER:
272 case MIMER_T_SMALLINT:
273 return MimerColumnTypes::Int;
274 case MIMER_UUID:
275 return MimerColumnTypes::Uuid;
276 default:
277 qCWarning(lcMimer) << "QMimerSQLDriver::mimerMapColumnTypes: Unknown data type:" << t;
278 }
279 return MimerColumnTypes::Unknown;
280}
281
283{
284 switch (t) {
285 case MIMER_BINARY:
286 case MIMER_BINARY_VARYING:
287 case MIMER_BLOB:
288 case MIMER_NATIVE_BLOB:
289 return QMetaType::QByteArray;
290 case MIMER_CLOB:
291 case MIMER_NCLOB:
292 case MIMER_NATIVE_CLOB:
293 case MIMER_NATIVE_NCLOB:
294 case MIMER_INTERVAL_DAY:
295 case MIMER_DECIMAL:
296 case MIMER_INTERVAL_DAY_TO_HOUR:
297 case MIMER_INTERVAL_DAY_TO_MINUTE:
298 case MIMER_INTERVAL_DAY_TO_SECOND:
299 case MIMER_INTERVAL_HOUR:
300 case MIMER_INTERVAL_HOUR_TO_MINUTE:
301 case MIMER_INTERVAL_HOUR_TO_SECOND:
302 case MIMER_INTERVAL_MINUTE:
303 case MIMER_INTERVAL_MINUTE_TO_SECOND:
304 case MIMER_INTERVAL_MONTH:
305 case MIMER_INTERVAL_SECOND:
306 case MIMER_INTERVAL_YEAR:
307 case MIMER_INTERVAL_YEAR_TO_MONTH:
308 case MIMER_NCHAR:
309 case MIMER_CHARACTER:
310 case MIMER_CHARACTER_VARYING:
311 case MIMER_NCHAR_VARYING:
312 case MIMER_UTF8:
314 case MIMER_INTEGER:
315 case MIMER_FLOAT:
316 return QMetaType::QString;
317 case MIMER_BOOLEAN:
318 return QMetaType::Bool;
319 case MIMER_T_BIGINT:
320 case MIMER_T_UNSIGNED_BIGINT:
321 case MIMER_NATIVE_BIGINT_NULLABLE:
322 case MIMER_NATIVE_BIGINT:
323 return QMetaType::LongLong;
324 case MIMER_NATIVE_REAL_NULLABLE:
325 case MIMER_NATIVE_REAL:
326 case MIMER_T_REAL:
327 return QMetaType::Float;
328 case MIMER_T_FLOAT:
329 case MIMER_NATIVE_DOUBLE_NULLABLE:
330 case MIMER_NATIVE_DOUBLE:
331 case MIMER_T_DOUBLE:
332 return QMetaType::Double;
333 case MIMER_NATIVE_INTEGER_NULLABLE:
334 case MIMER_T_INTEGER:
335 case MIMER_NATIVE_INTEGER:
336 return QMetaType::Int;
337 case MIMER_NATIVE_SMALLINT_NULLABLE:
338 case MIMER_T_SMALLINT:
339 return QMetaType::Int;
340 case MIMER_DATE:
341 return QMetaType::QDate;
342 case MIMER_TIME:
343 return QMetaType::QTime;
344 break;
345 case MIMER_TIMESTAMP:
346 return QMetaType::QDateTime;
347 case MIMER_UUID:
348 return QMetaType::QUuid;
349 default:
350 qCWarning(lcMimer) << "QMimerSQLDriver::qDecodeMSQLType: Unknown data type:" << t;
352 }
353}
354
356{
357 if (s == u"BINARY")
358 return MIMER_BINARY;
359 if (s == u"BINARY VARYING")
360 return MIMER_BINARY_VARYING;
361 if (s == u"BINARY LARGE OBJECT")
362 return MIMER_BLOB;
363 if (s == u"CHARACTER LARGE OBJECT")
364 return MIMER_CLOB;
365 if (s == u"NATIONAL CHAR LARGE OBJECT")
366 return MIMER_NCLOB;
367 if (s == u"INTERVAL DAY")
368 return MIMER_INTERVAL_DAY;
369 if (s == u"DECIMAL")
370 return MIMER_DECIMAL;
371 if (s == u"INTERVAL DAY TO HOUR")
372 return MIMER_INTERVAL_DAY_TO_HOUR;
373 if (s == u"INTERVAL DAY TO MINUTE")
374 return MIMER_INTERVAL_DAY_TO_MINUTE;
375 if (s == u"INTERVAL DAY TO SECOND")
376 return MIMER_INTERVAL_DAY_TO_SECOND;
377 if (s == u"INTERVAL HOUR")
378 return MIMER_INTERVAL_HOUR;
379 if (s == u"INTERVAL HOUR TO MINUTE")
380 return MIMER_INTERVAL_HOUR_TO_MINUTE;
381 if (s == u"INTERVAL HOUR TO SECOND")
382 return MIMER_INTERVAL_HOUR_TO_SECOND;
383 if (s == u"INTERVAL MINUTE")
384 return MIMER_INTERVAL_MINUTE;
385 if (s == u"INTERVAL MINUTE TO SECOND")
386 return MIMER_INTERVAL_MINUTE_TO_SECOND;
387 if (s == u"INTERVAL MONTH")
388 return MIMER_INTERVAL_MONTH;
389 if (s == u"INTERVAL SECOND")
390 return MIMER_INTERVAL_SECOND;
391 if (s == u"INTERVAL YEAR")
392 return MIMER_INTERVAL_YEAR;
393 if (s == u"INTERVAL YEAR TO MONTH")
394 return MIMER_INTERVAL_YEAR_TO_MONTH;
395 if (s == u"NATIONAL CHARACTER")
396 return MIMER_NCHAR;
397 if (s == u"CHARACTER")
398 return MIMER_CHARACTER;
399 if (s == u"CHARACTER VARYING")
400 return MIMER_CHARACTER_VARYING;
401 if (s == u"NATIONAL CHARACTER VARYING")
402 return MIMER_NCHAR_VARYING;
403 if (s == u"UTF-8")
404 return MIMER_UTF8;
405 if (s == u"BOOLEAN")
406 return MIMER_BOOLEAN;
407 if (s == u"BIGINT")
408 return MIMER_T_BIGINT;
409 if (s == u"REAL")
410 return MIMER_T_REAL;
411 if (s == u"FLOAT")
412 return MIMER_T_FLOAT;
413 if (s == u"DOUBLE PRECISION")
414 return MIMER_T_DOUBLE;
415 if (s == u"INTEGER")
416 return MIMER_T_INTEGER;
417 if (s == u"SMALLINT")
418 return MIMER_T_SMALLINT;
419 if (s == u"DATE")
420 return MIMER_DATE;
421 if (s == u"TIME")
422 return MIMER_TIME;
423 if (s == u"TIMESTAMP")
424 return MIMER_TIMESTAMP;
425 if (s == u"BUILTIN.UUID")
426 return MIMER_UUID;
427 if (s == u"USER-DEFINED")
429 qCWarning(lcMimer) << "QMimerSQLDriver::qLookupMimDataType: Unhandled data type:" << s;
431}
432
434{
435 Q_D(const QMimerSQLResult);
436 return QVariant::fromValue(d->statementhandle);
437}
438
439void QMimerSQLResult::cleanup()
440{
441 Q_D(QMimerSQLResult);
442 if (!driver() || !driver()->isOpen()) {
443 d->openCursor = false;
444 d->openStatement = false;
445 return;
446 }
447 if (d->openCursor) {
448 const int32_t err = MimerCloseCursor(d->statementhandle);
449 if (!MIMER_SUCCEEDED(err))
451 QCoreApplication::translate("QMimerSQLResult", "Could not close cursor"), err,
452 QSqlError::StatementError, d->drv_d_func()));
453 d->openCursor = false;
454 }
455 if (d->openStatement) {
456 const int32_t err = MimerEndStatement(&d->statementhandle);
457 if (!MIMER_SUCCEEDED(err))
459 QCoreApplication::translate("QMimerSQLResult", "Could not close statement"),
460 err, QSqlError::StatementError, d->drv_d_func()));
461 d->openStatement = false;
462 }
463 d->currentSize = -1;
464}
465
466qint64 QMimerSQLResult::currentRow()
467{
468 Q_D(const QMimerSQLResult);
469 return d->currentRow;
470}
471
473{
474 Q_D(const QMimerSQLResult);
475 int32_t err = 0;
476 if (!isActive() || !isSelect())
477 return false;
478 if (i == at())
479 return true;
480 if (i < 0)
481 return false;
482
483 if (isForwardOnly() && i < at())
484 return false;
485
486 if (isForwardOnly()) {
487 bool rc;
488 do {
489 rc = fetchNext();
490 } while (rc && currentRow() < i);
491 return rc;
492 } else {
493 err = MimerFetchScroll(d->statementhandle, MIMER_ABSOLUTE, i + 1);
494 if (err == MIMER_NO_DATA)
495 return false;
496 }
497 if (!MIMER_SUCCEEDED(err)) {
499 qMakeError(QCoreApplication::translate("QMimerSQLResult", "Fetch did not succeed"),
500 err, QSqlError::StatementError, d->drv_d_func()));
501 return false;
502 }
503 setAt(MimerCurrentRow(d->statementhandle) - 1);
504 return true;
505}
506
508{
509 Q_D(const QMimerSQLResult);
510 int32_t err = 0;
511 if (!isActive() || !isSelect())
512 return false;
513 if (isForwardOnly()) {
514 if (currentRow() < 0)
515 return fetchNext();
516 else if (currentRow() == 0)
517 setAt(0);
518 else
519 return false;
520 } else {
521 err = MimerFetchScroll(d->statementhandle, MIMER_FIRST, 0);
522 if (MIMER_SUCCEEDED(err) && err != MIMER_NO_DATA)
523 setAt(0);
524 }
525 if (!MIMER_SUCCEEDED(err)) {
527 QCoreApplication::translate("QMimerSQLResult", "Fetch first did not succeed"), err,
528 QSqlError::StatementError, d->drv_d_func()));
529 return false;
530 }
531 if (err == MIMER_NO_DATA)
532 return false;
533 return true;
534}
535
537{
538 Q_D(const QMimerSQLResult);
539 int32_t err = 0;
540 int row = 0;
541 if (!isActive() || !isSelect())
542 return false;
543 if (isForwardOnly()) {
544 bool rc;
545 do {
546 rc = fetchNext();
547 } while (rc);
548
549 return currentRow() >= 0;
550 } else {
551 err = MimerFetchScroll(d->statementhandle, static_cast<std::int32_t>(MIMER_LAST), 0);
552 if (err == MIMER_NO_DATA)
553 return false;
554 if (MIMER_SUCCEEDED(err)) {
555 row = MimerCurrentRow(d->statementhandle) - 1;
556 } else {
558 QCoreApplication::translate("QMimerSQLResult:", "Fetch last did not succeed"),
559 err, QSqlError::StatementError, d->drv_d_func()));
560 return false;
561 }
562 }
563
564 if (row < 0) {
566 return false;
567 } else {
568 setAt(row);
569 return true;
570 }
571}
572
574{
575 Q_D(QMimerSQLResult);
576 int32_t err = 0;
577 if (!isActive() || !isSelect())
578 return false;
579 if (isForwardOnly())
580 err = MimerFetch(d->statementhandle);
581 else
582 err = MimerFetchScroll(d->statementhandle, MIMER_NEXT, 0);
583 if (!MIMER_SUCCEEDED(err)) {
585 QCoreApplication::translate("QMimerSQLResult", "Could not fetch next row"), err,
586 QSqlError::StatementError, d->drv_d_func()));
587 if (isForwardOnly())
588 d->currentRow = QSql::BeforeFirstRow;
589 return false;
590 }
591 if (err == MIMER_NO_DATA)
592 return false;
593 if (isForwardOnly())
594 setAt(++d->currentRow);
595 else
596 setAt(MimerCurrentRow(d->statementhandle) - 1);
597 return true;
598}
599
601{
602 Q_D(QMimerSQLResult);
603 int32_t err;
604 int32_t mType;
605 if (d->callWithOut) {
606 if (i >= MimerParameterCount(d->statementhandle)) {
608 QCoreApplication::translate("QMimerSQLResult:", "Column %1 out of range")
609 .arg(i),
611 return QVariant();
612 }
613 mType = MimerParameterType(d->statementhandle, static_cast<std::int16_t>(i + 1));
614 } else {
615 if (i >= MimerColumnCount(d->statementhandle)) {
617 QCoreApplication::translate("QMimerSQLResult:", "Column %1 out of range")
618 .arg(i),
620 return QVariant();
621 }
622 mType = MimerColumnType(d->statementhandle, static_cast<std::int16_t>(i + 1));
623 }
624 const QMetaType::Type type = qDecodeMSQLType(mType);
625 const MimerColumnTypes mimDataType = mimerMapColumnTypes(mType);
626 err = MimerIsNull(d->statementhandle, static_cast<std::int16_t>(i + 1));
627 if (err > 0) {
628 return QVariant(QMetaType(type), nullptr);
629 } else {
630 switch (mimDataType) {
631 case MimerColumnTypes::Date: {
632 wchar_t dateString_w[maxDateStringSize + 1];
633 err = MimerGetString(d->statementhandle, static_cast<std::int16_t>(i + 1), dateString_w,
634 sizeof(dateString_w) / sizeof(dateString_w[0]));
635 if (!MIMER_SUCCEEDED(err)) {
637 err, QSqlError::StatementError, d->drv_d_func()));
638 return QVariant(QMetaType(type), nullptr);
639 }
640 return QDate::fromString(QString::fromWCharArray(dateString_w), "yyyy-MM-dd"_L1);
641 }
642 case MimerColumnTypes::Time: {
643 wchar_t timeString_w[maxTimeStringSize + 1];
644 err = MimerGetString(d->statementhandle, static_cast<std::int16_t>(i + 1), timeString_w,
645 sizeof(timeString_w) / sizeof(timeString_w[0]));
646 if (!MIMER_SUCCEEDED(err)) {
648 err, QSqlError::StatementError, d->drv_d_func()));
649 return QVariant(QMetaType(type), nullptr);
650 }
651 QString timeString = QString::fromWCharArray(timeString_w);
652 QString timeFormatString = "HH:mm:ss"_L1;
653 if (timeString.size() > 8) {
654 timeFormatString.append(".zzz"_L1);
655 timeString = timeString.left(12);
656 }
657 return QTime::fromString(timeString, timeFormatString);
658 }
659 case MimerColumnTypes::Timestamp: {
660 wchar_t dateTimeString_w[maxTimestampStringSize + 1];
661 err = MimerGetString(d->statementhandle, static_cast<std::int16_t>(i + 1),
662 dateTimeString_w,
663 sizeof(dateTimeString_w) / sizeof(dateTimeString_w[0]));
664 if (!MIMER_SUCCEEDED(err)) {
666 qMakeError(msgCouldNotGet("date time", i),
667 err, QSqlError::StatementError, d->drv_d_func()));
668 return QVariant(QMetaType(type), nullptr);
669 }
670 QString dateTimeString = QString::fromWCharArray(dateTimeString_w);
671 QString dateTimeFormatString = "yyyy-MM-dd HH:mm:ss"_L1;
672 if (dateTimeString.size() > 19) {
673 dateTimeFormatString.append(".zzz"_L1);
674 dateTimeString = dateTimeString.left(23);
675 }
676 return QDateTime::fromString(dateTimeString, dateTimeFormatString);
677 }
678 case MimerColumnTypes::Int: {
679 int resInt;
680 err = MimerGetInt32(d->statementhandle, static_cast<std::int16_t>(i + 1), &resInt);
681 if (!MIMER_SUCCEEDED(err)) {
683 err, QSqlError::StatementError, d->drv_d_func()));
684 return QVariant(QMetaType(type), nullptr);
685 }
686 return resInt;
687 }
688 case MimerColumnTypes::Long: {
689 int64_t resLongLong;
690 err = MimerGetInt64(d->statementhandle, static_cast<std::int16_t>(i + 1), &resLongLong);
691 if (!MIMER_SUCCEEDED(err)) {
693 err, QSqlError::StatementError, d->drv_d_func()));
694 return QVariant(QMetaType(type), nullptr);
695 }
696 return (qlonglong)resLongLong;
697 }
698 case MimerColumnTypes::Boolean: {
699 err = MimerGetBoolean(d->statementhandle, static_cast<std::int16_t>(i + 1));
700 if (!MIMER_SUCCEEDED(err)) {
702 qMakeError(msgCouldNotGet("boolean", i),
703 err, QSqlError::StatementError, d->drv_d_func()));
704 return QVariant(QMetaType(type), nullptr);
705 }
706 return err == 1;
707 }
708 case MimerColumnTypes::Float: {
709 float resFloat;
710 err = MimerGetFloat(d->statementhandle, static_cast<std::int16_t>(i + 1), &resFloat);
711 if (!MIMER_SUCCEEDED(err)) {
713 err, QSqlError::StatementError, d->drv_d_func()));
714 return QVariant(QMetaType(type), nullptr);
715 }
716 return resFloat;
717 }
718 case MimerColumnTypes::Double: {
719 double resDouble;
720 err = MimerGetDouble(d->statementhandle, static_cast<std::int16_t>(i + 1), &resDouble);
721 if (!MIMER_SUCCEEDED(err)) {
723 qMakeError(msgCouldNotGet("double", i),
724 err, QSqlError::StatementError, d->drv_d_func()));
725 return QVariant(QMetaType(type), nullptr);
726 }
727 switch (numericalPrecisionPolicy()) {
729 return static_cast<std::int32_t>(resDouble);
731 return static_cast<qint64>(resDouble);
733 return static_cast<qreal>(resDouble);
735 return QString::number(resDouble, 'g', 17);
736 }
737 return QVariant(QMetaType(type), nullptr);
738 }
739 case MimerColumnTypes::Binary: {
740 QByteArray byteArray;
741 // Get size
742 err = MimerGetBinary(d->statementhandle, static_cast<std::int16_t>(i + 1), NULL, 0);
743 if (MIMER_SUCCEEDED(err)) {
744 byteArray.resize(err);
745 err = MimerGetBinary(d->statementhandle, static_cast<std::int16_t>(i + 1),
746 byteArray.data(), err);
747 }
748 if (!MIMER_SUCCEEDED(err)) {
750 qMakeError(msgCouldNotGet("binary", i),
751 err, QSqlError::StatementError, d->drv_d_func()));
752 return QVariant(QMetaType(type), nullptr);
753 }
754 return byteArray;
755 }
756 case MimerColumnTypes::Blob: {
757 QByteArray byteArray;
758 size_t size;
759 err = MimerGetLob(d->statementhandle, static_cast<std::int16_t>(i + 1), &size,
760 &d->lobhandle);
761 if (MIMER_SUCCEEDED(err)) {
762 constexpr size_t maxSize = lobChunkMaxSizeFetch;
763 QVarLengthArray<char> blobchar(lobChunkMaxSizeFetch);
764 byteArray.reserve(size);
765 size_t left_to_return = size;
766 while (left_to_return > 0) {
767 const size_t bytesToReceive =
768 left_to_return <= maxSize ? left_to_return : maxSize;
769 err = MimerGetBlobData(&d->lobhandle, blobchar.data(), bytesToReceive);
770 byteArray.append(QByteArray::fromRawData(blobchar.data(), bytesToReceive));
771 left_to_return -= bytesToReceive;
772 if (!MIMER_SUCCEEDED(err)) {
774 err, QSqlError::StatementError, d->drv_d_func()));
775 return QVariant(QMetaType(type), nullptr);
776 }
777 }
778 } else {
780 err, QSqlError::StatementError, d->drv_d_func()));
781 return QVariant(QMetaType(type), nullptr);
782 }
783 return byteArray;
784 }
785 case MimerColumnTypes::Numeric:
786 case MimerColumnTypes::String: {
787 wchar_t resString_w[maxStackStringSize + 1];
788 // Get size
789 err = MimerGetString(d->statementhandle, static_cast<std::int16_t>(i + 1), resString_w,
790 0);
791 if (MIMER_SUCCEEDED(err)) {
792 int size = err;
793 if (err <= maxStackStringSize) { // For smaller strings, use a small buffer for
794 // efficiency
795 err = MimerGetString(d->statementhandle, static_cast<std::int16_t>(i + 1),
796 resString_w, maxStackStringSize + 1);
797 if (MIMER_SUCCEEDED(err))
798 return QString::fromWCharArray(resString_w);
799 } else { // For larger strings, dynamically allocate memory
800 QVarLengthArray<wchar_t> largeResString_w(size + 1);
801 err = MimerGetString(d->statementhandle, static_cast<std::int16_t>(i + 1),
802 largeResString_w.data(), size + 1);
803 if (MIMER_SUCCEEDED(err))
804 return QString::fromWCharArray(largeResString_w.data());
805 }
806 }
808 mimDataType == MimerColumnTypes::Numeric ? "numeric" : "string", i),
809 err, QSqlError::StatementError, d->drv_d_func()));
810 return QVariant(QMetaType(type), nullptr);
811 }
812 case MimerColumnTypes::Clob: {
813 size_t size;
814 err = MimerGetLob(d->statementhandle, static_cast<std::int16_t>(i + 1), &size,
815 &d->lobhandle);
816 if (MIMER_SUCCEEDED(err)) {
817 constexpr size_t maxSize = lobChunkMaxSizeFetch;
818 QVarLengthArray<wchar_t> clobstring_w(lobChunkMaxSizeFetch + 1);
819
820 size_t left_to_return = size;
821 QString returnString;
822 while (left_to_return > 0) {
823 const size_t bytesToReceive =
824 left_to_return <= maxSize ? left_to_return : maxSize;
825 err = MimerGetNclobData(&d->lobhandle, clobstring_w.data(), bytesToReceive + 1);
826 returnString.append(QString::fromWCharArray(clobstring_w.data()));
827 left_to_return -= bytesToReceive;
828 if (!MIMER_SUCCEEDED(err)) {
830 err, QSqlError::StatementError, d->drv_d_func()));
831 return QVariant(QMetaType(type), nullptr);
832 }
833 }
834 return returnString;
835 }
837 err, QSqlError::StatementError, d->drv_d_func()));
838 return QVariant(QMetaType(type), nullptr);
839 }
840 case MimerColumnTypes::Uuid: {
841 unsigned char uuidChar[16];
842 err = MimerGetUUID(d->statementhandle, static_cast<std::int16_t>(i + 1), uuidChar);
843 if (!MIMER_SUCCEEDED(err)) {
845 err, QSqlError::StatementError, d->drv_d_func()));
846 return QVariant(QMetaType(type), nullptr);
847 }
848 const QByteArray uuidByteArray = QByteArray(reinterpret_cast<char *>(uuidChar), 16);
849 return QUuid::fromRfc4122(uuidByteArray);
850 }
851 case MimerColumnTypes::Unknown:
852 default:
854 QCoreApplication::translate("QMimerSQLResult", "Unknown data type %1").arg(i),
856 }
857 return QVariant(QMetaType(type), nullptr);
858 }
859}
860
862{
863 Q_D(const QMimerSQLResult);
864 const int32_t rc = MimerIsNull(d->statementhandle, static_cast<std::int16_t>(index + 1));
865 if (!MIMER_SUCCEEDED(rc)) {
867 QCoreApplication::translate("QMimerSQLResult", "Could not check null, column %1")
868 .arg(index),
869 rc, QSqlError::StatementError, d->drv_d_func()));
870 return false;
871 }
872 return rc != 0;
873}
874
876{
877 if (!prepare(query))
878 return false;
879 return exec();
880}
881
883{
884 Q_D(QMimerSQLResult);
885 if (!isActive() || !isSelect() || isForwardOnly())
886 return -1;
887
888 if (d->currentSize != -1)
889 return d->currentSize;
890
891 const int currentRow = MimerCurrentRow(d->statementhandle);
892 MimerFetchScroll(d->statementhandle, static_cast<std::int32_t>(MIMER_LAST), 0);
893 int size = MimerCurrentRow(d->statementhandle);
894 if (!MIMER_SUCCEEDED(size))
895 size = -1;
896 MimerFetchScroll(d->statementhandle, MIMER_ABSOLUTE, currentRow);
897 d->currentSize = size;
898 return size;
899}
900
902{
903 Q_D(const QMimerSQLResult);
904 return d->rowsAffected;
905}
906
908{
909 Q_D(const QMimerSQLResult);
910 QSqlRecord rec;
911 if (!isActive() || !isSelect() || !driver())
912 return rec;
913 QSqlField field;
914 const int colSize = MimerColumnCount(d->statementhandle);
915 for (int i = 0; i < colSize; i++) {
916 wchar_t colName_w[100];
917 MimerColumnName(d->statementhandle, static_cast<std::int16_t>(i + 1), colName_w,
918 sizeof(colName_w) / sizeof(colName_w[0]));
919 field.setName(QString::fromWCharArray(colName_w));
920 const int32_t mType = MimerColumnType(d->statementhandle, static_cast<std::int16_t>(i + 1));
921 const QMetaType::Type type = qDecodeMSQLType(mType);
922 field.setMetaType(QMetaType(type));
923 field.setValue(QVariant(field.metaType()));
924 // field.setPrecision(); Should be implemented once the Mimer API can give this
925 // information.
926 // field.setLength(); Should be implemented once the Mimer API can give
927 // this information.
928 rec.insert(i, field);
929 }
930 return rec;
931}
932
934{
935 Q_D(QMimerSQLResult);
936 int32_t err;
937 if (!driver())
938 return false;
939 if (!d->preparedQuery)
941 if (query.isEmpty())
942 return false;
943 cleanup();
944 const int option = isForwardOnly() ? MIMER_FORWARD_ONLY : MIMER_SCROLLABLE;
945 err = MimerBeginStatement8(d->drv_d_func()->sessionhandle, query.toUtf8().constData(), option,
946 &d->statementhandle);
947 if (err == MIMER_STATEMENT_CANNOT_BE_PREPARED) {
948 err = MimerExecuteStatement8(d->drv_d_func()->sessionhandle, query.toUtf8().constData());
949 if (MIMER_SUCCEEDED(err)) {
950 d->executedStatement = true;
951 d->openCursor = false;
952 d->openStatement = false;
953 return true;
954 }
955 }
956 if (!MIMER_SUCCEEDED(err)) {
958 "Could not prepare/execute statement"),
959 err, QSqlError::StatementError, d->drv_d_func()));
960 return false;
961 }
962 d->openStatement = true;
963 return true;
964}
965
967{
968 Q_D(QMimerSQLResult);
969 int32_t err;
970 if (!driver())
971 return false;
972 if (!d->preparedQuery)
973 return QSqlResult::exec();
974 if (d->executedStatement) {
975 d->executedStatement = false;
976 return true;
977 }
978 if (d->openCursor) {
980 err = MimerCloseCursor(d->statementhandle);
981 d->openCursor = false;
982 d->currentSize = -1;
983 }
984 QVector<QVariant> &values = boundValues();
985 if (d->execBatch)
986 values = d->batch_vector;
987 int mimParamCount = MimerParameterCount(d->statementhandle);
988 if (!MIMER_SUCCEEDED(mimParamCount))
989 mimParamCount = 0;
990 if (mimParamCount != values.size()) {
992 QCoreApplication::translate("QMimerSQLResult", "Wrong number of parameters"),
994 return false;
995 }
996 for (int i = 0; i < mimParamCount; i++) {
997 if (bindValueType(i) == QSql::Out) {
998 d->callWithOut = true;
999 continue;
1000 }
1001 const QVariant &val = values.at(i);
1002 if (QSqlResultPrivate::isVariantNull(val) || val.isNull() || val.toString().isNull()) {
1003 err = MimerSetNull(d->statementhandle, i + 1);
1004 if (!MIMER_SUCCEEDED(err)) {
1006 qMakeError(msgCouldNotSet("null", i),
1007 err, QSqlError::StatementError, d->drv_d_func()));
1008 return false;
1009 }
1010 continue;
1011 }
1012
1013 const int mimParamType = MimerParameterType(d->statementhandle, i + 1);
1014 const MimerColumnTypes mimDataType = mimerMapColumnTypes(mimParamType);
1015 switch (mimDataType) {
1016 case MimerColumnTypes::Int: {
1017 bool convertOk;
1018 err = MimerSetInt32(d->statementhandle, i + 1, val.toInt(&convertOk));
1019 if (!convertOk || !MIMER_SUCCEEDED(err)) {
1021 qMakeError(msgCouldNotSet("int32", i),
1022 convertOk ? err : genericError, QSqlError::StatementError,
1023 convertOk ? d->drv_d_func() : nullptr));
1024 return false;
1025 }
1026 break;
1027 }
1028 case MimerColumnTypes::Long: {
1029 bool convertOk;
1030 err = MimerSetInt64(d->statementhandle, i + 1, val.toLongLong(&convertOk));
1031 if (!convertOk || !MIMER_SUCCEEDED(err)) {
1033 qMakeError(msgCouldNotSet("int64", i),
1034 convertOk ? err : genericError, QSqlError::StatementError,
1035 convertOk ? d->drv_d_func() : nullptr));
1036 return false;
1037 }
1038 break;
1039 }
1040 case MimerColumnTypes::Float: {
1041 bool convertOk;
1042 err = MimerSetFloat(d->statementhandle, i + 1, val.toFloat(&convertOk));
1043 if (!convertOk || !MIMER_SUCCEEDED(err)) {
1045 qMakeError(msgCouldNotSet("float", i),
1046 convertOk ? err : genericError, QSqlError::StatementError,
1047 convertOk ? d->drv_d_func() : nullptr));
1048 return false;
1049 }
1050 break;
1051 }
1052 case MimerColumnTypes::Double: {
1053 bool convertOk;
1054 err = MimerSetDouble(d->statementhandle, i + 1, val.toDouble(&convertOk));
1055 if (!convertOk || !MIMER_SUCCEEDED(err)) {
1057 qMakeError(msgCouldNotSet("double", i),
1058 convertOk ? err : genericError, QSqlError::StatementError,
1059 convertOk ? d->drv_d_func() : nullptr));
1060 return false;
1061 }
1062 break;
1063 }
1064 case MimerColumnTypes::Binary: {
1065 const QByteArray binArr = val.toByteArray();
1066 size_t size = static_cast<std::size_t>(binArr.size());
1067 err = MimerSetBinary(d->statementhandle, i + 1, binArr.data(), size);
1068 if (!MIMER_SUCCEEDED(err)) {
1070 qMakeError(msgCouldNotSet("binary", i),
1071 err, QSqlError::StatementError, d->drv_d_func()));
1072 return false;
1073 }
1074 break;
1075 }
1076 case MimerColumnTypes::Boolean: {
1077 err = MimerSetBoolean(d->statementhandle, i + 1, val.toBool() == true ? 1 : 0);
1078 if (!MIMER_SUCCEEDED(err)) {
1080 qMakeError(msgCouldNotSet("boolean", i),
1081 err, QSqlError::StatementError, d->drv_d_func()));
1082 return false;
1083 }
1084 break;
1085 }
1086 case MimerColumnTypes::Uuid: {
1087 const QByteArray uuidArray =
1088 QByteArray::fromHex(val.toUuid().toString(QUuid::WithoutBraces).toLatin1());
1089 const unsigned char *uuid =
1090 reinterpret_cast<const unsigned char *>(uuidArray.constData());
1091 err = MimerSetUUID(d->statementhandle, i + 1, uuid);
1092 if (!MIMER_SUCCEEDED(err)) {
1094 qMakeError(msgCouldNotSet("UUID", i),
1095 err, QSqlError::StatementError, d->drv_d_func()));
1096 return false;
1097 }
1098 break;
1099 }
1100 case MimerColumnTypes::Numeric:
1101 case MimerColumnTypes::String: {
1102 QByteArray string_b = val.toString().trimmed().toUtf8();
1103 const char *string_u = string_b.constData();
1104 err = MimerSetString8(d->statementhandle, i + 1, string_u);
1105 if (!MIMER_SUCCEEDED(err)) {
1108 mimDataType == MimerColumnTypes::Numeric ? "numeric" : "string", i),
1109 err, QSqlError::StatementError, d->drv_d_func()));
1110 return false;
1111 }
1112 break;
1113 }
1114 case MimerColumnTypes::Date: {
1115 err = MimerSetString8(d->statementhandle, i + 1, val.toString().toUtf8().constData());
1116 if (!MIMER_SUCCEEDED(err)) {
1118 qMakeError(msgCouldNotSet("date", i),
1119 err, QSqlError::StatementError, d->drv_d_func()));
1120 return false;
1121 }
1122 break;
1123 }
1124 case MimerColumnTypes::Time: {
1125 QString timeFormatString = "hh:mm:ss"_L1;
1126 const QTime timeVal = val.toTime();
1127 if (timeVal.msec() > 0)
1128 timeFormatString.append(".zzz"_L1);
1129 err = MimerSetString8(d->statementhandle, i + 1,
1130 timeVal.toString(timeFormatString).toUtf8().constData());
1131 if (!MIMER_SUCCEEDED(err)) {
1133 qMakeError(msgCouldNotSet("time", i),
1134 err, QSqlError::StatementError, d->drv_d_func()));
1135 return false;
1136 }
1137 break;
1138 }
1139 case MimerColumnTypes::Timestamp: {
1140 QString dateTimeFormatString = "yyyy-MM-dd hh:mm:ss"_L1;
1141 const QDateTime dateTimeVal = val.toDateTime();
1142 if (dateTimeVal.time().msec() > 0)
1143 dateTimeFormatString.append(".zzz"_L1);
1144 err = MimerSetString8(
1145 d->statementhandle, i + 1,
1146 val.toDateTime().toString(dateTimeFormatString).toUtf8().constData());
1147 if (!MIMER_SUCCEEDED(err)) {
1149 err, QSqlError::StatementError, d->drv_d_func()));
1150 return false;
1151 }
1152 break;
1153 }
1154 case MimerColumnTypes::Blob: {
1155 QByteArray blobArr = val.toByteArray();
1156 const char *blobData = blobArr.constData();
1157 qsizetype size = blobArr.size();
1158 err = MimerSetLob(d->statementhandle, i + 1, size, &d->lobhandle);
1159 if (MIMER_SUCCEEDED(err)) {
1160 qsizetype maxSize = lobChunkMaxSizeSet;
1161 if (size > maxSize) {
1162 qsizetype left_to_send = size;
1163 for (qsizetype k = 0; left_to_send > 0; k++) {
1164 if (left_to_send <= maxSize) {
1165 err = MimerSetBlobData(&d->lobhandle, &blobData[k * maxSize],
1166 left_to_send);
1167 left_to_send = 0;
1168 } else {
1169 err = MimerSetBlobData(&d->lobhandle, &blobData[k * maxSize], maxSize);
1170 left_to_send = left_to_send - maxSize;
1171 }
1172 }
1173 if (!MIMER_SUCCEEDED(err)) {
1175 qMakeError(msgCouldNotSet("BLOB byte array", i),
1176 err, QSqlError::StatementError, d->drv_d_func()));
1177 return false;
1178 }
1179 } else {
1180 err = MimerSetBlobData(&d->lobhandle, blobArr, size);
1181 }
1182 }
1183 if (!MIMER_SUCCEEDED(err)) {
1184 setLastError(qMakeError(msgCouldNotSet("BLOB byte array", i),
1185 err, QSqlError::StatementError, d->drv_d_func()));
1186 return false;
1187 }
1188 break;
1189 }
1190 case MimerColumnTypes::Clob: {
1191 QByteArray string_b = val.toString().trimmed().toUtf8();
1192 const char *string_u = string_b.constData();
1193 size_t size_c = 1;
1194 size_t size = 0;
1195 while (string_u[size++])
1196 if ((string_u[size] & 0xc0) != 0x80)
1197 size_c++;
1198 err = MimerSetLob(d->statementhandle, i + 1, size_c, &d->lobhandle);
1199 if (MIMER_SUCCEEDED(err)) {
1200 constexpr size_t maxSize = lobChunkMaxSizeSet;
1201 if (size > maxSize) {
1202 size_t left_to_send = size;
1203 size_t pos = 0;
1204 uint step_back = 0;
1205 while (left_to_send > 0 && step_back < maxSize) {
1206 step_back = 0;
1207 if (left_to_send <= maxSize) {
1208 err = MimerSetNclobData8(&d->lobhandle, &string_u[pos], left_to_send);
1209 left_to_send = 0;
1210 } else {
1211 // Check that we don't split a multi-byte utf-8 characters
1212 while (pos + maxSize - step_back > 0
1213 && (string_u[pos + maxSize - step_back] & 0xc0) == 0x80)
1214 step_back++;
1215 err = MimerSetNclobData8(&d->lobhandle, &string_u[pos],
1216 maxSize - step_back);
1217 left_to_send = left_to_send - maxSize + step_back;
1218 pos += maxSize - step_back;
1219 }
1220 if (!MIMER_SUCCEEDED(err)) {
1222 err, QSqlError::StatementError, d->drv_d_func()));
1223 return false;
1224 }
1225 }
1226 } else {
1227 err = MimerSetNclobData8(&d->lobhandle, string_u, size);
1228 }
1229 }
1230 if (!MIMER_SUCCEEDED(err)) {
1232 qMakeError(msgCouldNotSet("CLOB", i),
1233 err, QSqlError::StatementError, d->drv_d_func()));
1234 return false;
1235 }
1236 break;
1237 }
1238 case MimerColumnTypes::Unknown:
1239 default:
1241 QCoreApplication::translate("QMimerSQLResult", "Unknown datatype, parameter %1")
1242 .arg(i),
1244 return false;
1245 }
1246 }
1247 if (d->execBatch)
1248 return true;
1249 err = MimerExecute(d->statementhandle);
1250 if (MIMER_SUCCEEDED(err)) {
1251 d->rowsAffected = err;
1252 int k = 0;
1253 for (qsizetype i = 0; i < values.size(); i++) {
1255 bindValue(i, data(k), QSql::In);
1256 k++;
1257 }
1258 }
1259 d->callWithOut = false;
1260 }
1261 setSelect(false);
1262 if (MIMER_SEQUENCE_ERROR == err) {
1263 err = MimerOpenCursor(d->statementhandle);
1264 d->rowsAffected = err;
1265 d->openCursor = true;
1266 d->currentRow = QSql::BeforeFirstRow;
1267 setSelect(true);
1268 }
1269 if (!MIMER_SUCCEEDED(err)) {
1271 qMakeError(QCoreApplication::translate("QMimerSQLResult",
1272 "Could not execute statement/open cursor"),
1273 err, QSqlError::StatementError, d->drv_d_func()));
1274 return false;
1275 }
1276 setActive(true);
1277 return true;
1278}
1279
1280bool QMimerSQLResult::execBatch(bool arrayBind)
1281{
1282 Q_D(QMimerSQLResult);
1283 Q_UNUSED(arrayBind);
1284 int32_t err;
1285 const QVector<QVariant> values = boundValues();
1286
1287 // Check that we only have input parameters. Currently
1288 // we can only handle batch operations without output parameters.
1289 for (qsizetype i = 0; i < values.first().toList().size(); i++)
1292 "QMimerSQLResult",
1293 "Only input parameters can be used in batch operations"),
1295 d->execBatch = false;
1296 return false;
1297 }
1298 d->execBatch = true;
1299 for (qsizetype i = 0; i < values.first().toList().size(); i++) {
1300 for (qsizetype j = 0; j < values.size(); j++)
1301 d->batch_vector.append(values.at(j).toList().at(i));
1302 exec();
1303 if (i != (values.at(0).toList().size() - 1)) {
1304 err = MimerAddBatch(d->statementhandle);
1305 if (!MIMER_SUCCEEDED(err)) {
1307 //: %1 is the batch number
1308 QCoreApplication::translate("QMimerSQLResult", "Could not add batch %1")
1309 .arg(i),
1310 err, QSqlError::StatementError, d->drv_d_func()));
1311 d->execBatch = false;
1312 return false;
1313 }
1314 }
1315 d->batch_vector.clear();
1316 }
1317 d->execBatch = false;
1318 err = MimerExecute(d->statementhandle);
1319 if (!MIMER_SUCCEEDED(err)) {
1321 QCoreApplication::translate("QMimerSQLResult", "Could not execute batch"), err,
1322 QSqlError::StatementError, d->drv_d_func()));
1323 return false;
1324 }
1325 return true;
1326}
1327
1329{
1330 Q_D(const QMimerSQLResult);
1331 int64_t lastSequence;
1332 const int32_t err = MimerGetSequenceInt64(d->statementhandle, &lastSequence);
1333 if (!MIMER_SUCCEEDED(err))
1334 return QVariant(QMetaType(QMetaType::LongLong), nullptr);
1335 return QVariant(qint64(lastSequence));
1336}
1337
1339{
1340 switch (f) {
1341 case NamedPlaceholders: // Is true in reality but Qt parses Sql statement...
1342 case EventNotifications:
1344 case MultipleResultSets:
1345 case SimpleLocking:
1346 case CancelQuery:
1347 return false;
1348 case FinishQuery:
1349 case LastInsertId:
1350 case Transactions:
1351 case QuerySize:
1352 case BLOB:
1353 case Unicode:
1354 case PreparedQueries:
1356 case BatchOperations:
1357 return true;
1358 }
1359 return true;
1360}
1361
1362bool QMimerSQLDriver::open(const QString &db, const QString &user, const QString &password,
1363 const QString &host, int port, const QString &connOpts)
1364{
1365 Q_D(QMimerSQLDriver);
1366 Q_UNUSED(host);
1367 Q_UNUSED(port);
1368 Q_UNUSED(connOpts);
1369 if (isOpen())
1370 close();
1371 const int32_t err = MimerBeginSession8(db.toUtf8().constData(), user.toUtf8().constData(),
1372 password.toUtf8().constData(), &d->sessionhandle);
1373 if (!MIMER_SUCCEEDED(err)) {
1375 QCoreApplication::translate("QMimerSQLDriver", "Could not connect to database")
1376 + " "_L1 + db,
1377 err, QSqlError::ConnectionError, nullptr));
1378 setOpenError(true);
1379 return false;
1380 }
1381 d->dbUser = user;
1382 d->dbName = db;
1383 setOpen(true);
1384 setOpenError(false);
1385 return true;
1386}
1387
1389{
1390 Q_D(QMimerSQLDriver);
1391 if (isOpen()) {
1392 const int end_err = MimerEndSession(&d->sessionhandle);
1393 if (MIMER_SUCCEEDED(end_err)) {
1394 setOpen(false);
1395 setOpenError(false);
1396 }
1397 }
1398}
1399
1401{
1402 return new QMimerSQLResult(this);
1403}
1404
1406{
1407 QStringList tl;
1408 if (!isOpen())
1409 return tl;
1411 QString sql;
1412 switch (type) {
1413 case QSql::Tables: {
1414 sql = "select table_name from information_schema.tables where "
1415 "table_type=\'BASE TABLE\' AND table_schema = CURRENT_USER"_L1;
1416 break;
1417 }
1418 case QSql::SystemTables: {
1419 sql = "select table_name from information_schema.tables where "
1420 "table_type=\'BASE TABLE\' AND table_schema = \'SYSTEM\'"_L1;
1421 break;
1422 }
1423 case QSql::Views: {
1424 sql = "select table_name from information_schema.tables where "
1425 "table_type=\'VIEW\' AND table_schema = CURRENT_USER"_L1;
1426 break;
1427 }
1428 case QSql::AllTables: {
1429 sql = "select table_name from information_schema.tables where "
1430 "(table_type=\'VIEW\' or table_type=\'BASE TABLE\')"
1431 " AND (table_schema = CURRENT_USER OR table_schema =\'SYSTEM\')"_L1;
1432 break;
1433 }
1434 default:
1435 break;
1436 }
1437 if (sql.length() > 0) {
1438 t.exec(sql);
1439 while (t.next())
1440 tl.append(t.value(0).toString());
1441 }
1442 return tl;
1443}
1444
1446{
1447 Q_D(const QMimerSQLDriver);
1448 if (!isOpen())
1449 return QSqlIndex();
1450 QString table = tablename;
1453 QSqlIndex index(tablename);
1455 QString schema;
1456 QString qualifiedName = table;
1457 d->splitTableQualifier(qualifiedName, &schema, &table);
1458 QString sql =
1459 "select information_schema.ext_access_paths.column_name,"
1460 "case when data_type = 'INTERVAL' then 'INTERVAL '|| interval_type "
1461 "when data_type = 'INTEGER' and numeric_precision > 10 then 'BIGINT' "
1462 "when data_type = 'INTEGER' and numeric_precision <= 10 AND NUMERIC_PRECISION > 5 "
1463 "then 'INTEGER' when data_type = 'INTEGER' and numeric_precision <= 5 then 'SMALLINT' "
1464 "else upper(data_type) end as data_type "
1465 "from information_schema.ext_access_paths full outer join "
1466 "information_schema.columns on information_schema.ext_access_paths.column_name = "
1467 "information_schema.columns.column_name and "
1468 "information_schema.ext_access_paths.table_name = "
1469 "information_schema.columns.table_name where "
1470 "information_schema.ext_access_paths.table_name = \'"_L1;
1471 sql.append(table)
1472 .append("\' and index_type = \'PRIMARY KEY\'"_L1);
1473 if (schema.length() == 0)
1474 sql.append(" and table_schema = CURRENT_USER"_L1);
1475 else
1476 sql.append(" and table_schema = \'"_L1).append(schema).append("\'"_L1);
1477
1478 if (!t.exec(sql))
1479 return QSqlIndex();
1480 int i = 0;
1481 while (t.next()) {
1482 QSqlField field(t.value(0).toString(),
1483 QMetaType(qDecodeMSQLType(qLookupMimDataType(t.value(1).toString()))),
1484 tablename);
1485 index.insert(i, field);
1486 index.setName(t.value(0).toString());
1487 i++;
1488 }
1489 return index;
1490}
1491
1493{
1494 Q_D(const QMimerSQLDriver);
1495 if (!isOpen())
1496 return QSqlRecord();
1497 QSqlRecord rec;
1499 QString qualifiedName = tablename;
1500 if (isIdentifierEscaped(qualifiedName, QSqlDriver::TableName))
1501 qualifiedName = stripDelimiters(qualifiedName, QSqlDriver::TableName);
1502 QString schema, table;
1503 d->splitTableQualifier(qualifiedName, &schema, &table);
1504
1505 QString sql =
1506 "select column_name, case when data_type = 'INTERVAL' then 'INTERVAL '|| interval_type "
1507 "when data_type = 'INTEGER' and numeric_precision > 10 then 'BIGINT' "
1508 "when data_type = 'INTEGER' and numeric_precision <= 10 AND numeric_precision > 5 "
1509 "then 'INTEGER' when data_type = 'INTEGER' and numeric_precision <= 5 then 'SMALLINT' "
1510 "else UPPER(data_type) end as data_type, case when is_nullable = 'YES' then false else "
1511 "true end as required, "
1512 "coalesce(numeric_precision, coalesce(datetime_precision,coalesce(interval_precision, "
1513 "-1))) as prec from information_schema.columns where table_name = \'"_L1;
1514 if (schema.length() == 0)
1515 sql.append(table).append("\' and table_schema = CURRENT_USER"_L1);
1516 else
1517 sql.append(table).append("\' and table_schema = \'"_L1).append(schema).append("\'"_L1);
1518 sql.append(" order by ordinal_position"_L1);
1519 if (!t.exec(sql))
1520 return QSqlRecord();
1521
1522 while (t.next()) {
1523 QSqlField field(t.value(0).toString(),
1524 QMetaType(qDecodeMSQLType(qLookupMimDataType(t.value(1).toString()))),
1525 tablename);
1526 field.setRequired(t.value(3).toBool());
1527 if (t.value(3).toInt() != -1)
1528 field.setPrecision(t.value(3).toInt());
1529 rec.append(field);
1530 }
1531
1532 return rec;
1533}
1534
1536{
1537 Q_D(const QMimerSQLDriver);
1538 return QVariant::fromValue(d->sessionhandle);
1539}
1540
1542{
1543 Q_UNUSED(type);
1544 QString res = identifier;
1545 if (!identifier.isEmpty() && !identifier.startsWith(u'"') && !identifier.endsWith(u'"')) {
1546 res.replace(u'"', "\"\""_L1);
1547 res = u'"' + res + u'"';
1548 res.replace(u'.', "\".\""_L1);
1549 }
1550 return res;
1551}
1552
1554{
1555 Q_D(const QMimerSQLDriver);
1556 const int32_t err = MimerBeginTransaction(d->sessionhandle, MIMER_TRANS_READWRITE);
1557 if (!MIMER_SUCCEEDED(err)) {
1559 QCoreApplication::translate("QMimerSQLDriver", "Could not start transaction"), err,
1561 return false;
1562 }
1563 return true;
1564}
1565
1567{
1568 Q_D(const QMimerSQLDriver);
1569 const int32_t err = MimerEndTransaction(d->sessionhandle, MIMER_COMMIT);
1570 if (!MIMER_SUCCEEDED(err)) {
1572 QCoreApplication::translate("QMimerSQLDriver", "Could not commit transaction"), err,
1574 return false;
1575 }
1576 return true;
1577}
1578
1580{
1581 Q_D(const QMimerSQLDriver);
1582 const int32_t err = MimerEndTransaction(d->sessionhandle, MIMER_ROLLBACK);
1583 if (!MIMER_SUCCEEDED(err)) {
1585 QCoreApplication::translate("QMimerSQLDriver", "Could not roll back transaction"),
1587 return false;
1588 }
1589 return true;
1590}
1591
1593 QString *table) const
1594{
1595 const QList<QStringView> l = QStringView(qualifiedName).split(u'.');
1596 int n = l.count();
1597 if (n > 2) {
1598 return; // can't possibly be a valid table qualifier
1599 } else if (n == 1) {
1600 *schema = QString();
1601 *table = l.at(0).toString();
1602 } else {
1603 *schema = l.at(0).toString();
1604 *table = l.at(1).toString();
1605 }
1606}
1607
1609
1610#include "moc_qsql_mimer.cpp"
\inmodule QtCore
Definition qbytearray.h:57
QByteArray trimmed() const &
Definition qbytearray.h:262
char * data()
\macro QT_NO_CAST_FROM_BYTEARRAY
Definition qbytearray.h:611
static QByteArray fromHex(const QByteArray &hexEncoded)
Returns a decoded copy of the hex encoded array hexEncoded.
void reserve(qsizetype size)
Attempts to allocate memory for at least size bytes.
Definition qbytearray.h:634
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
Definition qbytearray.h:124
void resize(qsizetype size)
Sets the size of the byte array to size bytes.
QByteArray & append(char c)
This is an overloaded member function, provided for convenience. It differs from the above function o...
static QByteArray fromRawData(const char *data, qsizetype size)
Constructs a QByteArray that uses the first size bytes of the data array.
Definition qbytearray.h:409
static QString translate(const char *context, const char *key, const char *disambiguation=nullptr, int n=-1)
\threadsafe
\inmodule QtCore\reentrant
Definition qdatetime.h:283
\inmodule QtCore
Definition qmetatype.h:341
Type
\macro Q_DECLARE_OPAQUE_POINTER(PointerType)
Definition qmetatype.h:345
MimerSession sessionhandle
void splitTableQualifier(const QString &qualifier, QString *schema, QString *table) const
~QMimerSQLDriver() override
QSqlIndex primaryIndex(const QString &tablename) const override
Returns the primary index for table tableName.
bool rollbackTransaction() override
This function is called to rollback a transaction.
bool commitTransaction() override
This function is called to commit a transaction.
bool beginTransaction() override
This function is called to begin a transaction.
QStringList tables(QSql::TableType type) const override
Returns a list of the names of the tables in the database.
void close() override
Derived classes must reimplement this pure virtual function in order to close the database connection...
QString escapeIdentifier(const QString &identifier, IdentifierType type) const override
Returns the identifier escaped according to the database rules.
QMimerSQLDriver(QObject *parent=nullptr)
bool open(const QString &db, const QString &user, const QString &password, const QString &host, int port, const QString &connOpts) override
Derived classes must reimplement this pure virtual function to open a database connection on database...
bool hasFeature(DriverFeature f) const override
Returns true if the driver supports feature feature; otherwise returns false.
QSqlResult * createResult() const override
Creates an empty SQL result on the database.
QSqlRecord record(const QString &tablename) const override
Returns a QSqlRecord populated with the names of the fields in table tableName.
QVariant handle() const override
Returns the low-level database handle wrapped in a QVariant or an invalid variant if there is no hand...
MimerStatement statementhandle
QVector< QVariant > batch_vector
static constexpr int maxTimestampStringSize
static constexpr int lobChunkMaxSizeSet
bool fetchNext() override
Positions the result to the next available record (row) in the result.
bool reset(const QString &query) override
Sets the result to use the SQL statement query for subsequent data retrieval.
static constexpr int maxDateStringSize
bool prepare(const QString &query) override
Prepares the given query for execution; the query will normally use placeholders so that it can be ex...
QVariant data(int i) override
Returns the data for field index in the current row as a QVariant.
QSqlRecord record() const override
Returns the current record if the query is active; otherwise returns an empty QSqlRecord.
int size() override
Returns the size of the SELECT result, or -1 if it cannot be determined or if the query is not a SELE...
QVariant handle() const override
Returns the low-level database handle for this result set wrapped in a QVariant or an invalid QVarian...
bool fetchLast() override
Positions the result to the last record (last row) in the result.
bool fetch(int i) override
Positions the result to an arbitrary (zero-based) row index.
bool execBatch(bool arrayBind=false) override
bool isNull(int index) override
Returns true if the field at position index in the current row is null; otherwise returns false.
bool fetchFirst() override
Positions the result to the first record (row 0) in the result.
int numRowsAffected() override
Returns the number of rows affected by the last query executed, or -1 if it cannot be determined or i...
static constexpr int maxTimeStringSize
static constexpr int genericError
static constexpr int lobChunkMaxSizeFetch
QMimerSQLResult(const QMimerSQLDriver *db)
virtual ~QMimerSQLResult() override
bool exec() override
Executes the query, returning true if successful; otherwise returns false.
static constexpr int maxStackStringSize
QVariant lastInsertId() const override
Returns the object ID of the most recent inserted row if the database supports it.
\inmodule QtCore
Definition qobject.h:103
The QSqlDriver class is an abstract base class for accessing specific SQL databases.
Definition qsqldriver.h:26
IdentifierType
This enum contains a list of SQL identifier types.
Definition qsqldriver.h:41
virtual QString stripDelimiters(const QString &identifier, IdentifierType type) const
Returns the identifier with the leading and trailing delimiters removed, identifier can either be a t...
DriverFeature
This enum contains a list of features a driver might support.
Definition qsqldriver.h:33
@ PositionalPlaceholders
Definition qsqldriver.h:34
@ LowPrecisionNumbers
Definition qsqldriver.h:35
@ EventNotifications
Definition qsqldriver.h:36
@ PreparedQueries
Definition qsqldriver.h:33
@ NamedPlaceholders
Definition qsqldriver.h:34
@ BatchOperations
Definition qsqldriver.h:35
@ MultipleResultSets
Definition qsqldriver.h:36
virtual void setLastError(const QSqlError &e)
This function is used to set the value of the last error, error, that occurred on the database.
virtual bool isOpen() const
Returns true if the database connection is open; otherwise returns false.
virtual void setOpenError(bool e)
This function sets the open error state of the database to error.
virtual bool isIdentifierEscaped(const QString &identifier, IdentifierType type) const
Returns whether identifier is escaped according to the database rules.
virtual void setOpen(bool o)
This function sets the open state of the database to open.
The QSqlError class provides SQL database error information.
Definition qsqlerror.h:17
ErrorType
This enum type describes the context in which the error occurred, e.g., a connection error,...
Definition qsqlerror.h:19
@ StatementError
Definition qsqlerror.h:22
@ TransactionError
Definition qsqlerror.h:23
@ ConnectionError
Definition qsqlerror.h:21
The QSqlField class manipulates the fields in SQL database tables and views.
Definition qsqlfield.h:19
void setValue(const QVariant &value)
Sets \l value to value.
void setName(const QString &name)
Sets \l name to name.
QMetaType metaType
Definition qsqlfield.h:28
void setMetaType(QMetaType type)
Sets \l metaType to type.
void setRequired(bool required)
Sets the required status of this field to \l Required if required is true; otherwise sets it to \l Op...
Definition qsqlfield.h:80
void setPrecision(int precision)
Sets \l precision to precision.
The QSqlIndex class provides functions to manipulate and describe database indexes.
Definition qsqlindex.h:18
The QSqlQuery class provides a means of executing and manipulating SQL statements.
Definition qsqlquery.h:24
The QSqlRecord class encapsulates a database record.
Definition qsqlrecord.h:20
void append(const QSqlField &field)
Append a copy of field field to the end of the record.
void insert(int pos, const QSqlField &field)
Inserts the field field at position pos in the record.
static bool isVariantNull(const QVariant &variant)
The QSqlResult class provides an abstract interface for accessing data from specific SQL databases.
Definition qsqlresult.h:22
bool isForwardOnly() const
Returns true if you can only scroll forward through the result set; otherwise returns false.
QSql::ParamType bindValueType(const QString &placeholder) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
int at() const
Returns the current (zero-based) row position of the result.
virtual bool prepare(const QString &query)
Prepares the given query for execution; the query will normally use placeholders so that it can be ex...
virtual bool exec()
Executes the query, returning true if successful; otherwise returns false.
bool isSelect() const
Returns true if the current result is from a SELECT statement; otherwise returns false.
virtual void setAt(int at)
This function is provided for derived classes to set the internal (zero-based) row position to index.
virtual void setSelect(bool s)
This function is provided for derived classes to indicate whether or not the current statement is a S...
virtual void setActive(bool a)
This function is provided for derived classes to set the internal active state to active.
QVariantList & boundValues(QT6_DECL_NEW_OVERLOAD)
QSql::NumericalPrecisionPolicy numericalPrecisionPolicy() const
virtual void setLastError(const QSqlError &e)
This function is provided for derived classes to set the last error to error.
const QSqlDriver * driver() const
Returns the driver associated with the result.
virtual void bindValue(int pos, const QVariant &val, QSql::ParamType type)
Binds the value val of parameter type paramType to position index in the current record (row).
bool isActive() const
Returns true if the result has records to be retrieved; otherwise returns false.
\inmodule QtCore
\inmodule QtCore
Definition qstringview.h:78
Q_CORE_EXPORT QList< QStringView > split(QStringView sep, Qt::SplitBehavior behavior=Qt::KeepEmptyParts, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Splits the view into substring views wherever sep occurs, and returns the list of those string views.
Definition qstring.cpp:8249
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
QString left(qsizetype n) const &
Definition qstring.h:363
bool startsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string starts with s; otherwise returns false.
Definition qstring.cpp:5455
QString & replace(qsizetype i, qsizetype len, QChar after)
Definition qstring.cpp:3824
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
bool endsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string ends with s; otherwise returns false.
Definition qstring.cpp:5506
static QString fromWCharArray(const wchar_t *string, qsizetype size=-1)
Definition qstring.h:1309
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:8084
QString & append(QChar c)
Definition qstring.cpp:3252
QByteArray toUtf8() const &
Definition qstring.h:634
qsizetype length() const noexcept
Returns the number of characters in this string.
Definition qstring.h:191
\inmodule QtCore \reentrant
Definition qdatetime.h:215
@ WithoutBraces
Definition quuid.h:54
static QUuid fromRfc4122(QByteArrayView) noexcept
Creates a QUuid object from the binary representation of the UUID, as specified by RFC 4122 section 4...
Definition quuid.cpp:595
\inmodule QtCore
Definition qvariant.h:65
static auto fromValue(T &&value) noexcept(std::is_nothrow_copy_constructible_v< T > &&Private::CanUseInternalSpace< T >) -> std::enable_if_t< std::conjunction_v< std::is_copy_constructible< T >, std::is_destructible< T > >, QVariant >
Definition qvariant.h:536
#define this
Definition dialogs.cpp:9
@ BeforeFirstRow
Definition qtsqlglobal.h:21
@ SystemTables
Definition qtsqlglobal.h:37
@ Views
Definition qtsqlglobal.h:38
@ Tables
Definition qtsqlglobal.h:36
@ AllTables
Definition qtsqlglobal.h:39
@ InOut
Definition qtsqlglobal.h:29
@ LowPrecisionInt32
Definition qtsqlglobal.h:44
@ LowPrecisionDouble
Definition qtsqlglobal.h:46
@ LowPrecisionInt64
Definition qtsqlglobal.h:45
@ HighPrecision
Definition qtsqlglobal.h:48
Combined button and popup list for selecting options.
typedef QByteArray(EGLAPIENTRYP PFNQGSGETDISPLAYSPROC)()
EGLOutputPortEXT port
#define Q_LOGGING_CATEGORY(name,...)
#define qCWarning(category,...)
#define Q_DECLARE_OPAQUE_POINTER(POINTER)
Definition qmetatype.h:1517
#define Q_DECLARE_METATYPE(TYPE)
Definition qmetatype.h:1525
GLenum GLsizei GLsizei GLint * values
[15]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint index
[2]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLfloat GLfloat f
GLenum type
GLfloat n
GLenum GLenum GLsizei void GLsizei void * column
GLdouble s
[6]
Definition qopenglext.h:235
GLboolean reset
GLenum query
GLuint res
GLdouble GLdouble t
Definition qopenglext.h:243
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLenum GLenum GLsizei void * row
GLfloat GLfloat p
[1]
GLuint GLenum option
GLenum GLenum GLsizei void * table
static QSqlError qMakeError(const QString &err, QSqlError::ErrorType type, const QDB2DriverPrivate *p)
Definition qsql_db2.cpp:203
static QList< QVariant > toList(char **buf, int count)
static QSqlError qMakeError(const QString &err, const int errCode, QSqlError::ErrorType type, const QMimerSQLDriverPrivate *p)
static MimerColumnTypes mimerMapColumnTypes(int32_t t)
static QString msgCouldNotGet(const char *type, int column)
static QMetaType::Type qDecodeMSQLType(int32_t t)
static QString msgCouldNotSet(const char *type, int column)
static int32_t qLookupMimDataType(QStringView s)
#define MIMER_DEFAULT_DATATYPE
#define Q_DECLARE_SQLDRIVER_PRIVATE(Class)
SSL_CTX int void * arg
#define Q_UNUSED(x)
ptrdiff_t qsizetype
Definition qtypes.h:165
unsigned int uint
Definition qtypes.h:34
long long qint64
Definition qtypes.h:60
double qreal
Definition qtypes.h:187
qint64 qlonglong
Definition qtypes.h:63
QObject::connect nullptr
QMimeDatabase db
[0]