From fb09a8bfcfb9caeb9066946a7340f60d1d6f169c Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Tue, 17 Sep 2019 09:56:07 +0300 Subject: Android: rework assets support The new version fix QDirIterators and it lists all the files and dirs. Change-Id: I5a30eedb61ab2397a84365d00f308cda0c194de2 Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/plugins/platforms/android/androidjnimain.cpp | 11 +- src/plugins/platforms/android/androidjnimain.h | 1 + .../android/qandroidassetsfileenginehandler.cpp | 356 ++++++++++----------- .../android/qandroidassetsfileenginehandler.h | 8 - 4 files changed, 184 insertions(+), 192 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/android/androidjnimain.cpp b/src/plugins/platforms/android/androidjnimain.cpp index 27eb337aaa..13ea9468df 100644 --- a/src/plugins/platforms/android/androidjnimain.cpp +++ b/src/plugins/platforms/android/androidjnimain.cpp @@ -75,6 +75,7 @@ static jclass m_applicationClass = nullptr; static jobject m_classLoaderObject = nullptr; static jmethodID m_loadClassMethodID = nullptr; static AAssetManager *m_assetManager = nullptr; +static jobject m_assets = nullptr; static jobject m_resourcesObj = nullptr; static jobject m_activityObject = nullptr; static jmethodID m_createSurfaceMethodID = nullptr; @@ -439,6 +440,11 @@ namespace QtAndroid return block; } + jobject assets() + { + return m_assets; + } + } // namespace QtAndroid static jboolean startQtAndroidPlugin(JNIEnv *env, jobject /*object*/, jstring paramsString, jstring environmentString) @@ -588,6 +594,8 @@ static void terminateQt(JNIEnv *env, jclass /*clazz*/) env->DeleteGlobalRef(m_RGB_565_BitmapConfigValue); if (m_bitmapDrawableClass) env->DeleteGlobalRef(m_bitmapDrawableClass); + if (m_assets) + env->DeleteGlobalRef(m_assets); m_androidPlatformIntegration = nullptr; delete m_androidAssetsFileEngineHandler; m_androidAssetsFileEngineHandler = nullptr; @@ -840,7 +848,8 @@ static int registerNatives(JNIEnv *env) if (object) { FIND_AND_CHECK_CLASS("android/content/ContextWrapper"); GET_AND_CHECK_METHOD(methodID, clazz, "getAssets", "()Landroid/content/res/AssetManager;"); - m_assetManager = AAssetManager_fromJava(env, env->CallObjectMethod(object, methodID)); + m_assets = env->NewGlobalRef(env->CallObjectMethod(object, methodID)); + m_assetManager = AAssetManager_fromJava(env, m_assets); GET_AND_CHECK_METHOD(methodID, clazz, "getResources", "()Landroid/content/res/Resources;"); m_resourcesObj = env->NewGlobalRef(env->CallObjectMethod(object, methodID)); diff --git a/src/plugins/platforms/android/androidjnimain.h b/src/plugins/platforms/android/androidjnimain.h index 08f1d50fe3..17ae30a1be 100644 --- a/src/plugins/platforms/android/androidjnimain.h +++ b/src/plugins/platforms/android/androidjnimain.h @@ -82,6 +82,7 @@ namespace QtAndroid double scaledDensity(); double pixelDensity(); JavaVM *javaVM(); + jobject assets(); AAssetManager *assetManager(); jclass applicationClass(); jobject activity(); diff --git a/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp b/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp index e1dcebfa4c..26e72a480f 100644 --- a/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp +++ b/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp @@ -39,40 +39,139 @@ #include "qandroidassetsfileenginehandler.h" #include "androidjnimain.h" +#include #include #include +#include QT_BEGIN_NAMESPACE -typedef QVector FilesList; +static const QLatin1String assetsPrefix("assets:"); +const static int prefixSize = 7; -struct AndroidAssetDir +static inline QString cleanedAssetPath(QString file) { - AndroidAssetDir(AAssetDir* ad) + if (file.startsWith(assetsPrefix)) + file.remove(0, prefixSize); + file.replace(QLatin1String("//"), QLatin1String("/")); + if (file.startsWith(QLatin1Char('/'))) + file.remove(0, 1); + if (file.endsWith(QLatin1Char('/'))) + file.chop(1); + return file; +} + +static inline QString prefixedPath(QString path) +{ + path = assetsPrefix + QLatin1Char('/') + path; + path.replace(QLatin1String("//"), QLatin1String("/")); + return path; +} + +struct AssetItem { + enum class Type { + File, + Folder + }; + + AssetItem (const QString &rawName) + : name(rawName) + { + if (name.endsWith(QLatin1Char('/'))) { + type = Type::Folder; + name.chop(1); + } + } + Type type = Type::File; + QString name; +}; + +using AssetItemList = QVector; + +class FolderIterator : public AssetItemList +{ +public: + static QSharedPointer fromCache(const QString &path) { - if (ad) { - const char *fileName; - while ((fileName = AAssetDir_getNextFileName(ad))) - m_items.push_back(QString::fromUtf8(fileName)); - AAssetDir_close(ad); + QMutexLocker lock(&m_assetsCacheMutex); + QSharedPointer *folder = m_assetsCache.object(path); + if (!folder) { + folder = new QSharedPointer{new FolderIterator{path}}; + if (!m_assetsCache.insert(path, folder)) { + QSharedPointer res = *folder; + delete folder; + return res; + } } + return *folder; + } + + FolderIterator(const QString &path) + : m_path(path) + { + QJNIObjectPrivate files = QJNIObjectPrivate::callStaticObjectMethod(QtAndroid::applicationClass(), + "listAssetContent", + "(Landroid/content/res/AssetManager;Ljava/lang/String;)[Ljava/lang/String;", + QtAndroid::assets(), QJNIObjectPrivate::fromString(path).object()); + if (files.isValid()) { + QJNIEnvironmentPrivate env; + jobjectArray jFiles = static_cast(files.object()); + const jint nFiles = env->GetArrayLength(jFiles); + for (int i = 0; i < nFiles; ++i) + push_back({QJNIObjectPrivate(env->GetObjectArrayElement(jFiles, i)).toString()}); + } + m_path = assetsPrefix + QLatin1Char('/') + m_path + QLatin1Char('/'); + m_path.replace(QLatin1String("//"), QLatin1String("/")); + } + + QString currentFileName() const + { + if (m_index < 0 || m_index >= size()) + return {}; + return at(m_index).name; + } + QString currentFilePath() const + { + if (m_index < 0 || m_index >= size()) + return {}; + return m_path + at(m_index).name; + } + + bool hasNext() const + { + return !empty() && m_index + 1 < size(); + } + + std::optional> next() + { + if (!hasNext()) + return {}; + ++m_index; + return std::pair(currentFileName(), at(m_index)); } - FilesList m_items; + +private: + int m_index = -1; + QString m_path; + static QCache> m_assetsCache; + static QMutex m_assetsCacheMutex; }; +QCache> FolderIterator::m_assetsCache(std::max(50, qEnvironmentVariableIntValue("QT_ANDROID_MAX_ASSETS_CACHE_SIZE"))); +QMutex FolderIterator::m_assetsCacheMutex; + class AndroidAbstractFileEngineIterator: public QAbstractFileEngineIterator { public: AndroidAbstractFileEngineIterator(QDir::Filters filters, const QStringList &nameFilters, - QSharedPointer asset, const QString &path) : QAbstractFileEngineIterator(filters, nameFilters) { - m_items = asset->m_items; - m_index = -1; - m_path = path; + m_stack.push_back(FolderIterator::fromCache(cleanedAssetPath(path))); + if (m_stack.last()->empty()) + m_stack.pop_back(); } QFileInfo currentFileInfo() const override @@ -82,54 +181,59 @@ public: QString currentFileName() const override { - if (m_index < 0 || m_index >= m_items.size()) - return QString(); - QString fileName = m_items[m_index]; - if (fileName.endsWith(QLatin1Char('/'))) - fileName.chop(1); - return fileName; + if (!m_currentIterator) + return {}; + return m_currentIterator->currentFileName(); } virtual QString currentFilePath() const { - return m_path + currentFileName(); + if (!m_currentIterator) + return {}; + return m_currentIterator->currentFilePath(); } bool hasNext() const override { - return m_items.size() && (m_index < m_items.size() - 1); + if (m_stack.empty()) + return false; + if (!m_stack.last()->hasNext()) { + m_stack.pop_back(); + return hasNext(); + } + return true; } QString next() override { - if (!hasNext()) - return QString(); - m_index++; - return currentFileName(); + if (m_stack.empty()) { + m_currentIterator.reset(); + return {}; + } + m_currentIterator = m_stack.last(); + auto res = m_currentIterator->next(); + if (!res) + return {}; + if (res->second.type == AssetItem::Type::Folder) { + m_stack.push_back(FolderIterator::fromCache(cleanedAssetPath(currentFilePath()))); + if (m_stack.last()->empty()) + m_stack.pop_back(); + } + return res->first; } private: - QString m_path; - FilesList m_items; - int m_index; + mutable QSharedPointer m_currentIterator; + mutable QVector> m_stack; }; class AndroidAbstractFileEngine: public QAbstractFileEngine { public: - explicit AndroidAbstractFileEngine(AAsset *asset, const QString &fileName) - { - m_assetFile = asset; - m_fileName = fileName; - } - - explicit AndroidAbstractFileEngine(QSharedPointer asset, const QString &fileName) + explicit AndroidAbstractFileEngine(AAssetManager *assetManager, const QString &fileName) + : m_assetManager(assetManager) { - m_assetFile = 0; - m_assetDir = asset; - m_fileName = fileName; - if (!m_fileName.endsWith(QLatin1Char('/'))) - m_fileName += QLatin1Char('/'); + setFileName(fileName); } ~AndroidAbstractFileEngine() @@ -139,7 +243,11 @@ public: bool open(QIODevice::OpenMode openMode) override { - return m_assetFile != 0 && (openMode & QIODevice::WriteOnly) == 0; + if (m_isFolder || (openMode & QIODevice::WriteOnly)) + return false; + close(); + m_assetFile = AAssetManager_open(m_assetManager, m_fileName.toUtf8(), AASSET_MODE_BUFFER); + return m_assetFile; } bool close() override @@ -200,7 +308,7 @@ public: FileFlags flags(ReadOwnerPerm|ReadUserPerm|ReadGroupPerm|ReadOtherPerm|ExistsFlag); if (m_assetFile) flags |= FileType; - if (!m_assetDir.isNull()) + else if (m_isFolder) flags |= DirectoryType; return type & flags; @@ -213,19 +321,19 @@ public: case DefaultName: case AbsoluteName: case CanonicalName: - return m_fileName; + return prefixedPath(m_fileName); case BaseName: if ((pos = m_fileName.lastIndexOf(QChar(QLatin1Char('/')))) != -1) - return m_fileName.mid(pos); + return prefixedPath(m_fileName.mid(pos)); else - return m_fileName; + return prefixedPath(m_fileName); case PathName: case AbsolutePathName: case CanonicalPathName: if ((pos = m_fileName.lastIndexOf(QChar(QLatin1Char('/')))) != -1) - return m_fileName.left(pos); + return prefixedPath(m_fileName.left(pos)); else - return m_fileName; + return prefixedPath(m_fileName); default: return QString(); } @@ -233,164 +341,46 @@ public: void setFileName(const QString &file) override { - if (file == m_fileName) - return; - - m_fileName = file; - if (!m_fileName.endsWith(QLatin1Char('/'))) - m_fileName += QLatin1Char('/'); - close(); + m_fileName = cleanedAssetPath(file); + m_isFolder = !open(QIODevice::ReadOnly) && !FolderIterator::fromCache(m_fileName)->empty(); } Iterator *beginEntryList(QDir::Filters filters, const QStringList &filterNames) override { - if (!m_assetDir.isNull()) - return new AndroidAbstractFileEngineIterator(filters, filterNames, m_assetDir, m_fileName); - return 0; + if (m_isFolder) + return new AndroidAbstractFileEngineIterator(filters, filterNames, m_fileName); + return nullptr; } private: - AAsset *m_assetFile; - QSharedPointer m_assetDir; + AAsset *m_assetFile = nullptr; + AAssetManager *m_assetManager; QString m_fileName; + bool m_isFolder; }; AndroidAssetsFileEngineHandler::AndroidAssetsFileEngineHandler() - : m_assetsCache(std::max(5, qEnvironmentVariableIntValue("QT_ANDROID_MAX_ASSETS_CACHE_SIZE"))) - , m_hasPrepopulatedCache(false) - , m_hasTriedPrepopulatingCache(false) { m_assetManager = QtAndroid::assetManager(); } -AndroidAssetsFileEngineHandler::~AndroidAssetsFileEngineHandler() -{ -} - -void AndroidAssetsFileEngineHandler::prepopulateCache() const -{ - Q_ASSERT(!m_hasTriedPrepopulatingCache); - m_hasTriedPrepopulatingCache = true; - - Q_ASSERT(m_assetsCache.isEmpty()); - - // Failsafe: Don't read cache files that are larger than 1MB - static qint64 maxPrepopulatedCacheSize = qMax(1024LL * 1024LL, - qgetenv("QT_ANDROID_MAX_PREPOPULATED_ASSETS_CACHE_SIZE").toLongLong()); - - const char *fileName = "--Added-by-androiddeployqt--/qt_cache_pregenerated_file_list"; - AAsset *asset = AAssetManager_open(m_assetManager, fileName, AASSET_MODE_BUFFER); - if (asset) { - m_hasPrepopulatedCache = true; - AndroidAbstractFileEngine fileEngine(asset, QString::fromLatin1(fileName)); - if (fileEngine.open(QIODevice::ReadOnly)) { - qint64 size = fileEngine.size(); - - if (size <= maxPrepopulatedCacheSize) { - QByteArray bytes(size, Qt::Uninitialized); - qint64 read = fileEngine.read(bytes.data(), size); - if (read != size) { - qWarning("Failed to read prepopulated cache"); - return; - } - - QDataStream stream(&bytes, QIODevice::ReadOnly); - stream.setVersion(QDataStream::Qt_5_3); - if (stream.status() != QDataStream::Ok) { - qWarning("Failed to read prepopulated cache"); - return; - } - - while (!stream.atEnd()) { - QString directoryName; - stream >> directoryName; - - int fileCount; - stream >> fileCount; - - QVector fileList; - fileList.reserve(fileCount); - while (fileCount--) { - QString fileName; - stream >> fileName; - fileList.append(fileName); - } - - QSharedPointer *aad = new QSharedPointer(new AndroidAssetDir(0)); - (*aad)->m_items = fileList; - - // Cost = 0, because we should always cache everything if there's a prepopulated cache - QByteArray key = directoryName != QLatin1String("/") - ? QByteArray("assets:/") + directoryName.toUtf8() - : QByteArray("assets:"); - - bool ok = m_assetsCache.insert(key, aad, 0); - if (!ok) - qWarning("Failed to insert in cache: %s", qPrintable(directoryName)); - } - } else { - qWarning("Prepopulated cache is too large to read.\n" - "Use environment variable QT_ANDROID_MAX_PREPOPULATED_ASSETS_CACHE_SIZE to adjust size."); - } - } - } -} - QAbstractFileEngine * AndroidAssetsFileEngineHandler::create(const QString &fileName) const { if (fileName.isEmpty()) - return 0; + return nullptr; - static QLatin1String assetsPrefix("assets:"); if (!fileName.startsWith(assetsPrefix)) - return 0; - - static int prefixSize = assetsPrefix.size() + 1; - - QByteArray path; - if (!fileName.endsWith(QLatin1Char('/'))) { - path = fileName.toUtf8(); - if (path.size() > prefixSize) { - AAsset *asset = AAssetManager_open(m_assetManager, - path.constData() + prefixSize, - AASSET_MODE_BUFFER); - if (asset) - return new AndroidAbstractFileEngine(asset, fileName); - } - } - - if (!path.size()) - path = fileName.left(fileName.length() - 1).toUtf8(); - - - m_assetsCacheMutext.lock(); - if (!m_hasTriedPrepopulatingCache) - prepopulateCache(); - - QSharedPointer *aad = m_assetsCache.object(path); - m_assetsCacheMutext.unlock(); - if (!aad) { - if (!m_hasPrepopulatedCache && path.size() > prefixSize) { - AAssetDir *assetDir = AAssetManager_openDir(m_assetManager, path.constData() + prefixSize); - if (assetDir) { - if (AAssetDir_getNextFileName(assetDir)) { - AAssetDir_rewind(assetDir); - aad = new QSharedPointer(new AndroidAssetDir(assetDir)); - m_assetsCacheMutext.lock(); - m_assetsCache.insert(path, aad); - m_assetsCacheMutext.unlock(); - return new AndroidAbstractFileEngine(*aad, fileName); - } else { - AAssetDir_close(assetDir); - } - } - } - } else { - return new AndroidAbstractFileEngine(*aad, fileName); - } - return 0; + return nullptr; + + QString path = fileName.mid(prefixSize); + path.replace(QLatin1String("//"), QLatin1String("/")); + if (path.startsWith(QLatin1Char('/'))) + path.remove(0, 1); + if (path.endsWith(QLatin1Char('/'))) + path.chop(1); + return new AndroidAbstractFileEngine(m_assetManager, path); } QT_END_NAMESPACE diff --git a/src/plugins/platforms/android/qandroidassetsfileenginehandler.h b/src/plugins/platforms/android/qandroidassetsfileenginehandler.h index f99dc9a11a..51cc5b07a8 100644 --- a/src/plugins/platforms/android/qandroidassetsfileenginehandler.h +++ b/src/plugins/platforms/android/qandroidassetsfileenginehandler.h @@ -49,22 +49,14 @@ QT_BEGIN_NAMESPACE -struct AndroidAssetDir; class AndroidAssetsFileEngineHandler: public QAbstractFileEngineHandler { public: AndroidAssetsFileEngineHandler(); - virtual ~AndroidAssetsFileEngineHandler(); QAbstractFileEngine *create(const QString &fileName) const override; private: - void prepopulateCache() const; - AAssetManager *m_assetManager; - mutable QCache> m_assetsCache; - mutable QMutex m_assetsCacheMutext; - mutable bool m_hasPrepopulatedCache; - mutable bool m_hasTriedPrepopulatingCache; }; QT_END_NAMESPACE -- cgit v1.2.3 From c8b07f7da3ff55f92378a1e98522f318bbc43077 Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Thu, 15 Aug 2019 08:25:30 +0300 Subject: Android: Do not extract QML assets data Instead to extract the assets QML file, we create a .rcc bundle file which is register by android qpa plugin before the it invokes the main function. Thsi way we avoid extracting the QML files from assets as they can be accessed directly from resources. [ChangeLog][Android] Instead of bundling QML resources in assets and extracting them on first start, Qt now creates an .rcc file and register it before invoking the main function. Change-Id: Icb2fda79d82c5af102cc9a0276ff26bb0d1599e8 Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/plugins/platforms/android/androidjnimain.cpp | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/plugins') diff --git a/src/plugins/platforms/android/androidjnimain.cpp b/src/plugins/platforms/android/androidjnimain.cpp index 13ea9468df..fd2644717e 100644 --- a/src/plugins/platforms/android/androidjnimain.cpp +++ b/src/plugins/platforms/android/androidjnimain.cpp @@ -60,6 +60,7 @@ #include "qandroideventdispatcher.h" #include +#include #include #include #include @@ -525,6 +526,10 @@ static jboolean startQtApplication(JNIEnv */*env*/, jclass /*clazz*/) vm->AttachCurrentThread(&env, &args); } + // Register resources if they are available + if (QFile{QStringLiteral("assets:/android_rcc_bundle.rcc")}.exists()) + QResource::registerResource(QStringLiteral("assets:/android_rcc_bundle.rcc")); + QVarLengthArray params(m_applicationParams.size()); for (int i = 0; i < m_applicationParams.size(); i++) params[i] = static_cast(m_applicationParams[i].constData()); -- cgit v1.2.3 From c9478e90ff7abef1f019805f0846e651c484ebc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Tue, 24 Sep 2019 17:25:57 +0200 Subject: Export lcEventDispatcher in private namespace MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The category is used outside of QtCore, and needs to be exported for shared library builds. Change-Id: I9bba477d37b823146eaec4e1e53197651f09c013 Reviewed-by: Timur Pocheptsov Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/ios/qioseventdispatcher.mm | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/plugins') diff --git a/src/plugins/platforms/ios/qioseventdispatcher.mm b/src/plugins/platforms/ios/qioseventdispatcher.mm index 776343c5aa..c5856051de 100644 --- a/src/plugins/platforms/ios/qioseventdispatcher.mm +++ b/src/plugins/platforms/ios/qioseventdispatcher.mm @@ -211,6 +211,8 @@ namespace } logActivity; } +using namespace QT_PREPEND_NAMESPACE(QtPrivate); + extern "C" int qt_main_wrapper(int argc, char *argv[]) { @autoreleasepool { -- cgit v1.2.3 From dabc33bf9543e552d8627eda4977e82d340e9bcf Mon Sep 17 00:00:00 2001 From: Christian Ehrlicher Date: Mon, 30 Sep 2019 22:25:33 +0200 Subject: QPainter: don't print deprecated warnings for HighQualityAntialiasing Add pragmas to not print warnings about the usage of the deprecated warnings inside QtCore. Change-Id: I2cd9f111cdf13cddff527ab3bac7fa80417d1445 Reviewed-by: Allan Sandfeld Jensen --- src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/plugins') diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp index d7aba66b2f..03be44e095 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp @@ -941,6 +941,8 @@ public: { Q_Q(QWindowsDirect2DPaintEngine); +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED // Default path (no optimization) if (!(path.shape() == QVectorPath::LinesHint || path.shape() == QVectorPath::PolygonHint) || !pen.dashBrush @@ -948,6 +950,7 @@ public: || q->state()->renderHints.testFlag(QPainter::HighQualityAntialiasing) #endif || q->state()->renderHints.testFlag(QPainter::Antialiasing)) { +QT_WARNING_POP ComPtr geometry = vectorPathToID2D1PathGeometry(path); if (!geometry) { qWarning("%s: Could not convert path to d2d geometry", __FUNCTION__); -- cgit v1.2.3 From a978d21dac57697ae9557b99062bc804b005b9d4 Mon Sep 17 00:00:00 2001 From: Christian Ehrlicher Date: Sun, 29 Sep 2019 21:28:52 +0200 Subject: PSQL: don't recreate QSqlField in loop in QPSQLResult::record() Move out the QSqlField variable out of the loop to avoid useless (de)allocations of QSqlField. Change-Id: I2c9e4c84f75e994d5eb1438839d502f6da531841 Reviewed-by: Robert Szefner Reviewed-by: Andy Shaw --- src/plugins/sqldrivers/psql/qsql_psql.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/plugins') diff --git a/src/plugins/sqldrivers/psql/qsql_psql.cpp b/src/plugins/sqldrivers/psql/qsql_psql.cpp index 28be7bdc38..3803f05b9f 100644 --- a/src/plugins/sqldrivers/psql/qsql_psql.cpp +++ b/src/plugins/sqldrivers/psql/qsql_psql.cpp @@ -812,8 +812,8 @@ QSqlRecord QPSQLResult::record() const return info; int count = PQnfields(d->result); + QSqlField f; for (int i = 0; i < count; ++i) { - QSqlField f; if (d->drv_d_func()->isUtf8) f.setName(QString::fromUtf8(PQfname(d->result, i))); else @@ -833,6 +833,8 @@ QSqlRecord QPSQLResult::record() const } } f.setTableName(tableName); + } else { + f.setTableName(QString()); } int ptype = PQftype(d->result, i); f.setType(qDecodePSQLType(ptype)); -- cgit v1.2.3