Warning: That file was not part of the compilation database. It may have many parsing errors.

1/****************************************************************************
2**
3** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4** Contact: http://www.qt-project.org/legal
5**
6** This file is part of the QtSql module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Digia. For licensing terms and
14** conditions see http://qt.digia.com/licensing. For further information
15** use the contact form at http://qt.digia.com/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 2.1 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 2.1 requirements
23** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24**
25** In addition, as a special exception, Digia gives you certain additional
26** rights. These rights are described in the Digia Qt LGPL Exception
27** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28**
29** GNU General Public License Usage
30** Alternatively, this file may be used under the terms of the GNU
31** General Public License version 3.0 as published by the Free Software
32** Foundation and appearing in the file LICENSE.GPL included in the
33** packaging of this file. Please review the following information to
34** ensure the GNU General Public License version 3.0 requirements will be
35** met: http://www.gnu.org/copyleft/gpl.html.
36**
37**
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qsql_symsql.h"
43
44
45#define SYMBIAN_ENABLE_PUBLIC_PLATFORM_HEADER_SPLIT
46
47#include <qcoreapplication.h>
48#include <qvariant.h>
49#include <qsqlerror.h>
50#include <qsqlfield.h>
51#include <qsqlindex.h>
52#include <qsqlquery.h>
53#include <qstringlist.h>
54#include <qvector.h>
55#include <qdebug.h>
56#include "../../../corelib/kernel/qcore_symbian_p.h"
57
58#if defined Q_OS_WIN
59# include <qt_windows.h>
60#else
61# include <unistd.h>
62#endif
63
64#include <sqldb.h>
65#include <e32capability.h>
66
67const char* qCapabilityNames[ECapability_Limit] =
68{
69 "TCB",
70 "CommDD",
71 "PowerMgmt",
72 "MultimediaDD",
73 "ReadDeviceData",
74 "WriteDeviceData",
75 "DRM",
76 "TrustedUI",
77 "ProtServ",
78 "DiskAdmin",
79 "NetworkControl",
80 "AllFiles",
81 "SwEvent",
82 "NetworkServices",
83 "LocalServices",
84 "ReadUserData",
85 "WriteUserData",
86 "Location",
87 "SurroundingsDD",
88 "UserEnvironment"
89};
90
91const char qCapabilityNone[] = "None";
92
93
94Q_DECLARE_METATYPE(RSqlDatabase)
95Q_DECLARE_METATYPE(RSqlStatement)
96
97QT_BEGIN_NAMESPACE
98
99const QString valueSeparator(QLatin1String("="));
100const QString fieldSeparator(QLatin1String(","));
101
102static QString _q_escapeIdentifier(const QString &identifier)
103{
104 QString res = identifier;
105 if (!identifier.isEmpty()
106 && identifier.left(1) != QString(QLatin1Char('"'))
107 && identifier.right(1) != QString(QLatin1Char('"'))) {
108 res.replace(QLatin1Char('"'), QLatin1String("\"\""));
109 res.prepend(QLatin1Char('"')).append(QLatin1Char('"'));
110 res.replace(QLatin1Char('.'), QLatin1String("\".\""));
111 }
112 return res;
113}
114
115static QVariant::Type qGetColumnType(const TSqlColumnType coltype)
116{
117 switch(coltype){
118 case ESqlInt:
119 case ESqlInt64:
120 return QVariant::Int;
121 case ESqlReal:
122 return QVariant::Double;
123 case ESqlBinary:
124 return QVariant::ByteArray;
125 case ESqlText:
126 case ESqlNull:
127 default:
128 return QVariant::String;
129 }
130}
131
132static QVariant::Type qGetColumnType(const QString &tpName)
133{
134 const QString typeName = tpName.toLower();
135
136 if (typeName == QLatin1String("integer")
137 || typeName == QLatin1String("int"))
138 return QVariant::Int;
139 if (typeName == QLatin1String("double")
140 || typeName == QLatin1String("float")
141 || typeName == QLatin1String("real")
142 || typeName.startsWith(QLatin1String("numeric")))
143 return QVariant::Double;
144 if (typeName == QLatin1String("blob"))
145 return QVariant::ByteArray;
146 return QVariant::String;
147}
148
149static QSqlError qMakeError(RSqlDatabase& access,
150 const QString &descr,
151 QSqlError::ErrorType type,
152 int errorCode = -1)
153{
154 return QSqlError(descr,
155 QString::fromUtf16(static_cast<const ushort *>(access.LastErrorMessage().Ptr())),
156 type,
157 errorCode);
158}
159
160
161static QSqlError gMakeErrorOpen(const QString &descr,
162 QSqlError::ErrorType type,
163 TInt errorCode)
164{
165 return QSqlError(descr, QLatin1String(""), type, errorCode);
166}
167
168class QSymSQLDriverPrivate
169{
170public:
171 inline QSymSQLDriverPrivate() {}
172 RSqlDatabase access;
173};
174
175class QSymSQLResultPrivate
176{
177public:
178 QSymSQLResultPrivate(QSymSQLResult *res);
179 void cleanup();
180 bool fetchNext(bool initialFetch);
181 // initializes the recordInfo
182 void initColumns(QSqlRecord& rec);
183 void finalize();
184
185 QSymSQLResult* q;
186 RSqlDatabase access;
187 RSqlStatement stmt;
188 bool skipRow; // skip the next fetchNext()?
189 bool skippedStatus; // the status of the fetchNext() that's skipped
190 bool prepareCalled;
191};
192
193QSymSQLResultPrivate::QSymSQLResultPrivate(QSymSQLResult* res) : q(res),
194 skipRow(false),
195 skippedStatus(false),
196 prepareCalled(false)
197{
198}
199
200void QSymSQLResultPrivate::cleanup()
201{
202 finalize();
203 skippedStatus = false;
204 skipRow = false;
205 q->setAt(QSql::BeforeFirstRow);
206 q->setActive(false);
207}
208
209void QSymSQLResultPrivate::finalize()
210{
211 prepareCalled = false;
212 stmt.Close();
213}
214
215void QSymSQLResultPrivate::initColumns(QSqlRecord& rec)
216{
217 int nCols = stmt.ColumnCount();
218 if (nCols <= 0) {
219 q->setLastError(qMakeError(access, QCoreApplication::translate("QSymSQLResult",
220 "Error retrieving column count"), QSqlError::UnknownError, nCols));
221 return;
222 }
223
224 for (int i = 0; i < nCols; ++i) {
225 TPtrC cName;
226 TInt err = stmt.ColumnName(i, cName);
227
228 if (err != KErrNone) {
229 q->setLastError(qMakeError(access, QCoreApplication::translate("QSymSQLResult",
230 "Error retrieving column name"), QSqlError::UnknownError, err));
231 return;
232 }
233
234 QString colName = qt_TDesC2QString(cName);
235
236 // must use typeName for resolving the type to match QSymSQLDriver::record
237 TPtrC tName;
238 TSqlColumnType decColType;
239 err = stmt.DeclaredColumnType(i, decColType);
240
241 if (err != KErrNone) {
242 q->setLastError(qMakeError(access, QCoreApplication::translate("QSymSQLResult",
243 "Error retrieving column type"), QSqlError::UnknownError, err));
244 return;
245 }
246
247 int dotIdx = colName.lastIndexOf(QLatin1Char('.'));
248 QSqlField fld(colName.mid(dotIdx == -1 ? 0 : dotIdx + 1), qGetColumnType(decColType));
249
250 rec.append(fld);
251 }
252}
253
254bool QSymSQLResultPrivate::fetchNext(bool initialFetch)
255{
256 int res;
257
258 if (skipRow) {
259 // already fetched
260 Q_ASSERT(!initialFetch);
261 skipRow = false;
262 return skippedStatus;
263 }
264
265 skipRow = initialFetch;
266 res = stmt.Next();
267
268 switch(res) {
269 case KSqlAtRow:
270 return true;
271 case KSqlAtEnd:
272 stmt.Reset();
273 return false;
274 case KSqlErrGeneral:
275 // KSqlErrGeneral is a generic error code and we must call stmt.Reset()
276 // to get the specific error message.
277 stmt.Reset();
278 q->setLastError(qMakeError(access, QCoreApplication::translate("QSymSQLResult",
279 "Unable to fetch row"), QSqlError::ConnectionError, res));
280 q->setAt(QSql::AfterLastRow);
281 return false;
282 case KSqlErrMisuse:
283 case KSqlErrBusy:
284 default:
285 // something wrong, don't get col info, but still return false
286 q->setLastError(qMakeError(access, QCoreApplication::translate("QSymSQLResult",
287 "Unable to fetch row"), QSqlError::ConnectionError, res));
288 stmt.Reset();
289 q->setAt(QSql::AfterLastRow);
290 return false;
291 }
292 return false;
293}
294
295////////////////////////////////// QSymSQLResult /////////////////////////////////////////////////
296
297QSymSQLResult::QSymSQLResult(const QSymSQLDriver* db)
298 : QSqlResult(db)
299{
300 d = new QSymSQLResultPrivate(this);
301 d->access = db->d->access;
302}
303
304
305QSymSQLResult::~QSymSQLResult()
306{
307 d->cleanup();
308 delete d;
309}
310
311bool QSymSQLResult::reset(const QString &query)
312{
313 if (!prepare(query))
314 return false;
315
316 return exec();
317}
318
319bool QSymSQLResult::prepare(const QString &query)
320{
321 if (!driver() || !driver()->isOpen() || driver()->isOpenError())
322 return false;
323
324 d->cleanup();
325 setSelect(false);
326
327 TInt res = d->stmt.Prepare(d->access, qt_QString2TPtrC(query));
328
329 if (res != KErrNone) {
330 setLastError(qMakeError(d->access, QCoreApplication::translate("QSymSQLResult",
331 "Unable to execute statement"), QSqlError::StatementError, res));
332 d->finalize();
333 return false;
334 }
335
336 d->prepareCalled = true;
337
338 return true;
339}
340
341bool QSymSQLResult::exec()
342{
343 if (d->prepareCalled == false) {
344 setLastError(qMakeError(d->access, QCoreApplication::translate("QSymSQLResult",
345 "Statement is not prepared"), QSqlError::StatementError, KErrGeneral));
346 return false;
347 }
348
349 const QVector<QVariant> values = boundValues();
350
351 d->skippedStatus = false;
352 d->skipRow = false;
353 setAt(QSql::BeforeFirstRow);
354 setLastError(QSqlError());
355 int res = d->stmt.Reset();
356
357 if (res != KErrNone) {
358 setLastError(qMakeError(d->access, QCoreApplication::translate("QSymSQLResult",
359 "Unable to reset statement"), QSqlError::StatementError, res));
360 d->finalize();
361 return false;
362 }
363 TPtrC tmp;
364 TInt paramCount = 0;
365 while (d->stmt.ParamName(paramCount, tmp) == KErrNone)
366 paramCount++;
367
368 if (paramCount == values.count()) {
369 for (int i = 0; i < paramCount; ++i) {
370 res = KErrNone;
371 const QVariant value = values.at(i);
372
373 if (value.isNull()) {
374 res = d->stmt.BindNull(i); //replaced i + 1 with i
375 } else {
376 switch (value.type()) {
377 case QVariant::ByteArray: {
378 const QByteArray *ba = static_cast<const QByteArray*>(value.constData());
379 TPtrC8 data(reinterpret_cast<const TUint8 *>(ba->constData()), ba->length());
380 res = d->stmt.BindBinary(i, data); //replaced i + 1 with i
381 break; }
382 case QVariant::Int:
383 res = d->stmt.BindInt(i, value.toInt()); //replaced i + 1 with i
384 break;
385 case QVariant::Double:
386 res = d->stmt.BindReal(i, value.toDouble()); //replaced i + 1 with i
387
388 break;
389 case QVariant::UInt:
390 case QVariant::LongLong:
391 res = d->stmt.BindReal(i, value.toLongLong()); //replaced i + 1 with i
392 break;
393
394 case QVariant::String: {
395 // lifetime of string == lifetime of its qvariant
396 const QString *str = static_cast<const QString*>(value.constData());
397 res = d->stmt.BindText(i, qt_QString2TPtrC(*str)); // replaced i + 1 with i
398 break; }
399 default: {
400 QString str = value.toString();
401 res = d->stmt.BindText(i, qt_QString2TPtrC(str)); //replaced i + 1 with i
402 break; }
403 }
404 }
405 if (res != KErrNone) {
406 setLastError(qMakeError(d->access, QCoreApplication::translate("QSymSQLResult",
407 "Unable to bind parameters"), QSqlError::StatementError, res));
408 d->finalize();
409 return false;
410 }
411 }
412 } else {
413 setLastError(QSqlError(QCoreApplication::translate("QSymSQLResult",
414 "Parameter count mismatch"), QString(), QSqlError::StatementError));
415 return false;
416 }
417
418 d->skippedStatus = d->fetchNext(true);
419
420 if (lastError().isValid()) {
421 setSelect(false);
422 setActive(false);
423 return false;
424 }
425
426 if (d->stmt.ColumnCount() > 0) {
427 //If there is something, it has to be select
428 setSelect(true);
429 } else {
430 //If there isn't it might be just bad query, let's check manually whether we can find SELECT
431 QString query = this->lastQuery();
432 query = query.trimmed();
433 query = query.toLower();
434
435 //Just check whether there is one in the beginning, don't know if this is enough
436 //Comments should be at the end of line if those are passed
437 //For some reason, case insensitive indexOf didn't work for me
438 if (query.indexOf(QLatin1String("select")) == 0) {
439 setSelect(true);
440 } else {
441 setSelect(false);
442 }
443 }
444
445 setActive(true);
446 return true;
447}
448
449
450int QSymSQLResult::size()
451{
452 return -1;
453}
454
455int QSymSQLResult::numRowsAffected()
456{
457 return -1;
458}
459
460QVariant QSymSQLResult::lastInsertId() const
461{
462 if (isActive()) {
463 qint64 id = static_cast<qint64>(d->access.LastInsertedRowId());
464 if (id)
465 return id;
466 }
467
468 return QVariant();
469}
470
471QSqlRecord QSymSQLResult::record() const
472{
473 if (!isActive() || !isSelect())
474 return QSqlRecord();
475
476 QSqlRecord res;
477 d->initColumns(res);
478
479 return res;
480}
481
482QVariant QSymSQLResult::handle() const
483{
484 return qVariantFromValue(d->stmt);
485}
486
487
488void QSymSQLResult::virtual_hook(int id, void *data)
489{
490 switch (id)
491 {
492 case QSqlResult::DetachFromResultSet:
493 d->stmt.Reset();
494 break;
495 default:
496 QSqlResult::virtual_hook(id, data);
497 }
498}
499
500QVariant QSymSQLResult::data(int idx)
501{
502 QVariant r;
503
504 switch (d->stmt.ColumnType(idx)) {
505 case ESqlBinary:
506 {
507 TPtrC8 data;
508 d->stmt.ColumnBinary(idx, data);
509 return QByteArray(reinterpret_cast<const char *>(data.Ptr()), data.Length());
510 break;
511 }
512 case ESqlInt:
513 r = QVariant(d->stmt.ColumnInt(idx));
514 break;
515 case ESqlInt64:
516 r = QVariant(d->stmt.ColumnInt64(idx));
517 break;
518 case ESqlReal:
519 switch(numericalPrecisionPolicy()) {
520 case QSql::LowPrecisionInt32:
521 r = QVariant(d->stmt.ColumnInt(idx));
522 break;
523 case QSql::LowPrecisionInt64:
524 r = QVariant(d->stmt.ColumnInt64(idx));
525 break;
526 case QSql::LowPrecisionDouble:
527 r = QVariant(d->stmt.ColumnReal(idx));
528 break;
529 case QSql::HighPrecision:
530 default:
531 TPtrC res;
532 d->stmt.ColumnText(idx, res);
533 r = QVariant(qt_TDesC2QString(res));
534 break;
535 };
536 break;
537 case ESqlNull:
538 r = QVariant(QVariant::String);
539 break;
540 default:
541 TPtrC res;
542 d->stmt.ColumnText(idx, res);
543 r = QVariant(qt_TDesC2QString(res));
544 break;
545 }
546
547 return r;
548}
549
550bool QSymSQLResult::isNull(int i)
551{
552 return d->stmt.IsNull(i);
553}
554
555bool QSymSQLResult::fetch(int i)
556{
557 //Single return point modified according to review
558 bool retVal = true;
559
560 if (i < 0 || !isActive()) {
561 retVal = false;
562 } else {
563 if (at() <= -1 || i < at()) {
564 d->stmt.Reset();
565 setAt(-1);
566 d->skipRow = false;
567 }
568
569 while (at() < i) {
570 if (!d->fetchNext(false)) {
571 retVal = false;
572 break;
573 }
574
575 setAt(at() + 1);
576 }
577 }
578
579 return retVal;
580}
581
582bool QSymSQLResult::fetchNext()
583{
584 bool res = d->fetchNext(false);
585 if (res) {
586 setAt(at()+1);
587 }
588
589 return res;
590}
591
592bool QSymSQLResult::fetchPrevious()
593{
594 return QSqlResult::fetchPrevious();
595}
596
597bool QSymSQLResult::fetchFirst()
598{
599 return fetch(0);
600}
601
602bool QSymSQLResult::fetchLast()
603{
604 if (!isActive())
605 return false;
606
607 if (at() <= -1) {
608 if (!fetchFirst())
609 return false;
610 }
611
612 TInt res;
613
614 do {
615 res = d->stmt.Next();
616 setAt(at()+1);
617 } while (res == KSqlAtRow);
618
619 if (res != KSqlAtEnd)
620 return false;
621
622 d->skippedStatus = false;
623 d->skipRow = false;
624
625 return fetchPrevious();
626}
627////////////////////////////////// QSymSQLDriver //////////////////////////////////////////
628
629QSymSQLDriver::QSymSQLDriver(QObject * parent)
630 : QSqlDriver(parent)
631{
632 d = new QSymSQLDriverPrivate();
633}
634
635QSymSQLDriver::QSymSQLDriver(RSqlDatabase& connection, QObject *parent)
636 : QSqlDriver(parent)
637{
638 d = new QSymSQLDriverPrivate();
639 d->access = connection;
640 setOpen(true);
641 setOpenError(false);
642}
643
644
645QSymSQLDriver::~QSymSQLDriver()
646{
647 d->access.Close();
648 delete d;
649}
650
651bool QSymSQLDriver::hasFeature(DriverFeature f) const
652{
653 switch (f) {
654 case BLOB:
655 case Transactions:
656 case Unicode:
657 case PreparedQueries:
658 case PositionalPlaceholders:
659 case SimpleLocking:
660 case FinishQuery:
661 case LowPrecisionNumbers:
662 case LastInsertId:
663 case NamedPlaceholders:
664 return true;
665 case QuerySize:
666 case BatchOperations:
667 case EventNotifications:
668 case MultipleResultSets:
669 return false;
670 }
671 return false;
672}
673
674/*!
675 Converts capability string to TCapability
676*/
677TCapability qMatchCapStr(QString& str)
678{
679 TCapability cap = ECapability_HardLimit;
680
681 for (int i = 0; i < static_cast<int>(ECapability_Limit); i++) {
682 if (str.compare(QLatin1String(qCapabilityNames[i]), Qt::CaseInsensitive) == 0) {
683 cap = static_cast<TCapability>(i);
684 break;
685 }
686 }
687
688 //Special case, we allow ECapability_None to be defined
689 if (cap == ECapability_HardLimit
690 && str.compare(QLatin1String(qCapabilityNone), Qt::CaseInsensitive) == 0)
691 cap = ECapability_None;
692
693 return cap;
694}
695
696bool qExtractSecurityPolicyFromString(const QString &string, TSecurityPolicy &policy)
697{
698 int startPos = string.indexOf(QLatin1Char('='));
699 QStringList values;
700 bool ret = false;
701
702 if (startPos == -1) {
703 values = string.split(QLatin1Char(','), QString::SkipEmptyParts);
704 } else {
705 values = string.mid(startPos + 1).split(QLatin1Char(','), QString::SkipEmptyParts);
706 }
707
708 if (values.count() > 0) {
709 const QString findVid(QLatin1String("vid["));
710 const QString findSid(QLatin1String("sid["));
711 const int MaxCapCount = 7;
712 const int VidMaxCount = 3;
713 const int SidMaxCount = 3;
714
715 TCapability capList[MaxCapCount] = { ECapability_None,ECapability_None,ECapability_None,
716 ECapability_None,ECapability_None,ECapability_None,ECapability_None };
717
718 bool isVID = false;
719 bool isSID = false;
720
721 QString idString(QLatin1String(""));
722 int maxAllowed = MaxCapCount;
723
724 if (values[0].contains(findVid, Qt::CaseInsensitive)) {
725 idString = values[0].remove(findVid, Qt::CaseInsensitive);
726 idString = idString.remove(QLatin1Char(']'));
727 values.removeAt(0);
728 isVID = true;
729 maxAllowed = VidMaxCount;
730
731 } else if (values[0].contains(findSid, Qt::CaseInsensitive)) {
732 idString = values[0].remove(findSid, Qt::CaseInsensitive);
733 idString = idString.remove(QLatin1Char(']'));
734 values.removeAt(0);
735 isSID = true;
736 maxAllowed = SidMaxCount;
737 }
738
739 if (values.count() <= maxAllowed) {
740 bool wasSuccesful = true;
741
742 for (int i = 0; i < values.count(); i++) {
743 capList[i] = qMatchCapStr(values[i]);
744
745 if (capList[i] == ECapability_HardLimit) {
746 wasSuccesful = false;
747 break;
748 }
749 }
750
751 if (wasSuccesful) {
752 if (isVID || isSID){
753 bool ok = true;
754 quint32 id = idString.toUInt(&ok, 16);
755
756 if (ok) {
757 if (isVID) {
758 TVendorId vid(id);
759 policy = TSecurityPolicy(vid, capList[0], capList[1], capList[2]);
760 } else {
761 TSecureId sid(id);
762 policy = TSecurityPolicy(sid, capList[0], capList[1], capList[2]);
763 }
764
765 ret = true; //Everything is fine
766 }
767 } else {
768 policy = TSecurityPolicy(capList[0], capList[1], capList[2], capList[3],
769 capList[4], capList[5], capList[6]);
770
771 ret = true; //Everything is fine
772 }
773 }
774 }
775 }
776
777 return ret;
778}
779
780/*!
781 Opens the database connection using the given connection options. Returns true on success; otherwise returns false.
782 Error information can be retrieved using the lastError() function. Symbian SQL dbs have no \a user, \a password, \a host
783 or \a port just file names.
784
785 \a connOpts Connection options hold definition for security policies and all parameters that does not contain "POLICY_" will be
786 passed to RSqlDatabase. Policy will be filled according to parsed values.
787
788 Value in database wide parameters starts by definition which can be vendorId or secureId. These come directly from TSecurityPolicy class in Symbian.
789
790 POLICY_DB_DEFAULT
791 Default security policy which will be used for the database and all database objects. POLICY_DB_DEFAULT must be
792 defined before any other policy definitions can be used.
793 POLICY_DB_READ
794 Read database security policy. An application with read database security policy can read from database.
795 POLICY_DB_WRITE:
796 Write database security policy. An application with write database security policy can write to database.
797 POLICY_DB_SCHEMA:
798 Schema database security policy. An application with schema database security policy can modify
799 the database schema, write to database, read from database.
800
801 Format:
802 POLICY_DB_DEFAULT=cap1,cap2,cap3,cap4,cap5,cap6,cap7 (Up to 7 capabilities)
803 POLICY_DB_READ=cap1,cap2,cap3,cap4,cap5,cap6,cap7 (Up to 7 capabilities)
804 POLICY_DB_WRITE=vendorid,cap1,cap2,cap3 (Vendor ID and up to 3 capabilities)
805 POLICY_DB_SCHEMA=secureid,cap1,cap2,cap3 (Secure ID and up to 3 capabilities)
806
807 Table policies does not support schema policy as database level does.
808
809 Table specific parameters would be as:
810 POLICY_TABLE_WRITE=tablename,cap1,cap2,cap3,cap4,cap5,cap6,cap7
811 POLICY_TABLE_READ=tablename,cap1,cap2,cap3,cap4,cap5,cap6,cap7
812
813 Vendor Id and Secure id format:
814 vid[0x12345678] (Hex)
815 sid[0x12345678] (Hex)
816
817 Example:
818 \code
819 QSqlDatabase database = QSqlDatabase::addDatabase("QSYMSQL", "MyConnection");
820 database.setConnectOptions("POLICY_DB_DEFAULT=ReadDeviceData");
821 database.setDatabaseName("[12345678]myDatabase");
822 bool ok = database.open();
823 \encode
824
825 \code
826 QSqlDatabase database = QSqlDatabase::addDatabase("QSYMSQL", "MyConnection");
827 database.setConnectOptions("POLICY_DB_DEFAULT=None; POLICY_DB_WRITE=sid[0x12345678], WriteDeviceData");
828 database.setDatabaseName("[12345678]myDatabase");
829 bool ok = database.open();
830 \encode
831
832 FOREIGN KEY:
833 Enabling foreign key support from underlying SQLite
834 add: "foreign_keys = ON" to your connection options string. This will be passes to SQLite.
835
836 Foreign key Example:
837 \code
838 QSqlDatabase database = QSqlDatabase::addDatabase("QSYMSQL", "MyConnection");
839 database.setDatabaseName("[12345678]myDatabase");
840 database.setConnectOptions("foreign_keys = ON");
841 bool ok = database.open();
842 \encode
843
844 More information about Symbian Security Policy can be found from Symbian documentation.
845
846*/
847bool QSymSQLDriver::open(const QString & db, const QString &, const QString &, const QString &, int, const QString &conOpts)
848{
849 if (isOpen())
850 close();
851 if (db.isEmpty())
852 return false;
853
854 //Separating our parameters from Symbian ones and construct new connection options
855 const QString itemSeparator(QLatin1String(";"));
856 QRegExp isOurOption(QLatin1String("POLICY_*"), Qt::CaseInsensitive, QRegExp::Wildcard);
857
858 QStringList optionList = conOpts.split(itemSeparator, QString::SkipEmptyParts);
859 QStringList symbianList;
860
861 for (int i = optionList.count() - 1; i >= 0; i--) {
862 if (!optionList[i].contains(isOurOption)) {
863 symbianList.append(optionList[i]);
864 optionList.removeAt(i);
865 } else {
866 //Removing whitespace
867 QString formatted = optionList[i];
868 formatted = formatted.remove(QLatin1Char(' '));
869 formatted = formatted.remove(QLatin1Char('\t'));
870 formatted = formatted.remove(QLatin1Char('\n'));
871 formatted = formatted.remove(QLatin1Char('\r'));
872 optionList[i] = formatted;
873 }
874 }
875
876 QString symbianOpt;
877
878 for (int i = 0; i < symbianList.count(); i++) {
879 symbianOpt += symbianList[i];
880 symbianOpt += itemSeparator;
881 }
882
883 TPtrC dbName(qt_QString2TPtrC(db));
884 QByteArray conOpts8 = symbianOpt.toUtf8();
885 const TPtrC8 config(reinterpret_cast<const TUint8*>(conOpts8.constData()), (conOpts8.length()));
886
887 TInt res = d->access.Open(dbName, &config);
888
889 if (res == KErrNotFound) {
890
891 QRegExp findDefault(QLatin1String("POLICY_DB_DEFAULT=*"), Qt::CaseInsensitive, QRegExp::Wildcard);
892 QRegExp findRead(QLatin1String("POLICY_DB_READ=*"), Qt::CaseInsensitive, QRegExp::Wildcard);
893 QRegExp findWrite(QLatin1String("POLICY_DB_WRITE=*"), Qt::CaseInsensitive, QRegExp::Wildcard);
894 QRegExp findSchema(QLatin1String("POLICY_DB_SCHEMA=*"), Qt::CaseInsensitive, QRegExp::Wildcard);
895 QRegExp findTableRead(QLatin1String("POLICY_TABLE_READ=*"), Qt::CaseInsensitive, QRegExp::Wildcard);
896 QRegExp findTableWrite(QLatin1String("POLICY_TABLE_WRITE=*"), Qt::CaseInsensitive, QRegExp::Wildcard);
897
898 int policyIndex = optionList.indexOf(findDefault);
899
900 if (policyIndex != -1) {
901 QString defaultPolicyString = optionList[policyIndex];
902 optionList.removeAt(policyIndex);
903
904 TSecurityPolicy policyItem;
905
906 if (qExtractSecurityPolicyFromString(defaultPolicyString, policyItem)) {
907 RSqlSecurityPolicy policy;
908 res = policy.Create(policyItem);
909
910 if (res == KErrNone) {
911 for (int i = 0; i < optionList.count(); i++) {
912 QString option = optionList[i];
913
914 if (option.contains(findRead)) {
915 if (qExtractSecurityPolicyFromString(option, policyItem)) {
916 res = policy.SetDbPolicy(RSqlSecurityPolicy::EReadPolicy, policyItem);
917 } else {
918 res = KErrArgument;
919 }
920 } else if (option.contains(findWrite)) {
921 if (qExtractSecurityPolicyFromString(option, policyItem)) {
922 res = policy.SetDbPolicy(RSqlSecurityPolicy::EWritePolicy, policyItem);
923 } else {
924 res = KErrArgument;
925 }
926 } else if (option.contains(findSchema)) {
927 if (qExtractSecurityPolicyFromString(option, policyItem)) {
928 res = policy.SetDbPolicy(RSqlSecurityPolicy::ESchemaPolicy, policyItem);
929 } else {
930 res = KErrArgument;
931 }
932 } else if (option.contains(findTableWrite)) {
933 QString tableOption = option.mid(option.indexOf(QLatin1Char('=')) + 1);
934 int firstComma = tableOption.indexOf(QLatin1Char(','));
935
936 if (firstComma != -1) {
937 QString tableName = tableOption.left(firstComma);
938 tableOption = tableOption.mid(firstComma + 1);
939
940 if (qExtractSecurityPolicyFromString(tableOption, policyItem)) {
941 TPtrC symTableName(qt_QString2TPtrC(tableName));
942
943 res = policy.SetPolicy(RSqlSecurityPolicy::ETable, symTableName,
944 RSqlSecurityPolicy::EWritePolicy, policyItem);
945 } else {
946 res = KErrArgument;
947 }
948 } else {
949 res = KErrArgument;
950 }
951 } else if (option.contains(findTableRead)) {
952 QString tableOption = option.mid(option.indexOf(QLatin1Char('=')) + 1);
953 int firstComma = tableOption.indexOf(QLatin1Char(','));
954
955 if (firstComma != -1) {
956 QString tableName = tableOption.left(firstComma);
957 tableOption = tableOption.mid(firstComma + 1);
958
959 if (qExtractSecurityPolicyFromString(tableOption, policyItem)) {
960 TPtrC symTableName(qt_QString2TPtrC(tableName));
961
962 res = policy.SetPolicy(RSqlSecurityPolicy::ETable, symTableName,
963 RSqlSecurityPolicy::EReadPolicy, policyItem);
964 } else {
965 res = KErrArgument;
966 }
967 } else {
968 res = KErrArgument;
969 }
970 } else {
971 res = KErrArgument;
972 }
973
974 if (res != KErrNone) {
975 setLastError(gMakeErrorOpen(tr("Invalid option: ") + option, QSqlError::ConnectionError, res));
976 break;
977 }
978 }
979
980 if (res == KErrNone) {
981 res = d->access.Create(dbName, policy, &config);
982 policy.Close();
983
984 if (res != KErrNone)
985 setLastError(gMakeErrorOpen(tr("Error opening database"), QSqlError::ConnectionError, res));
986 }
987 }
988
989 } else {
990 res = KErrArgument;
991 setLastError(gMakeErrorOpen(tr("Invalid option: ") + defaultPolicyString, QSqlError::ConnectionError, res));
992 }
993
994 } else {
995 //Check whether there is some of our options, fail if so.
996 policyIndex = optionList.indexOf(isOurOption);
997
998 if (policyIndex == -1) {
999 res = d->access.Create(dbName, &config);
1000
1001 if (res != KErrNone)
1002 setLastError(gMakeErrorOpen(tr("Error opening database"), QSqlError::ConnectionError, res));
1003 } else {
1004 res = KErrArgument;
1005 setLastError(gMakeErrorOpen(tr("POLICY_DB_DEFAULT must be defined before any other POLICY definitions can be used"), QSqlError::ConnectionError, res));
1006 }
1007 }
1008 }
1009
1010 if (res == KErrNone) {
1011 setOpen(true);
1012 setOpenError(false);
1013 return true;
1014 } else {
1015 setOpenError(true);
1016 return false;
1017 }
1018}
1019
1020void QSymSQLDriver::close()
1021{
1022 if (isOpen()) {
1023 d->access.Close();
1024 setOpen(false);
1025 setOpenError(false);
1026 }
1027}
1028
1029QSqlResult *QSymSQLDriver::createResult() const
1030{
1031 return new QSymSQLResult(this);
1032}
1033
1034bool QSymSQLDriver::beginTransaction()
1035{
1036 if (!isOpen() || isOpenError())
1037 return false;
1038
1039 TInt err = d->access.Exec(_L("BEGIN"));
1040 if (err < KErrNone) {
1041 setLastError(QSqlError(tr("Unable to begin transaction"),
1042 qt_TDesC2QString(d->access.LastErrorMessage()), QSqlError::TransactionError, err));
1043 return false;
1044 }
1045
1046 return true;
1047}
1048
1049bool QSymSQLDriver::commitTransaction()
1050{
1051 if (!isOpen() || isOpenError())
1052 return false;
1053
1054 TInt err = d->access.Exec(_L("COMMIT"));
1055 if (err < KErrNone) {
1056 setLastError(QSqlError(tr("Unable to commit transaction"),
1057 qt_TDesC2QString(d->access.LastErrorMessage()), QSqlError::TransactionError, err));
1058 return false;
1059 }
1060
1061 return true;
1062}
1063
1064bool QSymSQLDriver::rollbackTransaction()
1065{
1066 if (!isOpen() || isOpenError())
1067 return false;
1068
1069 TInt err = d->access.Exec(_L("ROLLBACK"));
1070 if (err < KErrNone) {
1071 setLastError(QSqlError(tr("Unable to rollback transaction"),
1072 qt_TDesC2QString(d->access.LastErrorMessage()), QSqlError::TransactionError, err));
1073 return false;
1074 }
1075
1076 return true;
1077}
1078
1079QStringList QSymSQLDriver::tables(QSql::TableType type) const
1080{
1081 QStringList res;
1082 if (!isOpen())
1083 return res;
1084
1085 QSqlQuery q(createResult());
1086 q.setForwardOnly(true);
1087
1088 QString sql = QLatin1String("SELECT name FROM sqlite_master WHERE %1 "
1089 "UNION ALL SELECT name FROM sqlite_temp_master WHERE %1");
1090 if ((type & QSql::Tables) && (type & QSql::Views))
1091 sql = sql.arg(QLatin1String("type='table' OR type='view'"));
1092 else if (type & QSql::Tables)
1093 sql = sql.arg(QLatin1String("type='table'"));
1094 else if (type & QSql::Views)
1095 sql = sql.arg(QLatin1String("type='view'"));
1096 else
1097 sql.clear();
1098
1099 if (!sql.isEmpty() && q.exec(sql)) {
1100 while (q.next())
1101 res.append(q.value(0).toString());
1102 }
1103
1104 if (type & QSql::SystemTables)
1105 // there are no internal tables beside this one:
1106 res.append(QLatin1String("sqlite_master"));
1107
1108 return res;
1109}
1110
1111static QSqlIndex qGetTableInfo(QSqlQuery &q, QString &tableName, bool onlyPIndex = false)
1112{
1113 QString dbName;
1114 QString table(tableName);
1115 int indexOfSeparator = tableName.indexOf(QLatin1Char('.'));
1116 if (indexOfSeparator > -1) {
1117 dbName = tableName.left(indexOfSeparator +1 );
1118 table = tableName.mid(indexOfSeparator + 1);
1119 }
1120 q.exec(QLatin1String("PRAGMA ") + dbName + QLatin1String("table_info (") + _q_escapeIdentifier(table) + QLatin1String(")"));
1121
1122 const int NAME_IDX = 1;
1123 const int TYPE_IDX = 2;
1124 const int NOTNULL_IDX = 3;
1125 const int DFLT_VALUE_IDX = 4;
1126 const int PK_IDX = 5;
1127
1128 QSqlIndex ind;
1129 while (q.next()) {
1130 bool isPk = q.value(PK_IDX).toInt();
1131 if (onlyPIndex && !isPk)
1132 continue;
1133 QString typeName = q.value(TYPE_IDX).toString().toLower();
1134 QSqlField fld(q.value(NAME_IDX).toString(), qGetColumnType(typeName));
1135 if (isPk && (typeName == QLatin1String("integer")))
1136 // INTEGER PRIMARY KEY fields are auto-generated in sqlite
1137 // INT PRIMARY KEY is not the same as INTEGER PRIMARY KEY!
1138 fld.setAutoValue(true);
1139 fld.setRequired(q.value(NOTNULL_IDX).toInt() != 0);
1140 fld.setDefaultValue(q.value(DFLT_VALUE_IDX));
1141 ind.append(fld);
1142 }
1143 return ind;
1144}
1145
1146QSqlIndex QSymSQLDriver::primaryIndex(const QString &tblname) const
1147{
1148 if (!isOpen())
1149 return QSqlIndex();
1150
1151 QString table = tblname;
1152 if (isIdentifierEscaped(table, QSqlDriver::TableName))
1153 table = stripDelimiters(table, QSqlDriver::TableName);
1154
1155 QSqlQuery q(createResult());
1156 q.setForwardOnly(true);
1157 return qGetTableInfo(q, table, true);
1158}
1159
1160QSqlRecord QSymSQLDriver::record(const QString &tbl) const
1161{
1162 if (!isOpen())
1163 return QSqlRecord();
1164
1165 QString table = tbl;
1166 if (isIdentifierEscaped(table, QSqlDriver::TableName))
1167 table = stripDelimiters(table, QSqlDriver::TableName);
1168
1169 QSqlQuery q(createResult());
1170 q.setForwardOnly(true);
1171 return qGetTableInfo(q, table);
1172}
1173
1174QVariant QSymSQLDriver::handle() const
1175{
1176 return qVariantFromValue(d->access);
1177}
1178
1179QString QSymSQLDriver::escapeIdentifier(const QString &identifier, IdentifierType type) const
1180{
1181 Q_UNUSED(type);
1182 return _q_escapeIdentifier(identifier);
1183}
1184
1185QT_END_NAMESPACE
1186

Warning: That file was not part of the compilation database. It may have many parsing errors.