<commit_before>/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QStringList>
#include <QtQml/qqmlextensionplugin.h>
#include <QtQml/qqml.h>
#include <private/qqmlengine_p.h>
#include <QDebug>
#include <private/qv8engine_p.h>
#include <QtSql/qsqldatabase.h>
#include <QtSql/qsqlquery.h>
#include <QtSql/qsqlerror.h>
#include <QtSql/qsqlrecord.h>
#include <QtSql/qsqlfield.h>
#include <QtCore/qstandardpaths.h>
#include <QtCore/qstack.h>
#include <QtCore/qcryptographichash.h>
#include <QtCore/qsettings.h>
#include <QtCore/qdir.h>
#include <private/qv4sqlerrors_p.h>
#include <private/qv4engine_p.h>
#include <private/qv4object_p.h>
#include <private/qv4functionobject_p.h>
#include <private/qv4objectproto_p.h>
#include <private/qv4scopedvalue_p.h>

using namespace QV4;

#define V4THROW_SQL(error, desc) { \
    QV4::Scoped<String> v(scope, ctx->engine->newString(desc)); \
    QV4::Scoped<Object> ex(scope, ctx->engine->newErrorObject(v)); \
    ex->put(QV4::ScopedString(scope, ctx->engine->newIdentifier(QStringLiteral("code"))), QV4::ScopedValue(scope, Primitive::fromInt32(error))); \
    ctx->throwError(ex); \
}

#define V4THROW_REFERENCE(string) { \
    QV4::Scoped<String> v(scope, ctx->engine->newString(string)); \
    ctx->throwReferenceError(v); \
}


class QQmlSqlDatabaseData : public QV8Engine::Deletable
{
public:
    QQmlSqlDatabaseData(QV8Engine *engine);
    ~QQmlSqlDatabaseData();

    PersistentValue databaseProto;
    PersistentValue queryProto;
    PersistentValue rowsProto;
};

V8_DEFINE_EXTENSION(QQmlSqlDatabaseData, databaseData)

class QQmlSqlDatabaseWrapper : public Object
{
    Q_MANAGED

public:
    enum Type { Database, Query, Rows };
    QQmlSqlDatabaseWrapper(QV8Engine *e)
        : Object(QV8Engine::getV4(e)), type(Database), inTransaction(false), readonly(false), forwardOnly(false)
    {
        vtbl = &static_vtbl;
    }

    ~QQmlSqlDatabaseWrapper() {
    }

    static ReturnedValue getIndexed(Managed *m, uint index, bool *hasProperty);
    static void destroy(Managed *that) {
        static_cast<QQmlSqlDatabaseWrapper *>(that)->~QQmlSqlDatabaseWrapper();
    }

    Type type;
    QSqlDatabase database;

    QString version; // type == Database

    bool inTransaction; // type == Query
    bool readonly;   // type == Query

    QSqlQuery sqlQuery; // type == Rows
    bool forwardOnly; // type == Rows
};

DEFINE_MANAGED_VTABLE(QQmlSqlDatabaseWrapper);

static ReturnedValue qmlsqldatabase_version(SimpleCallContext *ctx)
{
    QV4::Scope scope(ctx);
    QV4::Scoped<QQmlSqlDatabaseWrapper> r(scope, ctx->callData->thisObject.as<QQmlSqlDatabaseWrapper>());
    if (!r || r->type != QQmlSqlDatabaseWrapper::Database)
        V4THROW_REFERENCE("Not a SQLDatabase object");

    return Encode(ctx->engine->newString(r->version));
}

static ReturnedValue qmlsqldatabase_rows_length(SimpleCallContext *ctx)
{
    QV4::Scope scope(ctx);
    QV4::Scoped<QQmlSqlDatabaseWrapper> r(scope, ctx->callData->thisObject.as<QQmlSqlDatabaseWrapper>());
    if (!r || r->type != QQmlSqlDatabaseWrapper::Rows)
        V4THROW_REFERENCE("Not a SQLDatabase::Rows object");

    int s = r->sqlQuery.size();
    if (s < 0) {
        // Inefficient
        if (r->sqlQuery.last()) {
            s = r->sqlQuery.at() + 1;
        } else {
            s = 0;
        }
    }
    return Encode(s);
}

static ReturnedValue qmlsqldatabase_rows_forwardOnly(SimpleCallContext *ctx)
{
    QV4::Scope scope(ctx);
    QV4::Scoped<QQmlSqlDatabaseWrapper> r(scope, ctx->callData->thisObject.as<QQmlSqlDatabaseWrapper>());
    if (!r || r->type != QQmlSqlDatabaseWrapper::Rows)
        V4THROW_REFERENCE("Not a SQLDatabase::Rows object");
    return Encode(r->sqlQuery.isForwardOnly());
}

static ReturnedValue qmlsqldatabase_rows_setForwardOnly(SimpleCallContext *ctx)
{
    QV4::Scope scope(ctx);
    QV4::Scoped<QQmlSqlDatabaseWrapper> r(scope, ctx->callData->thisObject.as<QQmlSqlDatabaseWrapper>());
    if (!r || r->type != QQmlSqlDatabaseWrapper::Rows)
        V4THROW_REFERENCE("Not a SQLDatabase::Rows object");
    if (ctx->callData->argc < 1)
        ctx->throwTypeError();

    r->sqlQuery.setForwardOnly(ctx->callData->args[0].toBoolean());
    return Encode::undefined();
}

QQmlSqlDatabaseData::~QQmlSqlDatabaseData()
{
}

static QString qmlsqldatabase_databasesPath(QV8Engine *engine)
{
    return engine->engine()->offlineStoragePath() +
           QDir::separator() + QLatin1String("Databases");
}

static void qmlsqldatabase_initDatabasesPath(QV8Engine *engine)
{
    QDir().mkpath(qmlsqldatabase_databasesPath(engine));
}

static QString qmlsqldatabase_databaseFile(const QString& connectionName, QV8Engine *engine)
{
    return qmlsqldatabase_databasesPath(engine) + QDir::separator() + connectionName;
}

static ReturnedValue qmlsqldatabase_rows_index(QV4::Referenced<QQmlSqlDatabaseWrapper> r, ExecutionEngine *v4, quint32 index, bool *hasProperty = 0)
{
    Scope scope(v4);
    QV8Engine *v8 = v4->v8Engine;

    if (r->sqlQuery.at() == (int)index || r->sqlQuery.seek(index)) {
        QSqlRecord record = r->sqlQuery.record();
        // XXX optimize
        Scoped<Object> row(scope, v4->newObject());
        for (int ii = 0; ii < record.count(); ++ii) {
            QVariant v = record.value(ii);
            ScopedString s(scope, v4->newIdentifier(record.fieldName(ii)));
            ScopedValue val(scope, v.isNull() ? Encode::null() : v8->fromVariant(v));
            row->put(s, val);
        }
        if (hasProperty)
            *hasProperty = true;
        return row.asReturnedValue();
    } else {<commit_msg>Make LocalStorage more verbose<commit_after>/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QStringList>
#include <QtQml/qqmlextensionplugin.h>
#include <QtQml/qqml.h>
#include <private/qqmlengine_p.h>
#include <QDebug>
#include <private/qv8engine_p.h>
#include <QtSql/qsqldatabase.h>
#include <QtSql/qsqlquery.h>
#include <QtSql/qsqlerror.h>
#include <QtSql/qsqlrecord.h>
#include <QtSql/qsqlfield.h>
#include <QtCore/qstandardpaths.h>
#include <QtCore/qstack.h>
#include <QtCore/qcryptographichash.h>
#include <QtCore/qsettings.h>
#include <QtCore/qdir.h>
#include <private/qv4sqlerrors_p.h>
#include <private/qv4engine_p.h>
#include <private/qv4object_p.h>
#include <private/qv4functionobject_p.h>
#include <private/qv4objectproto_p.h>
#include <private/qv4scopedvalue_p.h>

using namespace QV4;

#define V4THROW_SQL(error, desc) { \
    QV4::Scoped<String> v(scope, ctx->engine->newString(desc)); \
    QV4::Scoped<Object> ex(scope, ctx->engine->newErrorObject(v)); \
    ex->put(QV4::ScopedString(scope, ctx->engine->newIdentifier(QStringLiteral("code"))), QV4::ScopedValue(scope, Primitive::fromInt32(error))); \
    ctx->throwError(ex); \
}

#define V4THROW_REFERENCE(string) { \
    QV4::Scoped<String> v(scope, ctx->engine->newString(string)); \
    ctx->throwReferenceError(v); \
}


class QQmlSqlDatabaseData : public QV8Engine::Deletable
{
public:
    QQmlSqlDatabaseData(QV8Engine *engine);
    ~QQmlSqlDatabaseData();

    PersistentValue databaseProto;
    PersistentValue queryProto;
    PersistentValue rowsProto;
};

V8_DEFINE_EXTENSION(QQmlSqlDatabaseData, databaseData)

class QQmlSqlDatabaseWrapper : public Object
{
    Q_MANAGED

public:
    enum Type { Database, Query, Rows };
    QQmlSqlDatabaseWrapper(QV8Engine *e)
        : Object(QV8Engine::getV4(e)), type(Database), inTransaction(false), readonly(false), forwardOnly(false)
    {
        vtbl = &static_vtbl;
    }

    ~QQmlSqlDatabaseWrapper() {
    }

    static ReturnedValue getIndexed(Managed *m, uint index, bool *hasProperty);
    static void destroy(Managed *that) {
        static_cast<QQmlSqlDatabaseWrapper *>(that)->~QQmlSqlDatabaseWrapper();
    }

    Type type;
    QSqlDatabase database;

    QString version; // type == Database

    bool inTransaction; // type == Query
    bool readonly;   // type == Query

    QSqlQuery sqlQuery; // type == Rows
    bool forwardOnly; // type == Rows
};

DEFINE_MANAGED_VTABLE(QQmlSqlDatabaseWrapper);

static ReturnedValue qmlsqldatabase_version(SimpleCallContext *ctx)
{
    QV4::Scope scope(ctx);
    QV4::Scoped<QQmlSqlDatabaseWrapper> r(scope, ctx->callData->thisObject.as<QQmlSqlDatabaseWrapper>());
    if (!r || r->type != QQmlSqlDatabaseWrapper::Database)
        V4THROW_REFERENCE("Not a SQLDatabase object");

    return Encode(ctx->engine->newString(r->version));
}

static ReturnedValue qmlsqldatabase_rows_length(SimpleCallContext *ctx)
{
    QV4::Scope scope(ctx);
    QV4::Scoped<QQmlSqlDatabaseWrapper> r(scope, ctx->callData->thisObject.as<QQmlSqlDatabaseWrapper>());
    if (!r || r->type != QQmlSqlDatabaseWrapper::Rows)
        V4THROW_REFERENCE("Not a SQLDatabase::Rows object");

    int s = r->sqlQuery.size();
    if (s < 0) {
        // Inefficient
        if (r->sqlQuery.last()) {
            s = r->sqlQuery.at() + 1;
        } else {
            s = 0;
        }
    }
    return Encode(s);
}

static ReturnedValue qmlsqldatabase_rows_forwardOnly(SimpleCallContext *ctx)
{
    QV4::Scope scope(ctx);
    QV4::Scoped<QQmlSqlDatabaseWrapper> r(scope, ctx->callData->thisObject.as<QQmlSqlDatabaseWrapper>());
    if (!r || r->type != QQmlSqlDatabaseWrapper::Rows)
        V4THROW_REFERENCE("Not a SQLDatabase::Rows object");
    return Encode(r->sqlQuery.isForwardOnly());
}

static ReturnedValue qmlsqldatabase_rows_setForwardOnly(SimpleCallContext *ctx)
{
    QV4::Scope scope(ctx);
    QV4::Scoped<QQmlSqlDatabaseWrapper> r(scope, ctx->callData->thisObject.as<QQmlSqlDatabaseWrapper>());
    if (!r || r->type != QQmlSqlDatabaseWrapper::Rows)
        V4THROW_REFERENCE("Not a SQLDatabase::Rows object");
    if (ctx->callData->argc < 1)
        ctx->throwTypeError();

    r->sqlQuery.setForwardOnly(ctx->callData->args[0].toBoolean());
    return Encode::undefined();
}

QQmlSqlDatabaseData::~QQmlSqlDatabaseData()
{
}

static QString qmlsqldatabase_databasesPath(QV8Engine *engine)
{
    return engine->engine()->offlineStoragePath() +
           QDir::separator() + QLatin1String("Databases");
}

static void qmlsqldatabase_initDatabasesPath(QV8Engine *engine)
{
    QString databasesPath = qmlsqldatabase_databasesPath(engine);
    if (!QDir().mkpath(databasesPath))
        qWarning() << "LocalStorage: can't create path - " << databasesPath;
}

static QString qmlsqldatabase_databaseFile(const QString& connectionName, QV8Engine *engine)
{
    return qmlsqldatabase_databasesPath(engine) + QDir::separator() + connectionName;
}

static ReturnedValue qmlsqldatabase_rows_index(QV4::Referenced<QQmlSqlDatabaseWrapper> r, ExecutionEngine *v4, quint32 index, bool *hasProperty = 0)
{
    Scope scope(v4);
    QV8Engine *v8 = v4->v8Engine;

    if (r->sqlQuery.at() == (int)index || r->sqlQuery.seek(index)) {
        QSqlRecord record = r->sqlQuery.record();
        // XXX optimize
        Scoped<Object> row(scope, v4->newObject());
        for (int ii = 0; ii < record.count(); ++ii) {
            QVariant v = record.value(ii);
            ScopedString s(scope, v4->newIdentifier(record.fieldName(ii)));
            ScopedValue val(scope, v.isNull() ? Encode::null() : v8->fromVariant(v));
            row->put(s, val);
        }
        if (hasProperty)
            *hasProperty = true;
        return row.asReturnedValue();
    } else {
{'fraction_non_alphanumeric': 0.14457512884894938, 'fraction_numerical': 0.009779304876437162, 'mean_word_length': 4.401498929336189, 'pattern_counts': {'":': 0, '<': 85, '<?xml version=': 0, '>': 169, 'https://': 0, 'lorem ipsum': 0, 'www.': 6, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1194611', 'n_tokens_mistral': 4931, 'n_tokens_neox': 4773, 'n_words': 1127}