[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    [kdb] src: Improve KDb::cstringToVariant()
From:       Jaroslaw Staniek <staniek () kde ! org>
Date:       2015-06-30 22:09:07
Message-ID: E1ZA3iF-00042Q-Rj () scm ! kde ! org
[Download RAW message or body]

Git commit 3eed88bb098e3c42760ea7b0c4e364126e48d3c8 by Jaroslaw Staniek.
Committed on 30/06/2015 at 16:51.
Pushed by staniek into branch 'master'.

Improve KDb::cstringToVariant()

- add signedness support for integers
- extend the docs
- add more sanity checks
- fail on unsupported types (Null, etc.) or if data is 0
- set result in the ok OUT arg
- much better convert integers (check limits)

+Add KDb::iif helper

M  +57   -15   src/KDb.cpp
M  +25   -3    src/KDb.h

http://commits.kde.org/kdb/3eed88bb098e3c42760ea7b0c4e364126e48d3c8

diff --git a/src/KDb.cpp b/src/KDb.cpp
index cb716cb..6338880 100644
--- a/src/KDb.cpp
+++ b/src/KDb.cpp
@@ -43,6 +43,7 @@
 #include <QApplication>
 #include <QDir>
 #include <QProcess>
+#include <QtDebug>
 
 #include <memory>
 
@@ -1552,30 +1553,71 @@ QString KDb::defaultFileBasedDriverId()
     return QLatin1String("org.kde.kdb.sqlite");
 }
 
-/*! @return QVariant value converted from null-terminated @a data string.
- In case of BLOB type, @a data is not null terminated, so passing length is needed. */
-QVariant KDb::cstringToVariant(const char* data, KDbField* f, int length)
+// Try to convert from string to type T
+template <typename T>
+QVariant convert(T (QString::*ConvertToT)(bool*,int) const, const char *data, int size,
+                 qlonglong minValue, qlonglong maxValue, bool *ok)
 {
-    if (!data)
+    T v = (QString::fromLatin1(data, size).*ConvertToT)(ok, 10);
+    if (*ok) {
+        *ok = minValue <= v && v <= maxValue;
+    }
+    return KDb::iif(*ok, QVariant(v));
+}
+
+QVariant KDb::cstringToVariant(const char* data, KDbField::Type type, bool *ok, int length,
+                               KDb::Signedness signedness)
+{
+    bool tempOk;
+    bool *thisOk = ok ? ok : &tempOk;
+    if (!data || type > KDbField::LastType) {
+        *thisOk = false;
         return QVariant();
+    }
     // from most to least frequently used types:
 
-    if (!f || f->isTextType())
+    if (KDbField::isTextType(type)) {
+        *thisOk = true;
+        //! @todo use KDbDriverBehaviour::TEXT_TYPE_MAX_LENGTH for Text type?
         return QString::fromUtf8(data, length);
-    if (f->isIntegerType()) {
-        if (f->type() == KDbField::BigInteger)
-            return QVariant(QString::fromLatin1(data, length).toLongLong());
-        return QVariant(QString::fromLatin1(data, length).toInt());
-    }
-    if (f->isFPNumericType())
-        return QString::fromLatin1(data, length).toDouble();
-    if (f->type() == KDbField::BLOB)
-        return QByteArray(data, length);
+    }
+    if (KDbField::isIntegerType(type)) {
+        qlonglong minValue, maxValue;
+        const bool isUnsigned = signedness == KDb::Unsigned;
+        KDb::getLimitsForFieldType(type, &minValue, &maxValue, signedness);
+        switch (type) {
+        case KDbField::Byte: // Byte here too, minValue/maxValue will take care of limits
+        case KDbField::ShortInteger:
+            return isUnsigned ?
+                convert(&QString::toUShort, data, length, minValue, maxValue, thisOk)
+                : convert(&QString::toShort, data, length, minValue, maxValue, thisOk);
+        case KDbField::Integer:
+            return isUnsigned ?
+                convert(&QString::toUInt, data, length, minValue, maxValue, thisOk)
+                : convert(&QString::toInt, data, length, minValue, maxValue, thisOk);
+        case KDbField::BigInteger:
+            return isUnsigned ?
+                convert(&QString::toULongLong, data, length, minValue, maxValue, thisOk)
+                : convert(&QString::toLongLong, data, length, minValue, maxValue, thisOk);
+        default:
+            qFatal("Unsupported integer type %d", type);
+        }
+    }
+    if (KDbField::isFPNumericType(type)) {
+        return KDb::iif(*thisOk, QVariant(QString::fromLatin1(data, length).toDouble(thisOk)));
+    }
+    if (type == KDbField::BLOB) {
+        *thisOk = length >= 0;
+        return *thisOk ? QVariant(QByteArray(data, length)) : QVariant();
+    }
     // the default
 //! @todo date/time?
     QVariant result(QString::fromUtf8(data, length));
-    if (!result.convert(KDbField::variantType(f->type())))
+    if (!result.convert(KDbField::variantType(type))) {
+        *thisOk = false;
         return QVariant();
+    }
+    *thisOk = true;
     return result;
 }
 
diff --git a/src/KDb.h b/src/KDb.h
index 7835464..f064247 100644
--- a/src/KDb.h
+++ b/src/KDb.h
@@ -418,9 +418,21 @@ KDB_EXPORT void getLimitsForFieldType(KDbField::Type type, qlonglong *minValue,
  of 100 * 100 exceeds the range of Byte. */
 KDB_EXPORT KDbField::Type maximumForIntegerFieldTypes(KDbField::Type t1, KDbField::Type t2);
 
-/*! @return QVariant value converted from null-terminated @a data string.
- In case of BLOB type, @a data is not null terminated, so passing length is needed. */
-KDB_EXPORT QVariant cstringToVariant(const char* data, KDbField* f, int length = -1);
+//! @return QVariant value converted from a @a data string
+/*! Conversion is based on the information about type @a type.
+ @a type has to be an element from KDbField::Type, not greater than KDbField::LastType.
+ For unsupported type this function fails. @a length value controls number of characters
+ used in the conversion. It is optional value for all cases but for the BLOB type because
+ for it @a data is not null-terminated so the length cannot be measured.
+ The value of @a signedness controls the conversion in case of integer types; numbers can be
+ limited to unsigned or not.
+ If @a ok is not 0 *ok is set to false on failure and to true on success. On failure a null
+ QVariant is returned. The function fails if @a data is 0.
+ For rules of conversion to the boolean type see the documentation of @ref QVariant::toBool(),
+ QVariant::toDate() for date type, QVariant::toDateTime() for date+time type,
+ QVariant::toTime() for time type. */
+KDB_EXPORT QVariant cstringToVariant(const char* data, KDbField::Type type, bool *ok, int length = -1,
+                                     KDb::Signedness signedness = KDb::Signed);
 
 /*! @return default file-based driver MIME type
  (typically something like "application/x-kexiproject-sqlite") */
@@ -489,6 +501,16 @@ T iifNotEmpty(const T &string, const QByteArray &stringIfEmpty)
     return iifNotEmpty(string, QString(stringIfEmpty));
 }
 
+//! @return @a value if @a ok is true, else returns default value T().
+template<typename T>
+T iif(bool ok, const T &value)
+{
+    if (ok) {
+        return value;
+    }
+    return T();
+}
+
 /*! @return a list of paths that KDb will search when dynamically loading libraries (plugins)
  This is basicaly list of directories returned QCoreApplication::libraryPaths() that have readable
  subdirectory "kdb".

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic