Qt 6.x
The Qt SDK
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 <qsqlerror.h>
9#include <qsqlfield.h>
10#include <qsqlindex.h>
11#include <qsqlrecord.h>
12#include <qsqlquery.h>
13#include <qsocketnotifier.h>
14#include <qstringlist.h>
15#include <qlocale.h>
16#if defined(Q_OS_WIN32)
17# include <QtCore/qt_windows.h>
18#endif
19#include <QtSql/private/qsqlresult_p.h>
20#include <QtSql/private/qsqldriver_p.h>
21#include "qsql_mimer.h"
22
23#define MIMER_DEFAULT_DATATYPE 1000
24
25Q_DECLARE_OPAQUE_POINTER(MimerSession)
26Q_DECLARE_METATYPE(MimerSession)
27
28Q_DECLARE_OPAQUE_POINTER(MimerStatement)
29Q_DECLARE_METATYPE(MimerStatement)
30
32
33enum class MimerColumnTypes {
34 Binary,
35 Clob,
36 Blob,
37 String,
38 Int,
39 Long,
40 Float,
41 Double,
42 Boolean,
43 Uuid,
44 Date,
45 Time,
48};
49
50using namespace Qt::StringLiterals;
51
53
54class QMimerSQLResult final : public QSqlResult
55{
56 Q_DECLARE_PRIVATE(QMimerSQLResult)
57public:
59 virtual ~QMimerSQLResult() override;
60 QVariant handle() const override;
61 static constexpr int genericError = -1;
62 static constexpr int lobChunkMaxSizeSet = 1048500;
63 static constexpr int lobChunkMaxSizeFetch = 65536;
64 static constexpr int maxStackStringSize = 200;
65 static constexpr int maxTimeStringSize = 18;
66 static constexpr int maxDateStringSize = 10;
67 static constexpr int maxTimestampStringSize = 29;
68
69private:
70 void cleanup();
71 bool fetch(int i) override;
72 bool fetchFirst() override;
73 bool fetchLast() override;
74 bool fetchNext() override;
75 QVariant data(int i) override;
76 bool isNull(int index) override;
77 bool reset(const QString &query) override;
78 int size() override;
79 int numRowsAffected() override;
80 QSqlRecord record() const override;
81 bool prepare(const QString &query) override;
82 bool execBatch(bool arrayBind = false) override;
83 bool exec() override;
84 qint64 currentRow();
85 QVariant lastInsertId() const override;
86};
87
89{
90 Q_DECLARE_PUBLIC(QMimerSQLDriver)
91public:
93 MimerSession sessionhandle;
96 void splitTableQualifier(const QString &qualifier, QString *schema, QString *table) const;
97};
98
100{
101 Q_DECLARE_PUBLIC(QMimerSQLResult)
102public:
106 statementhandle(nullptr),
107 lobhandle(nullptr),
108 rowsAffected(0),
115 currentRow(QSql::BeforeFirstRow)
116 {
117 }
118 MimerStatement statementhandle;
119 MimerLob lobhandle;
128 qint64 currentRow; // Only used when forwardOnly()
130};
131
132static QSqlError qMakeError(const QString &err, const int errCode, QSqlError::ErrorType type,
134{
135 QString msg;
136 if (p) {
137 size_t str_len;
138 int e_code;
139 int rc;
140 str_len = (rc = MimerGetError(p->sessionhandle, &e_code, NULL, 0)) + 1;
141 if (!MIMER_SUCCEEDED(rc)) {
142 msg = QCoreApplication::translate("QMimerSQL", "No Mimer SQL error for code %1")
143 .arg(errCode);
144 } else {
145 QVarLengthArray<wchar_t> tmp_buff((qsizetype)str_len);
146 if (!MIMER_SUCCEEDED(
147 rc = MimerGetError(p->sessionhandle, &e_code, tmp_buff.data(), str_len)))
148 msg = QCoreApplication::translate("QMimerSQL", "No Mimer SQL error for code %1")
149 .arg(errCode);
150 else
151 msg = QString::fromWCharArray(tmp_buff.data());
152 }
153 } else {
154 msg = QCoreApplication::translate("QMimerSQL", "Generic Mimer SQL error");
155 }
156
157 return QSqlError("QMIMER: "_L1 + err, msg, type, QString::number(errCode));
158}
159
160static QString msgCouldNotGet(const char *type, int column)
161{
162 //: Data type, column
163 return QCoreApplication::translate("QMimerSQLResult",
164 "Could not get %1, column %2").arg(QLatin1StringView(type)).arg(column);
165}
166
167static QString msgCouldNotSet(const char *type, int column)
168{
169 //: Data type, parameter
170 return QCoreApplication::translate("QMimerSQLResult",
171 "Could not set %1, parameter %2").arg(QLatin1StringView(type)).arg(column);
172}
173
175{
176}
177
180{
181 Q_D(QMimerSQLDriver);
182 if (conn)
183 d->sessionhandle = *conn;
184}
185
187{
188 close();
189}
190
193{
194 Q_D(QMimerSQLResult);
195 d->preparedQuery = db->hasFeature(QSqlDriver::PreparedQueries);
196}
197
199{
200 cleanup();
201}
202
204{
205 switch (t) {
206 case MIMER_BINARY:
207 case MIMER_BINARY_VARYING:
209 case MIMER_BLOB:
210 case MIMER_NATIVE_BLOB:
212 case MIMER_CLOB:
213 case MIMER_NCLOB:
214 case MIMER_NATIVE_CLOB:
215 case MIMER_NATIVE_NCLOB:
217 case MIMER_DATE:
219 case MIMER_TIME:
221 case MIMER_TIMESTAMP:
223 case MIMER_INTERVAL_DAY:
224 case MIMER_DECIMAL:
225 case MIMER_INTERVAL_DAY_TO_HOUR:
226 case MIMER_INTERVAL_DAY_TO_MINUTE:
227 case MIMER_INTERVAL_DAY_TO_SECOND:
228 case MIMER_INTERVAL_HOUR:
229 case MIMER_INTERVAL_HOUR_TO_MINUTE:
230 case MIMER_INTERVAL_HOUR_TO_SECOND:
231 case MIMER_INTERVAL_MINUTE:
232 case MIMER_INTERVAL_MINUTE_TO_SECOND:
233 case MIMER_INTERVAL_MONTH:
234 case MIMER_INTERVAL_SECOND:
235 case MIMER_INTERVAL_YEAR:
236 case MIMER_INTERVAL_YEAR_TO_MONTH:
237 case MIMER_NCHAR:
238 case MIMER_CHARACTER:
239 case MIMER_CHARACTER_VARYING:
240 case MIMER_NCHAR_VARYING:
241 case MIMER_UTF8:
244 case MIMER_BOOLEAN:
246 case MIMER_T_BIGINT:
247 case MIMER_T_UNSIGNED_BIGINT:
248 case MIMER_NATIVE_BIGINT_NULLABLE:
249 case MIMER_NATIVE_BIGINT:
251 case MIMER_T_FLOAT:
252 case MIMER_FLOAT:
254 case MIMER_NATIVE_REAL_NULLABLE:
255 case MIMER_NATIVE_REAL:
256 case MIMER_T_REAL:
257 case MIMER_NATIVE_DOUBLE_NULLABLE:
258 case MIMER_NATIVE_DOUBLE:
259 case MIMER_T_DOUBLE:
261 case MIMER_NATIVE_INTEGER:
262 case MIMER_NATIVE_INTEGER_NULLABLE:
263 case MIMER_INTEGER:
264 case MIMER_NATIVE_SMALLINT_NULLABLE:
265 case MIMER_NATIVE_SMALLINT:
266 case MIMER_T_INTEGER:
267 case MIMER_T_SMALLINT:
269 case MIMER_UUID:
271 default:
272 qWarning() << "QMimerSQLDriver::mimerMapColumnTypes: Unknown data type: " << t;
273 }
275}
276
278{
279 switch (t) {
280 case MIMER_BINARY:
281 case MIMER_BINARY_VARYING:
282 case MIMER_BLOB:
283 case MIMER_NATIVE_BLOB:
284 return QMetaType::QByteArray;
285 case MIMER_CLOB:
286 case MIMER_NCLOB:
287 case MIMER_NATIVE_CLOB:
288 case MIMER_NATIVE_NCLOB:
289 case MIMER_INTERVAL_DAY:
290 case MIMER_DECIMAL:
291 case MIMER_INTERVAL_DAY_TO_HOUR:
292 case MIMER_INTERVAL_DAY_TO_MINUTE:
293 case MIMER_INTERVAL_DAY_TO_SECOND:
294 case MIMER_INTERVAL_HOUR:
295 case MIMER_INTERVAL_HOUR_TO_MINUTE:
296 case MIMER_INTERVAL_HOUR_TO_SECOND:
297 case MIMER_INTERVAL_MINUTE:
298 case MIMER_INTERVAL_MINUTE_TO_SECOND:
299 case MIMER_INTERVAL_MONTH:
300 case MIMER_INTERVAL_SECOND:
301 case MIMER_INTERVAL_YEAR:
302 case MIMER_INTERVAL_YEAR_TO_MONTH:
303 case MIMER_NCHAR:
304 case MIMER_CHARACTER:
305 case MIMER_CHARACTER_VARYING:
306 case MIMER_NCHAR_VARYING:
307 case MIMER_UTF8:
309 return QMetaType::QString;
310 case MIMER_BOOLEAN:
311 return QMetaType::Bool;
312 case MIMER_T_BIGINT:
313 case MIMER_T_UNSIGNED_BIGINT:
314 case MIMER_NATIVE_BIGINT_NULLABLE:
315 case MIMER_NATIVE_BIGINT:
316 return QMetaType::LongLong;
317 case MIMER_T_FLOAT:
318 case MIMER_FLOAT:
319 return QMetaType::Float;
320 case MIMER_NATIVE_REAL_NULLABLE:
321 case MIMER_NATIVE_REAL:
322 case MIMER_T_REAL:
323 case MIMER_NATIVE_DOUBLE_NULLABLE:
324 case MIMER_NATIVE_DOUBLE:
325 case MIMER_T_DOUBLE:
326 return QMetaType::Double;
327 case MIMER_NATIVE_INTEGER_NULLABLE:
328 case MIMER_T_INTEGER:
329 case MIMER_INTEGER:
330 return QMetaType::Int;
331 case MIMER_NATIVE_SMALLINT_NULLABLE:
332 case MIMER_T_SMALLINT:
333 return QMetaType::Int;
334 case MIMER_DATE:
335 return QMetaType::QDate;
336 case MIMER_TIME:
337 return QMetaType::QTime;
338 break;
339 case MIMER_TIMESTAMP:
340 return QMetaType::QDateTime;
341 case MIMER_UUID:
342 return QMetaType::QUuid;
343 default:
344 qWarning() << "QMimerSQLDriver::qDecodeMSQLType: Unknown data type: " << t;
346 }
347}
348
350{
351 if (s == u"BINARY")
352 return MIMER_BINARY;
353 if (s == u"BINARY VARYING")
354 return MIMER_BINARY_VARYING;
355 if (s == u"BINARY LARGE OBJECT")
356 return MIMER_BLOB;
357 if (s == u"CHARACTER LARGE OBJECT")
358 return MIMER_CLOB;
359 if (s == u"NATIONAL CHAR LARGE OBJECT")
360 return MIMER_NCLOB;
361 if (s == u"INTERVAL DAY")
362 return MIMER_INTERVAL_DAY;
363 if (s == u"DECIMAL")
364 return MIMER_DECIMAL;
365 if (s == u"INTERVAL DAY TO HOUR")
366 return MIMER_INTERVAL_DAY_TO_HOUR;
367 if (s == u"INTERVAL DAY TO MINUTE")
368 return MIMER_INTERVAL_DAY_TO_MINUTE;
369 if (s == u"INTERVAL DAY TO SECOND")
370 return MIMER_INTERVAL_DAY_TO_SECOND;
371 if (s == u"INTERVAL HOUR")
372 return MIMER_INTERVAL_HOUR;
373 if (s == u"INTERVAL HOUR TO MINUTE")
374 return MIMER_INTERVAL_HOUR_TO_MINUTE;
375 if (s == u"INTERVAL HOUR TO SECOND")
376 return MIMER_INTERVAL_HOUR_TO_SECOND;
377 if (s == u"INTERVAL MINUTE")
378 return MIMER_INTERVAL_MINUTE;
379 if (s == u"INTERVAL MINUTE TO SECOND")
380 return MIMER_INTERVAL_MINUTE_TO_SECOND;
381 if (s == u"INTERVAL MONTH")
382 return MIMER_INTERVAL_MONTH;
383 if (s == u"INTERVAL SECOND")
384 return MIMER_INTERVAL_SECOND;
385 if (s == u"INTERVAL YEAR")
386 return MIMER_INTERVAL_YEAR;
387 if (s == u"INTERVAL YEAR TO MONTH")
388 return MIMER_INTERVAL_YEAR_TO_MONTH;
389 if (s == u"NATIONAL CHARACTER")
390 return MIMER_NCHAR;
391 if (s == u"CHARACTER")
392 return MIMER_CHARACTER;
393 if (s == u"CHARACTER VARYING")
394 return MIMER_CHARACTER_VARYING;
395 if (s == u"NATIONAL CHARACTER VARYING")
396 return MIMER_NCHAR_VARYING;
397 if (s == u"UTF-8")
398 return MIMER_UTF8;
399 if (s == u"BOOLEAN")
400 return MIMER_BOOLEAN;
401 if (s == u"BIGINT")
402 return MIMER_T_BIGINT;
403 if (s == u"REAL")
404 return MIMER_T_REAL;
405 if (s == u"FLOAT")
406 return MIMER_T_FLOAT;
407 if (s == u"DOUBLE PRECISION")
408 return MIMER_T_DOUBLE;
409 if (s == u"INTEGER")
410 return MIMER_INTEGER;
411 if (s == u"SMALLINT")
412 return MIMER_T_SMALLINT;
413 if (s == u"DATE")
414 return MIMER_DATE;
415 if (s == u"TIME")
416 return MIMER_TIME;
417 if (s == u"TIMESTAMP")
418 return MIMER_TIMESTAMP;
419 if (s == u"BUILTIN.UUID")
420 return MIMER_UUID;
421 if (s == u"USER-DEFINED")
423 qWarning() << "QMimerSQLDriver::qLookupMimDataType: Unhandled data type: " << s;
425}
426
428{
429 Q_D(const QMimerSQLResult);
430 return QVariant::fromValue(d->statementhandle);
431}
432
433void QMimerSQLResult::cleanup()
434{
435 Q_D(QMimerSQLResult);
436 if (!driver() || !driver()->isOpen()) {
437 d->openCursor = false;
438 d->openStatement = false;
439 return;
440 }
441 if (d->openCursor) {
442 const int32_t err = MimerCloseCursor(d->statementhandle);
443 if (!MIMER_SUCCEEDED(err))
445 QCoreApplication::translate("QMimerSQLResult", "Could not close cursor"), err,
446 QSqlError::StatementError, d->drv_d_func()));
447 d->openCursor = false;
448 }
449 if (d->openStatement) {
450 const int32_t err = MimerEndStatement(&d->statementhandle);
451 if (!MIMER_SUCCEEDED(err))
453 QCoreApplication::translate("QMimerSQLResult", "Could not close statement"),
454 err, QSqlError::StatementError, d->drv_d_func()));
455 d->openStatement = false;
456 }
457 d->currentSize = -1;
458}
459
460qint64 QMimerSQLResult::currentRow()
461{
462 Q_D(const QMimerSQLResult);
463 return d->currentRow;
464}
465
467{
468 Q_D(const QMimerSQLResult);
469 int32_t err = 0;
470 if (!isActive() || !isSelect())
471 return false;
472 if (i == at())
473 return true;
474 if (i < 0)
475 return false;
476
477 if (isForwardOnly() && i < at())
478 return false;
479
480 if (isForwardOnly()) {
481 bool rc;
482 do {
483 rc = fetchNext();
484 } while (rc && currentRow() < i);
485 return rc;
486 } else {
487 err = MimerFetchScroll(d->statementhandle, MIMER_ABSOLUTE, i + 1);
488 if (err == MIMER_NO_DATA)
489 return false;
490 }
491 if (!MIMER_SUCCEEDED(err)) {
493 qMakeError(QCoreApplication::translate("QMimerSQLResult", "Fetch did not succeed"),
494 err, QSqlError::StatementError, d->drv_d_func()));
495 return false;
496 }
497 setAt(MimerCurrentRow(d->statementhandle) - 1);
498 return true;
499}
500
502{
503 Q_D(const QMimerSQLResult);
504 int32_t err = 0;
505 if (!isActive() || !isSelect())
506 return false;
507 if (isForwardOnly()) {
508 if (currentRow() < 0)
509 return fetchNext();
510 else if (currentRow() == 0)
511 setAt(0);
512 else
513 return false;
514 } else {
515 err = MimerFetchScroll(d->statementhandle, MIMER_FIRST, 0);
516 if (MIMER_SUCCEEDED(err) && err != MIMER_NO_DATA)
517 setAt(0);
518 }
519 if (!MIMER_SUCCEEDED(err)) {
521 QCoreApplication::translate("QMimerSQLResult", "Fetch first did not succeed"), err,
522 QSqlError::StatementError, d->drv_d_func()));
523 return false;
524 }
525 if (err == MIMER_NO_DATA)
526 return false;
527 return true;
528}
529
531{
532 Q_D(const QMimerSQLResult);
533 int32_t err = 0;
534 int row = 0;
535 if (!isActive() || !isSelect())
536 return false;
537 if (isForwardOnly()) {
538 bool rc;
539 do {
540 rc = fetchNext();
541 } while (rc);
542
543 return currentRow() >= 0;
544 } else {
545 err = MimerFetchScroll(d->statementhandle, static_cast<std::int32_t>(MIMER_LAST), 0);
546 if (err == MIMER_NO_DATA)
547 return false;
548 if (MIMER_SUCCEEDED(err)) {
549 row = MimerCurrentRow(d->statementhandle) - 1;
550 } else {
552 QCoreApplication::translate("QMimerSQLResult:", "Fetch last did not succeed"),
553 err, QSqlError::StatementError, d->drv_d_func()));
554 return false;
555 }
556 }
557
558 if (row < 0) {
560 return false;
561 } else {
562 setAt(row);
563 return true;
564 }
565}
566
568{
569 Q_D(QMimerSQLResult);
570 int32_t err = 0;
571 if (!isActive() || !isSelect())
572 return false;
573 if (isForwardOnly())
574 err = MimerFetch(d->statementhandle);
575 else
576 err = MimerFetchScroll(d->statementhandle, MIMER_NEXT, 0);
577 if (!MIMER_SUCCEEDED(err)) {
579 QCoreApplication::translate("QMimerSQLResult", "Could not fetch next row"), err,
580 QSqlError::StatementError, d->drv_d_func()));
581 if (isForwardOnly())
582 d->currentRow = QSql::BeforeFirstRow;
583 return false;
584 }
585 if (err == MIMER_NO_DATA)
586 return false;
587 if (isForwardOnly())
588 setAt(++d->currentRow);
589 else
590 setAt(MimerCurrentRow(d->statementhandle) - 1);
591 return true;
592}
593
595{
596 Q_D(QMimerSQLResult);
597 int32_t err;
598 int32_t mType;
599 if (d->callWithOut) {
600 if (i >= MimerParameterCount(d->statementhandle)) {
602 QCoreApplication::translate("QMimerSQLResult:", "Column %1 out of range")
603 .arg(i),
605 return QVariant();
606 }
607 mType = MimerParameterType(d->statementhandle, static_cast<std::int16_t>(i) + 1);
608 } else {
609 if (i >= MimerColumnCount(d->statementhandle)) {
611 QCoreApplication::translate("QMimerSQLResult:", "Column %1 out of range")
612 .arg(i),
614 return QVariant();
615 }
616 mType = MimerColumnType(d->statementhandle, static_cast<std::int16_t>(i) + 1);
617 }
618 const QMetaType::Type type = qDecodeMSQLType(mType);
619 const MimerColumnTypes mimDataType = mimerMapColumnTypes(mType);
620 err = MimerIsNull(d->statementhandle, static_cast<std::int16_t>(i) + 1);
621 if (err > 0) {
622 return QVariant(QMetaType(type), nullptr);
623 } else {
624 switch (mimDataType) {
626 wchar_t dateString_w[maxDateStringSize + 1];
627 err = MimerGetString(d->statementhandle, static_cast<std::int16_t>(i) + 1, dateString_w,
628 sizeof(dateString_w) / sizeof(dateString_w[0]));
629 if (!MIMER_SUCCEEDED(err)) {
631 err, QSqlError::StatementError, d->drv_d_func()));
632 return QVariant(QMetaType(type), nullptr);
633 }
634 return QDate::fromString(QString::fromWCharArray(dateString_w), "yyyy-MM-dd"_L1);
635 }
637 wchar_t timeString_w[maxTimeStringSize + 1];
638 err = MimerGetString(d->statementhandle, static_cast<std::int16_t>(i) + 1, timeString_w,
639 sizeof(timeString_w) / sizeof(timeString_w[0]));
640 if (!MIMER_SUCCEEDED(err)) {
642 err, QSqlError::StatementError, d->drv_d_func()));
643 return QVariant(QMetaType(type), nullptr);
644 }
645 QString timeString = QString::fromWCharArray(timeString_w);
646 QString timeFormatString = "HH:mm:ss"_L1;
647 if (timeString.size() > 8) {
648 timeFormatString.append(".zzz"_L1);
649 timeString = timeString.left(12);
650 }
651 return QTime::fromString(timeString, timeFormatString);
652 }
654 wchar_t dateTimeString_w[maxTimestampStringSize + 1];
655 err = MimerGetString(d->statementhandle, static_cast<std::int16_t>(i) + 1,
656 dateTimeString_w,
657 sizeof(dateTimeString_w) / sizeof(dateTimeString_w[0]));
658 if (!MIMER_SUCCEEDED(err)) {
660 qMakeError(msgCouldNotGet("date time", i),
661 err, QSqlError::StatementError, d->drv_d_func()));
662 return QVariant(QMetaType(type), nullptr);
663 }
664 QString dateTimeString = QString::fromWCharArray(dateTimeString_w);
665 QString dateTimeFormatString = "yyyy-MM-dd HH:mm:ss"_L1;
666 if (dateTimeString.size() > 19) {
667 dateTimeFormatString.append(".zzz"_L1);
668 dateTimeString = dateTimeString.left(23);
669 }
670 return QDateTime::fromString(dateTimeString, dateTimeFormatString);
671 }
673 int resInt;
674 err = MimerGetInt32(d->statementhandle, static_cast<std::int16_t>(i) + 1, &resInt);
675 if (!MIMER_SUCCEEDED(err)) {
677 err, QSqlError::StatementError, d->drv_d_func()));
678 return QVariant(QMetaType(type), nullptr);
679 }
680 return resInt;
681 }
683 int64_t resLongLong;
684 err = MimerGetInt64(d->statementhandle, static_cast<std::int16_t>(i) + 1, &resLongLong);
685 if (!MIMER_SUCCEEDED(err)) {
687 err, QSqlError::StatementError, d->drv_d_func()));
688 return QVariant(QMetaType(type), nullptr);
689 }
690 return QString::number(resLongLong).toLongLong();
691 }
693 err = MimerGetBoolean(d->statementhandle, static_cast<std::int16_t>(i) + 1);
694 if (!MIMER_SUCCEEDED(err)) {
696 qMakeError(msgCouldNotGet("boolean", i),
697 err, QSqlError::StatementError, d->drv_d_func()));
698 return QVariant(QMetaType(type), nullptr);
699 }
700 return err == 1;
701 }
703 float resFloat;
704 err = MimerGetFloat(d->statementhandle, static_cast<std::int16_t>(i) + 1, &resFloat);
705 if (!MIMER_SUCCEEDED(err)) {
707 err, QSqlError::StatementError, d->drv_d_func()));
708 return QVariant(QMetaType(type), nullptr);
709 }
710 return resFloat;
711 }
713 double resDouble;
714 err = MimerGetDouble(d->statementhandle, static_cast<std::int16_t>(i) + 1, &resDouble);
715 if (!MIMER_SUCCEEDED(err)) {
717 qMakeError(msgCouldNotGet("double", i),
718 err, QSqlError::StatementError, d->drv_d_func()));
719 return QVariant(QMetaType(type), nullptr);
720 }
721 switch (numericalPrecisionPolicy()) {
723 return static_cast<std::int32_t>(resDouble);
725 return static_cast<qint64>(resDouble);
727 return resDouble;
729 return QString::number(resDouble, 'g', 17);
730 }
731 return QVariant(QMetaType(type), nullptr);
732 }
734 QByteArray byteArray;
735 // Get size
736 err = MimerGetBinary(d->statementhandle, static_cast<std::int16_t>(i) + 1, NULL, 0);
737 if (MIMER_SUCCEEDED(err)) {
738 byteArray.resize(err);
739 err = MimerGetBinary(d->statementhandle, static_cast<std::int16_t>(i) + 1,
740 byteArray.data(), err);
741 }
742 if (!MIMER_SUCCEEDED(err)) {
744 qMakeError(msgCouldNotGet("binary", i),
745 err, QSqlError::StatementError, d->drv_d_func()));
746 return QVariant(QMetaType(type), nullptr);
747 }
748 return byteArray;
749 }
751 QByteArray byteArray;
752 size_t size;
753 err = MimerGetLob(d->statementhandle, static_cast<std::int16_t>(i) + 1, &size,
754 &d->lobhandle);
755 if (MIMER_SUCCEEDED(err)) {
756 constexpr size_t maxSize = lobChunkMaxSizeFetch;
758 byteArray.reserve(size);
759 size_t left_to_return = size;
760 while (left_to_return > 0) {
761 const size_t bytesToReceive =
762 left_to_return <= maxSize ? left_to_return : maxSize;
763 err = MimerGetBlobData(&d->lobhandle, blobchar.data(), bytesToReceive);
764 byteArray.append(QByteArray::fromRawData(blobchar.data(), bytesToReceive));
765 left_to_return -= bytesToReceive;
766 if (!MIMER_SUCCEEDED(err)) {
768 err, QSqlError::StatementError, d->drv_d_func()));
769 return QVariant(QMetaType(type), nullptr);
770 }
771 }
772 } else {
774 err, QSqlError::StatementError, d->drv_d_func()));
775 return QVariant(QMetaType(type), nullptr);
776 }
777 return byteArray;
778 }
780 wchar_t resString_w[maxStackStringSize + 1];
781 // Get size
782 err = MimerGetString(d->statementhandle, static_cast<std::int16_t>(i) + 1, resString_w,
783 0);
784 if (MIMER_SUCCEEDED(err)) {
785 int size = err;
786 if (err <= maxStackStringSize) { // For smaller strings, use a small buffer for
787 // efficiency
788 err = MimerGetString(d->statementhandle, static_cast<std::int16_t>(i) + 1,
789 resString_w, maxStackStringSize + 1);
790 if (MIMER_SUCCEEDED(err))
791 return QString::fromWCharArray(resString_w);
792 } else { // For larger strings, dynamically allocate memory
793 QVarLengthArray<wchar_t> largeResString_w(size + 1);
794 err = MimerGetString(d->statementhandle, static_cast<std::int16_t>(i) + 1,
795 largeResString_w.data(), size + 1);
796 if (MIMER_SUCCEEDED(err))
797 return QString::fromWCharArray(largeResString_w.data());
798 }
799 }
801 err, QSqlError::StatementError, d->drv_d_func()));
802 return QVariant(QMetaType(type), nullptr);
803 }
805 size_t size;
806 err = MimerGetLob(d->statementhandle, static_cast<std::int16_t>(i) + 1, &size,
807 &d->lobhandle);
808 if (MIMER_SUCCEEDED(err)) {
809 constexpr size_t maxSize = lobChunkMaxSizeFetch;
811
812 size_t left_to_return = size;
813 QString returnString;
814 while (left_to_return > 0) {
815 const size_t bytesToReceive =
816 left_to_return <= maxSize ? left_to_return : maxSize;
817 err = MimerGetNclobData(&d->lobhandle, clobstring_w.data(), bytesToReceive + 1);
818 returnString.append(QString::fromWCharArray(clobstring_w.data()));
819 left_to_return -= bytesToReceive;
820 if (!MIMER_SUCCEEDED(err)) {
822 err, QSqlError::StatementError, d->drv_d_func()));
823 return QVariant(QMetaType(type), nullptr);
824 }
825 }
826 return returnString;
827 }
829 err, QSqlError::StatementError, d->drv_d_func()));
830 return QVariant(QMetaType(type), nullptr);
831 }
833 unsigned char uuidChar[16];
834 err = MimerGetUUID(d->statementhandle, static_cast<std::int16_t>(i) + 1, uuidChar);
835 if (!MIMER_SUCCEEDED(err)) {
837 err, QSqlError::StatementError, d->drv_d_func()));
838 return QVariant(QMetaType(type), nullptr);
839 }
840 const QByteArray uuidByteArray = QByteArray(reinterpret_cast<char *>(uuidChar), 16);
841 return QUuid::fromRfc4122(uuidByteArray);
842 }
844 default:
846 QCoreApplication::translate("QMimerSQLResult", "Unknown data type %1").arg(i),
848 }
849 return QVariant(QMetaType(type), nullptr);
850 }
851}
852
854{
855 Q_D(const QMimerSQLResult);
856 const int32_t rc = MimerIsNull(d->statementhandle, static_cast<std::int16_t>(index) + 1);
857 if (!MIMER_SUCCEEDED(rc)) {
859 QCoreApplication::translate("QMimerSQLResult", "Could not check null, column %1")
860 .arg(index),
861 rc, QSqlError::StatementError, d->drv_d_func()));
862 return false;
863 }
864 return rc != 0;
865}
866
868{
869 if (!prepare(query))
870 return false;
871 return exec();
872}
873
875{
876 Q_D(QMimerSQLResult);
877 if (!isActive() || !isSelect() || isForwardOnly())
878 return -1;
879
880 if (d->currentSize != -1)
881 return d->currentSize;
882
883 const int currentRow = MimerCurrentRow(d->statementhandle);
884 MimerFetchScroll(d->statementhandle, static_cast<std::int32_t>(MIMER_LAST), 0);
885 int size = MimerCurrentRow(d->statementhandle);
886 if (!MIMER_SUCCEEDED(size))
887 size = -1;
888 MimerFetchScroll(d->statementhandle, MIMER_ABSOLUTE, currentRow);
889 d->currentSize = size;
890 return size;
891}
892
894{
895 Q_D(const QMimerSQLResult);
896 return d->rowsAffected;
897}
898
900{
901 Q_D(const QMimerSQLResult);
902 QSqlRecord rec;
903 if (!isActive() || !isSelect() || !driver())
904 return rec;
905 QSqlField field;
906 const int colSize = MimerColumnCount(d->statementhandle);
907 for (int i = 0; i < colSize; i++) {
908 wchar_t colName_w[100];
909 MimerColumnName(d->statementhandle, static_cast<std::int16_t>(i) + 1, colName_w,
910 sizeof(colName_w) / sizeof(colName_w[0]));
911 field.setName(QString::fromWCharArray(colName_w));
912 const int32_t mType = MimerColumnType(d->statementhandle, static_cast<std::int16_t>(i) + 1);
913 const QMetaType::Type type = qDecodeMSQLType(mType);
914 field.setSqlType(mType);
915 field.setMetaType(QMetaType(type));
916 field.setValue(QVariant(field.metaType()));
917 // field.setPrecision(); Should be implemented once the Mimer API can give this
918 // information.
919 // field.setLength(); Should be implemented once the Mimer API can give
920 // this information.
921 rec.insert(i, field);
922 }
923 return rec;
924}
925
927{
928 Q_D(QMimerSQLResult);
929 int32_t err;
930 if (!driver())
931 return false;
932 if (!d->preparedQuery)
934 if (query.isEmpty())
935 return false;
936 cleanup();
937 const int option = isForwardOnly() ? MIMER_FORWARD_ONLY : MIMER_SCROLLABLE;
938 err = MimerBeginStatement8(d->drv_d_func()->sessionhandle, query.toUtf8().constData(), option,
939 &d->statementhandle);
940 if (err == MIMER_STATEMENT_CANNOT_BE_PREPARED) {
941 err = MimerExecuteStatement8(d->drv_d_func()->sessionhandle, query.toUtf8().constData());
942 if (MIMER_SUCCEEDED(err)) {
943 d->executedStatement = true;
944 d->openCursor = false;
945 d->openStatement = false;
946 return true;
947 }
948 }
949 if (!MIMER_SUCCEEDED(err)) {
951 "Could not prepare/execute statement"),
952 err, QSqlError::StatementError, d->drv_d_func()));
953 return false;
954 }
955 d->openStatement = true;
956 return true;
957}
958
960{
961 Q_D(QMimerSQLResult);
962 int32_t err;
963 if (!driver())
964 return false;
965 if (!d->preparedQuery)
966 return QSqlResult::exec();
967 if (d->executedStatement) {
968 d->executedStatement = false;
969 return true;
970 }
971 if (d->openCursor) {
973 err = MimerCloseCursor(d->statementhandle);
974 d->openCursor = false;
975 d->currentSize = -1;
976 }
978 if (d->execBatch)
979 values = d->batch_vector;
980 int mimParamCount = MimerParameterCount(d->statementhandle);
981 if (!MIMER_SUCCEEDED(mimParamCount))
982 mimParamCount = 0;
983 if (mimParamCount != values.size()) {
985 QCoreApplication::translate("QMimerSQLResult", "Wrong number of parameters"),
987 return false;
988 }
989 for (int i = 0; i < mimParamCount; i++) {
990 if (bindValueType(i) == QSql::Out) {
991 d->callWithOut = true;
992 continue;
993 }
994 const QVariant &val = values.at(i);
995 if (QSqlResultPrivate::isVariantNull(val) || val.isNull() || val.toString().isNull()) {
996 err = MimerSetNull(d->statementhandle, i + 1);
997 if (!MIMER_SUCCEEDED(err)) {
999 qMakeError(msgCouldNotSet("null", i),
1000 err, QSqlError::StatementError, d->drv_d_func()));
1001 return false;
1002 }
1003 continue;
1004 }
1005
1006 const int mimParamType = MimerParameterType(d->statementhandle, i + 1);
1007 const MimerColumnTypes mimDataType = mimerMapColumnTypes(mimParamType);
1008 switch (mimDataType) {
1009 case MimerColumnTypes::Int: {
1010 bool convertOk;
1011 err = MimerSetInt32(d->statementhandle, i + 1, val.toInt(&convertOk));
1012 if (!convertOk || !MIMER_SUCCEEDED(err)) {
1014 qMakeError(msgCouldNotSet("int32", i),
1015 convertOk ? err : genericError, QSqlError::StatementError,
1016 convertOk ? d->drv_d_func() : nullptr));
1017 return false;
1018 }
1019 break;
1020 }
1022 bool convertOk;
1023 err = MimerSetInt64(d->statementhandle, i + 1, val.toLongLong(&convertOk));
1024 if (!convertOk || !MIMER_SUCCEEDED(err)) {
1026 qMakeError(msgCouldNotSet("int64", i),
1027 convertOk ? err : genericError, QSqlError::StatementError,
1028 convertOk ? d->drv_d_func() : nullptr));
1029 return false;
1030 }
1031 break;
1032 }
1034 bool convertOk;
1035 err = MimerSetFloat(d->statementhandle, i + 1, val.toFloat(&convertOk));
1036 if (!convertOk || !MIMER_SUCCEEDED(err)) {
1038 qMakeError(msgCouldNotSet("float", i),
1039 convertOk ? err : genericError, QSqlError::StatementError,
1040 convertOk ? d->drv_d_func() : nullptr));
1041 return false;
1042 }
1043 break;
1044 }
1046 bool convertOk;
1047 err = MimerSetDouble(d->statementhandle, i + 1, val.toDouble(&convertOk));
1048 if (!convertOk || !MIMER_SUCCEEDED(err)) {
1050 qMakeError(msgCouldNotSet("double", i),
1051 convertOk ? err : genericError, QSqlError::StatementError,
1052 convertOk ? d->drv_d_func() : nullptr));
1053 return false;
1054 }
1055 break;
1056 }
1058 const QByteArray binArr = val.toByteArray();
1059 size_t size = static_cast<std::size_t>(binArr.size());
1060 err = MimerSetBinary(d->statementhandle, i + 1, binArr.data(), size);
1061 if (!MIMER_SUCCEEDED(err)) {
1063 qMakeError(msgCouldNotSet("binary", i),
1064 err, QSqlError::StatementError, d->drv_d_func()));
1065 return false;
1066 }
1067 break;
1068 }
1070 err = MimerSetBoolean(d->statementhandle, i + 1, val.toBool() == true ? 1 : 0);
1071 if (!MIMER_SUCCEEDED(err)) {
1073 qMakeError(msgCouldNotSet("boolean", i),
1074 err, QSqlError::StatementError, d->drv_d_func()));
1075 return false;
1076 }
1077 break;
1078 }
1080 const QByteArray uuidArray =
1081 QByteArray::fromHex(val.toUuid().toString(QUuid::WithoutBraces).toLatin1());
1082 const unsigned char *uuid =
1083 reinterpret_cast<const unsigned char *>(uuidArray.constData());
1084 err = MimerSetUUID(d->statementhandle, i + 1, uuid);
1085 if (!MIMER_SUCCEEDED(err)) {
1087 qMakeError(msgCouldNotSet("UUID", i),
1088 err, QSqlError::StatementError, d->drv_d_func()));
1089 return false;
1090 }
1091 break;
1092 }
1094 QByteArray string_b = val.toString().trimmed().toUtf8();
1095 const char *string_u = string_b.constData();
1096 err = MimerSetString8(d->statementhandle, i + 1, string_u);
1097 if (!MIMER_SUCCEEDED(err)) {
1099 qMakeError(msgCouldNotSet("string", i),
1100 err, QSqlError::StatementError, d->drv_d_func()));
1101 return false;
1102 }
1103 break;
1104 }
1106 err = MimerSetString8(d->statementhandle, i + 1, val.toString().toUtf8().constData());
1107 if (!MIMER_SUCCEEDED(err)) {
1109 qMakeError(msgCouldNotSet("date", i),
1110 err, QSqlError::StatementError, d->drv_d_func()));
1111 return false;
1112 }
1113 break;
1114 }
1116 QString timeFormatString = "hh:mm:ss"_L1;
1117 const QTime timeVal = val.toTime();
1118 if (timeVal.msec() > 0)
1119 timeFormatString.append(".zzz"_L1);
1120 err = MimerSetString8(d->statementhandle, i + 1,
1121 timeVal.toString(timeFormatString).toUtf8().constData());
1122 if (!MIMER_SUCCEEDED(err)) {
1124 qMakeError(msgCouldNotSet("time", i),
1125 err, QSqlError::StatementError, d->drv_d_func()));
1126 return false;
1127 }
1128 break;
1129 }
1131 QString dateTimeFormatString = "yyyy-MM-dd hh:mm:ss"_L1;
1132 const QDateTime dateTimeVal = val.toDateTime();
1133 if (dateTimeVal.time().msec() > 0)
1134 dateTimeFormatString.append(".zzz"_L1);
1135 err = MimerSetString8(
1136 d->statementhandle, i + 1,
1137 val.toDateTime().toString(dateTimeFormatString).toUtf8().constData());
1138 if (!MIMER_SUCCEEDED(err)) {
1140 err, QSqlError::StatementError, d->drv_d_func()));
1141 return false;
1142 }
1143 break;
1144 }
1146 QByteArray blobArr = val.toByteArray();
1147 const char *blobData = blobArr.constData();
1148 qsizetype size = blobArr.size();
1149 err = MimerSetLob(d->statementhandle, i + 1, size, &d->lobhandle);
1150 if (MIMER_SUCCEEDED(err)) {
1151 qsizetype maxSize = lobChunkMaxSizeSet;
1152 if (size > maxSize) {
1153 qsizetype left_to_send = size;
1154 for (qsizetype k = 0; left_to_send > 0; k++) {
1155 if (left_to_send <= maxSize) {
1156 err = MimerSetBlobData(&d->lobhandle, &blobData[k * maxSize],
1157 left_to_send);
1158 left_to_send = 0;
1159 } else {
1160 err = MimerSetBlobData(&d->lobhandle, &blobData[k * maxSize], maxSize);
1161 left_to_send = left_to_send - maxSize;
1162 }
1163 }
1164 if (!MIMER_SUCCEEDED(err)) {
1166 qMakeError(msgCouldNotSet("BLOB byte array", i),
1167 err, QSqlError::StatementError, d->drv_d_func()));
1168 return false;
1169 }
1170 } else {
1171 err = MimerSetBlobData(&d->lobhandle, blobArr, size);
1172 }
1173 }
1174 if (!MIMER_SUCCEEDED(err)) {
1175 setLastError(qMakeError(msgCouldNotSet("BLOB byte array", i),
1176 err, QSqlError::StatementError, d->drv_d_func()));
1177 return false;
1178 }
1179 break;
1180 }
1182 QByteArray string_b = val.toString().trimmed().toUtf8();
1183 const char *string_u = string_b.constData();
1184 size_t size_c = 1;
1185 size_t size = 0;
1186 while (string_u[size++])
1187 if ((string_u[size] & 0xc0) != 0x80)
1188 size_c++;
1189 err = MimerSetLob(d->statementhandle, i + 1, size_c, &d->lobhandle);
1190 if (MIMER_SUCCEEDED(err)) {
1191 constexpr size_t maxSize = lobChunkMaxSizeSet;
1192 if (size > maxSize) {
1193 size_t left_to_send = size;
1194 size_t pos = 0;
1195 uint step_back = 0;
1196 while (left_to_send > 0 && step_back < maxSize) {
1197 step_back = 0;
1198 if (left_to_send <= maxSize) {
1199 err = MimerSetNclobData8(&d->lobhandle, &string_u[pos], left_to_send);
1200 left_to_send = 0;
1201 } else {
1202 // Check that we don't split a multi-byte utf-8 characters
1203 while (pos + maxSize - step_back > 0
1204 && (string_u[pos + maxSize - step_back] & 0xc0) == 0x80)
1205 step_back++;
1206 err = MimerSetNclobData8(&d->lobhandle, &string_u[pos],
1207 maxSize - step_back);
1208 left_to_send = left_to_send - maxSize + step_back;
1209 pos += maxSize - step_back;
1210 }
1211 if (!MIMER_SUCCEEDED(err)) {
1213 err, QSqlError::StatementError, d->drv_d_func()));
1214 return false;
1215 }
1216 }
1217 } else {
1218 err = MimerSetNclobData8(&d->lobhandle, string_u, size);
1219 }
1220 }
1221 if (!MIMER_SUCCEEDED(err)) {
1223 qMakeError(msgCouldNotSet("CLOB", i),
1224 err, QSqlError::StatementError, d->drv_d_func()));
1225 return false;
1226 }
1227 break;
1228 }
1230 default:
1232 QCoreApplication::translate("QMimerSQLResult", "Unknown datatype, parameter %1")
1233 .arg(i),
1235 return false;
1236 }
1237 }
1238 if (d->execBatch)
1239 return true;
1240 err = MimerExecute(d->statementhandle);
1241 if (MIMER_SUCCEEDED(err)) {
1242 d->rowsAffected = err;
1243 int k = 0;
1244 for (qsizetype i = 0; i < values.size(); i++) {
1246 bindValue(i, data(k), QSql::In);
1247 k++;
1248 }
1249 }
1250 d->callWithOut = false;
1251 }
1252 setSelect(false);
1253 if (MIMER_SEQUENCE_ERROR == err) {
1254 err = MimerOpenCursor(d->statementhandle);
1255 d->rowsAffected = err;
1256 d->openCursor = true;
1257 d->currentRow = QSql::BeforeFirstRow;
1258 setSelect(true);
1259 }
1260 if (!MIMER_SUCCEEDED(err)) {
1262 qMakeError(QCoreApplication::translate("QMimerSQLResult",
1263 "Could not execute statement/open cursor"),
1264 err, QSqlError::StatementError, d->drv_d_func()));
1265 return false;
1266 }
1267 setActive(true);
1268 return true;
1269}
1270
1271bool QMimerSQLResult::execBatch(bool arrayBind)
1272{
1273 Q_D(QMimerSQLResult);
1274 Q_UNUSED(arrayBind);
1275 int32_t err;
1277
1278 // Check that we only have input parameters. Currently
1279 // we can only handle batch operations without output parameters.
1280 for (qsizetype i = 0; i < values.first().toList().size(); i++)
1283 "QMimerSQLResult",
1284 "Only input parameter can be used in batch operations"),
1286 d->execBatch = false;
1287 return false;
1288 }
1289 d->execBatch = true;
1290 for (qsizetype i = 0; i < values.first().toList().size(); i++) {
1291 for (qsizetype j = 0; j < values.size(); j++)
1292 d->batch_vector.append(values.at(j).toList().at(i));
1293 exec();
1294 if (i != (values.at(0).toList().size() - 1)) {
1295 err = MimerAddBatch(d->statementhandle);
1296 if (!MIMER_SUCCEEDED(err)) {
1298 QCoreApplication::translate("QMimerSQLResult", "Could not add batch %1")
1299 .arg(i),
1300 err, QSqlError::StatementError, d->drv_d_func()));
1301 d->execBatch = false;
1302 return false;
1303 }
1304 }
1305 d->batch_vector.clear();
1306 }
1307 d->execBatch = false;
1308 err = MimerExecute(d->statementhandle);
1309 if (!MIMER_SUCCEEDED(err)) {
1311 QCoreApplication::translate("QMimerSQLResult", "Could not execute batch"), err,
1312 QSqlError::StatementError, d->drv_d_func()));
1313 return false;
1314 }
1315 return true;
1316}
1317
1319{
1320 Q_D(const QMimerSQLResult);
1321 int64_t lastSequence;
1322 const int32_t err = MimerGetSequenceInt64(d->statementhandle, &lastSequence);
1323 if (!MIMER_SUCCEEDED(err))
1324 return QVariant(QMetaType(QMetaType::LongLong), nullptr);
1325 return QVariant(qint64(lastSequence));
1326}
1327
1329{
1330 switch (f) {
1331 case NamedPlaceholders: // Is true in reality but Qt parses Sql statement...
1332 case EventNotifications:
1334 case MultipleResultSets:
1335 case SimpleLocking:
1336 case CancelQuery:
1337 return false;
1338 case FinishQuery:
1339 case LastInsertId:
1340 case Transactions:
1341 case QuerySize:
1342 case BLOB:
1343 case Unicode:
1344 case PreparedQueries:
1346 case BatchOperations:
1347 return true;
1348 }
1349 return true;
1350}
1351
1352bool QMimerSQLDriver::open(const QString &db, const QString &user, const QString &password,
1353 const QString &host, int port, const QString &connOpts)
1354{
1355 Q_D(QMimerSQLDriver);
1356 Q_UNUSED(host);
1357 Q_UNUSED(port);
1358 Q_UNUSED(connOpts);
1359 if (isOpen())
1360 close();
1361 const int32_t err = MimerBeginSession8(db.toUtf8().constData(), user.toUtf8().constData(),
1362 password.toUtf8().constData(), &d->sessionhandle);
1363 if (!MIMER_SUCCEEDED(err)) {
1365 QCoreApplication::translate("QMimerSQLDriver", "Could not connect to database")
1366 + " "_L1 + db,
1367 err, QSqlError::ConnectionError, nullptr));
1368 setOpenError(true);
1369 return false;
1370 }
1371 d->dbUser = user;
1372 d->dbName = db;
1373 setOpen(true);
1374 setOpenError(false);
1375 return true;
1376}
1377
1379{
1380 Q_D(QMimerSQLDriver);
1381 if (isOpen()) {
1382 const int end_err = MimerEndSession(&d->sessionhandle);
1383 if (MIMER_SUCCEEDED(end_err)) {
1384 setOpen(false);
1385 setOpenError(false);
1386 }
1387 }
1388}
1389
1391{
1392 return new QMimerSQLResult(this);
1393}
1394
1396{
1397 QStringList tl;
1398 if (!isOpen())
1399 return tl;
1401 QString sql;
1402 switch (type) {
1403 case QSql::Tables: {
1404 sql = "select table_name from information_schema.tables where "
1405 "table_type=\'BASE TABLE\' AND table_schema = CURRENT_USER"_L1;
1406 break;
1407 }
1408 case QSql::SystemTables: {
1409 sql = "select table_name from information_schema.tables where "
1410 "table_type=\'BASE TABLE\' AND table_schema = \'SYSTEM\'"_L1;
1411 break;
1412 }
1413 case QSql::Views: {
1414 sql = "select table_name from information_schema.tables where "
1415 "table_type=\'VIEW\' AND table_schema = CURRENT_USER"_L1;
1416 break;
1417 }
1418 case QSql::AllTables: {
1419 sql = "select table_name from information_schema.tables where "
1420 "(table_type=\'VIEW\' or table_type=\'BASE TABLE\')"
1421 " AND (table_schema = CURRENT_USER OR table_schema =\'SYSTEM\')"_L1;
1422 break;
1423 }
1424 default:
1425 break;
1426 }
1427 if (sql.length() > 0) {
1428 t.exec(sql);
1429 while (t.next())
1430 tl.append(t.value(0).toString());
1431 }
1432 return tl;
1433}
1434
1436{
1437 Q_D(const QMimerSQLDriver);
1438 if (!isOpen())
1439 return QSqlIndex();
1440 QString table = tablename;
1443 QSqlIndex index(tablename);
1445 QString schema;
1446 QString qualifiedName = table;
1447 d->splitTableQualifier(qualifiedName, &schema, &table);
1448 QString sql =
1449 "select information_schema.ext_access_paths.column_name,"
1450 "case when data_type = 'INTERVAL' then 'INTERVAL '|| interval_type "
1451 "when data_type = 'INTEGER' and numeric_precision > 10 then 'BIGINT' "
1452 "when data_type = 'INTEGER' and numeric_precision <= 10 AND NUMERIC_PRECISION > 5 "
1453 "then 'INTEGER' when data_type = 'INTEGER' and numeric_precision <= 5 then 'SMALLINT' "
1454 "else upper(data_type) end as data_type "
1455 "from information_schema.ext_access_paths full outer join "
1456 "information_schema.columns on information_schema.ext_access_paths.column_name = "
1457 "information_schema.columns.column_name and "
1458 "information_schema.ext_access_paths.table_name = "
1459 "information_schema.columns.table_name where "
1460 "information_schema.ext_access_paths.table_name = \'"_L1;
1461 sql.append(table)
1462 .append("\' and index_type = \'PRIMARY KEY\'"_L1);
1463 if (schema.length() == 0)
1464 sql.append(" and table_schema = CURRENT_USER"_L1);
1465 else
1466 sql.append(" and table_schema = \'"_L1).append(schema).append("\'"_L1);
1467
1468 if (!t.exec(sql))
1469 return QSqlIndex();
1470 int i = 0;
1471 while (t.next()) {
1472 QSqlField field(t.value(0).toString(),
1473 QMetaType(qDecodeMSQLType(qLookupMimDataType(t.value(1).toString()))),
1474 tablename);
1475 index.insert(i, field);
1476 index.setName(t.value(0).toString());
1477 i++;
1478 }
1479 return index;
1480}
1481
1483{
1484 Q_D(const QMimerSQLDriver);
1485 if (!isOpen())
1486 return QSqlRecord();
1487 QSqlRecord rec;
1489 QString qualifiedName = tablename;
1490 if (isIdentifierEscaped(qualifiedName, QSqlDriver::TableName))
1491 qualifiedName = stripDelimiters(qualifiedName, QSqlDriver::TableName);
1492 QString schema, table;
1493 d->splitTableQualifier(qualifiedName, &schema, &table);
1494
1495 QString sql =
1496 "select column_name, case when data_type = 'INTERVAL' then 'INTERVAL '|| interval_type "
1497 "when data_type = 'INTEGER' and numeric_precision > 10 then 'BIGINT' "
1498 "when data_type = 'INTEGER' and numeric_precision <= 10 AND numeric_precision > 5 "
1499 "then 'INTEGER' when data_type = 'INTEGER' and numeric_precision <= 5 then 'SMALLINT' "
1500 "else UPPER(data_type) end as data_type, case when is_nullable = 'YES' then false else "
1501 "true end as required, "
1502 "coalesce(numeric_precision, coalesce(datetime_precision,coalesce(interval_precision, "
1503 "-1))) as prec from information_schema.columns where table_name = \'"_L1;
1504 if (schema.length() == 0)
1505 sql.append(table).append("\' and table_schema = CURRENT_USER"_L1);
1506 else
1507 sql.append(table).append("\' and table_schema = \'"_L1).append(schema).append("\'"_L1);
1508 sql.append(" order by ordinal_position"_L1);
1509 if (!t.exec(sql))
1510 return QSqlRecord();
1511
1512 while (t.next()) {
1513 QSqlField field(t.value(0).toString(),
1514 QMetaType(qDecodeMSQLType(qLookupMimDataType(t.value(1).toString()))),
1515 tablename);
1516 field.setRequired(t.value(3).toBool());
1517 if (t.value(3).toInt() != -1)
1518 field.setPrecision(t.value(3).toInt());
1519 rec.append(field);
1520 }
1521
1522 return rec;
1523}
1524
1526{
1527 Q_D(const QMimerSQLDriver);
1528 return QVariant::fromValue(d->sessionhandle);
1529}
1530
1532{
1533 Q_UNUSED(type);
1534 QString res = identifier;
1535 if (!identifier.isEmpty() && !identifier.startsWith(u'"') && !identifier.endsWith(u'"')) {
1536 res.replace(u'"', "\"\""_L1);
1537 res = u'"' + res + u'"';
1538 res.replace(u'.', "\".\""_L1);
1539 }
1540 return res;
1541}
1542
1544{
1545 Q_D(const QMimerSQLDriver);
1546 const int32_t err = MimerBeginTransaction(d->sessionhandle, MIMER_TRANS_READWRITE);
1547 if (!MIMER_SUCCEEDED(err)) {
1549 QCoreApplication::translate("QMimerSQLDriver", "Could not start transaction"), err,
1551 return false;
1552 }
1553 return true;
1554}
1555
1557{
1558 Q_D(const QMimerSQLDriver);
1559 const int32_t err = MimerEndTransaction(d->sessionhandle, MIMER_COMMIT);
1560 if (!MIMER_SUCCEEDED(err)) {
1562 QCoreApplication::translate("QMimerSQLDriver", "Could not commit transaction"), err,
1564 return false;
1565 }
1566 return true;
1567}
1568
1570{
1571 Q_D(const QMimerSQLDriver);
1572 const int32_t err = MimerEndTransaction(d->sessionhandle, MIMER_ROLLBACK);
1573 if (!MIMER_SUCCEEDED(err)) {
1575 QCoreApplication::translate("QMimerSQLDriver", "Could not roll back transaction"),
1577 return false;
1578 }
1579 return true;
1580}
1581
1583 QString *table) const
1584{
1585 const QList<QStringView> l = QStringView(qualifiedName).split(u'.');
1586 int n = l.count();
1587 if (n > 2) {
1588 return; // can't possibly be a valid table qualifier
1589 } else if (n == 1) {
1590 *schema = QString();
1591 *table = l.at(0).toString();
1592 } else {
1593 *schema = l.at(0).toString();
1594 *table = l.at(1).toString();
1595 }
1596}
1597
\inmodule QtCore
Definition qbytearray.h:57
QByteArray trimmed() const &
Definition qbytearray.h:198
char * data()
\macro QT_NO_CAST_FROM_BYTEARRAY
Definition qbytearray.h:534
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
Definition qbytearray.h:474
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:557
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
Definition qbytearray.h:122
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:394
static QString translate(const char *context, const char *key, const char *disambiguation=nullptr, int n=-1)
\threadsafe
\inmodule QtCore\reentrant
Definition qdatetime.h:257
QTime time() const
Returns the time part of the datetime.
Definition qlist.h:74
const_reference at(qsizetype i) const noexcept
Definition qlist.h:429
qsizetype count() const noexcept
Definition qlist.h:387
\inmodule QtCore
Definition qmetatype.h:320
Type
\macro Q_DECLARE_OPAQUE_POINTER(PointerType)
Definition qmetatype.h:324
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:90
The QSqlDriver class is an abstract base class for accessing specific SQL databases.
Definition qsqldriver.h:25
IdentifierType
This enum contains a list of SQL identifier types.
Definition qsqldriver.h:40
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:32
@ PositionalPlaceholders
Definition qsqldriver.h:33
@ LowPrecisionNumbers
Definition qsqldriver.h:34
@ EventNotifications
Definition qsqldriver.h:35
@ PreparedQueries
Definition qsqldriver.h:32
@ NamedPlaceholders
Definition qsqldriver.h:33
@ BatchOperations
Definition qsqldriver.h:34
@ MultipleResultSets
Definition qsqldriver.h:35
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
QMetaType metaType() const
Returns the field's type as stored in the database.
void setValue(const QVariant &value)
Sets the value of the field to value.
void setName(const QString &name)
Sets the name of the field to name.
void setMetaType(QMetaType type)
Set's the field's variant type 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:67
void setPrecision(int precision)
Sets the field's precision.
void setSqlType(int type)
The QSqlIndex class provides functions to manipulate and describe database indexes.
Definition qsqlindex.h:16
The QSqlQuery class provides a means of executing and manipulating SQL statements.
Definition qsqlquery.h:23
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:25
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:76
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:7987
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
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:5299
QString & replace(qsizetype i, qsizetype len, QChar after)
Definition qstring.cpp:3794
qsizetype size() const
Returns the number of characters in this string.
Definition qstring.h:182
QString arg(qlonglong a, int fieldwidth=0, int base=10, QChar fillChar=u' ') const
Definition qstring.cpp:8606
qlonglong toLongLong(bool *ok=nullptr, int base=10) const
Returns the string converted to a {long long} using base base, which is 10 by default and must be bet...
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:5350
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:1083
static QString fromWCharArray(const wchar_t *string, qsizetype size=-1)
Definition qstring.h:1164
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:7822
QString & append(QChar c)
Definition qstring.cpp:3227
QString left(qsizetype n) const
Returns a substring that contains the n leftmost characters of the string.
Definition qstring.cpp:5161
QByteArray toUtf8() const &
Definition qstring.h:563
qsizetype length() const
Returns the number of characters in this string.
Definition qstring.h:187
\inmodule QtCore \reentrant
Definition qdatetime.h:189
int msec() const
Returns the millisecond part (0 to 999) of the time.
@ 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:547
T * data() noexcept
\inmodule QtCore
Definition qvariant.h:64
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:531
#define this
Definition dialogs.cpp:9
@ BeforeFirstRow
Definition qtsqlglobal.h:22
@ SystemTables
Definition qtsqlglobal.h:38
@ Views
Definition qtsqlglobal.h:39
@ Tables
Definition qtsqlglobal.h:37
@ AllTables
Definition qtsqlglobal.h:40
@ InOut
Definition qtsqlglobal.h:30
@ LowPrecisionInt32
Definition qtsqlglobal.h:45
@ LowPrecisionDouble
Definition qtsqlglobal.h:47
@ LowPrecisionInt64
Definition qtsqlglobal.h:46
@ HighPrecision
Definition qtsqlglobal.h:49
Combined button and popup list for selecting options.
EGLOutputPortEXT port
#define qWarning
Definition qlogging.h:162
#define Q_DECLARE_OPAQUE_POINTER(POINTER)
Definition qmetatype.h:1496
#define Q_DECLARE_METATYPE(TYPE)
Definition qmetatype.h:1504
GLenum GLsizei GLsizei GLint * values
[15]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint index
[2]
GLfloat GLfloat f
GLenum type
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLfloat n
GLenum GLenum GLsizei void GLsizei void * column
GLboolean reset
GLenum query
GLuint res
GLuint GLfloat * val
GLdouble GLdouble t
Definition qopenglext.h:243
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLenum GLenum GLsizei void * row
GLdouble s
[6]
Definition qopenglext.h:235
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)
MimerColumnTypes
#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:70
unsigned int uint
Definition qtypes.h:29
long long qint64
Definition qtypes.h:55
QObject::connect nullptr
QMimeDatabase db
[0]
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent