static QScriptValue qmlsqldatabase_change_version(QScriptContext *context, QScriptEngine *engine)
{
    if (context->argumentCount() < 2)
        return engine->undefinedValue();

    QSqlDatabase db = qscriptvalue_cast<QSqlDatabase>(context->thisObject());
    QString from_version = context->argument(0).toString();
    QString to_version = context->argument(1).toString();
    QScriptValue callback = context->argument(2);

    QScriptValue instance = engine->newObject();
    instance.setProperty(QLatin1String("executeSql"), engine->newFunction(qmlsqldatabase_executeSql,1));
    QScriptValue tx = engine->newVariant(instance,QVariant::fromValue(db));

    QString foundvers = context->thisObject().property(QLatin1String("version")).toString();
    if (from_version!=foundvers) {
        THROW_SQL(VERSION_ERR,QDeclarativeEngine::tr("Version mismatch: expected %1, found %2").arg(from_version).arg(foundvers));
        return engine->undefinedValue();
    }

    bool ok = true;
    if (callback.isFunction()) {
        ok = false;
        db.transaction();
        callback.call(QScriptValue(), QScriptValueList() << tx);
        if (engine->hasUncaughtException()) {
            db.rollback();
        } else {
            if (!db.commit()) {
                db.rollback();
                THROW_SQL(UNKNOWN_ERR,QDeclarativeEngine::tr("SQL transaction failed"));
            } else {
                ok = true;
            }
        }
    }

    if (ok) {
        context->thisObject().setProperty(QLatin1String("version"), to_version, QScriptValue::ReadOnly);
#ifndef QT_NO_SETTINGS
        QSettings ini(qmlsqldatabase_databaseFile(db.connectionName(),engine) + QLatin1String(".ini"), QSettings::IniFormat);
        ini.setValue(QLatin1String("Version"), to_version);
#endif
    }

    return engine->undefinedValue();
}
static QScriptValue qmlsqldatabase_executeSql(QScriptContext *context, QScriptEngine *engine)
{
    QSqlDatabase db = qscriptvalue_cast<QSqlDatabase>(context->thisObject());
    QString sql = context->argument(0).toString();
    QSqlQuery query(db);
    bool err = false;

    QScriptValue result;

    if (query.prepare(sql)) {
        if (context->argumentCount() > 1) {
            QScriptValue values = context->argument(1);
            if (values.isObject()) {
                if (values.isArray()) {
                    int size = values.property(QLatin1String("length")).toInt32();
                    for (int i = 0; i < size; ++i)
                        query.bindValue(i, values.property(i).toVariant());
                } else {
                    for (QScriptValueIterator it(values); it.hasNext();) {
                        it.next();
                        query.bindValue(it.name(),it.value().toVariant());
                    }
                }
            } else {
                query.bindValue(0,values.toVariant());
            }
        }
        if (query.exec()) {
            result = engine->newObject();
            QDeclarativeScriptEngine *qmlengine = static_cast<QDeclarativeScriptEngine*>(engine);
            if (!qmlengine->sqlQueryClass)
                qmlengine->sqlQueryClass = new QDeclarativeSqlQueryScriptClass(engine);
            QScriptValue rows = engine->newObject(qmlengine->sqlQueryClass);
            rows.setData(engine->newVariant(qVariantFromValue(query)));
            rows.setProperty(QLatin1String("item"), engine->newFunction(qmlsqldatabase_item,1), QScriptValue::SkipInEnumeration);
            result.setProperty(QLatin1String("rows"),rows);
            result.setProperty(QLatin1String("rowsAffected"),query.numRowsAffected());
            result.setProperty(QLatin1String("insertId"),query.lastInsertId().toString());
        } else {
            err = true;
        }
    } else {
        err = true;
    }
    if (err)
        THROW_SQL(DATABASE_ERR,query.lastError().text());
    return result;
}
static QScriptValue qmlsqldatabase_transaction_shared(QScriptContext *context, QScriptEngine *engine, bool readOnly)
{
    QSqlDatabase db = qscriptvalue_cast<QSqlDatabase>(context->thisObject());
    QScriptValue callback = context->argument(0);
    if (!callback.isFunction())
        THROW_SQL(UNKNOWN_ERR,QDeclarativeEngine::tr("transaction: missing callback"));

    QScriptValue instance = engine->newObject();
    instance.setProperty(QLatin1String("executeSql"),
        engine->newFunction(readOnly ? qmlsqldatabase_executeSql_readonly : qmlsqldatabase_executeSql,1));
    QScriptValue tx = engine->newVariant(instance,qVariantFromValue(db));

    db.transaction();
    callback.call(QScriptValue(), QScriptValueList() << tx);
    instance.setProperty(QLatin1String("executeSql"),
        engine->newFunction(qmlsqldatabase_executeSql_outsidetransaction));
    if (engine->hasUncaughtException()) {
        db.rollback();
    } else {
        if (!db.commit())
            db.rollback();
    }
    return engine->undefinedValue();
}
/*
    Currently documented in doc/src/declarative/globalobject.qdoc
*/
static QScriptValue qmlsqldatabase_open_sync(QScriptContext *context, QScriptEngine *engine)
{
    qmlsqldatabase_initDatabasesPath(engine);

    QSqlDatabase database;

    QString dbname = context->argument(0).toString();
    QString dbversion = context->argument(1).toString();
    QString dbdescription = context->argument(2).toString();
    int dbestimatedsize = context->argument(3).toNumber();
    QScriptValue dbcreationCallback = context->argument(4);

    QCryptographicHash md5(QCryptographicHash::Md5);
    md5.addData(dbname.toUtf8());
    QString dbid(QLatin1String(md5.result().toHex()));

    QString basename = qmlsqldatabase_databaseFile(dbid, engine);
    bool created = false;
    QString version = dbversion;

    {
        QSettings ini(basename+QLatin1String(".ini"),QSettings::IniFormat);

        if (QSqlDatabase::connectionNames().contains(dbid)) {
            database = QSqlDatabase::database(dbid);
            version = ini.value(QLatin1String("Version")).toString();
            if (version != dbversion && !dbversion.isEmpty() && !version.isEmpty())
                THROW_SQL(VERSION_ERR,QDeclarativeEngine::tr("SQL: database version mismatch"));
        } else {
            created = !QFile::exists(basename+QLatin1String(".sqlite"));
            database = QSqlDatabase::addDatabase(QLatin1String("QSQLITE"), dbid);
            if (created) {
                ini.setValue(QLatin1String("Name"), dbname);
                if (dbcreationCallback.isFunction())
                    version = QString();
                ini.setValue(QLatin1String("Version"), version);
                ini.setValue(QLatin1String("Description"), dbdescription);
                ini.setValue(QLatin1String("EstimatedSize"), dbestimatedsize);
                ini.setValue(QLatin1String("Driver"), QLatin1String("QSQLITE"));
            } else {
                if (!dbversion.isEmpty() && ini.value(QLatin1String("Version")) != dbversion) {
                    // Incompatible
                    THROW_SQL(VERSION_ERR,QDeclarativeEngine::tr("SQL: database version mismatch"));
                }
                version = ini.value(QLatin1String("Version")).toString();
            }
            database.setDatabaseName(basename+QLatin1String(".sqlite"));
        }
        if (!database.isOpen())
            database.open();
    }

    QScriptValue instance = engine->newObject();
    instance.setProperty(QLatin1String("transaction"), engine->newFunction(qmlsqldatabase_transaction,1));
    instance.setProperty(QLatin1String("readTransaction"), engine->newFunction(qmlsqldatabase_read_transaction,1));
    instance.setProperty(QLatin1String("version"), version, QScriptValue::ReadOnly);
    instance.setProperty(QLatin1String("changeVersion"), engine->newFunction(qmlsqldatabase_change_version,3));

    QScriptValue result = engine->newVariant(instance,qVariantFromValue(database));

    if (created && dbcreationCallback.isFunction()) {
        dbcreationCallback.call(QScriptValue(), QScriptValueList() << result);
    }

    return result;
}
static QScriptValue qmlsqldatabase_executeSql_outsidetransaction(QScriptContext *context, QScriptEngine * /*engine*/)
{
    THROW_SQL(DATABASE_ERR,QDeclarativeEngine::tr("executeSql called outside transaction()"));
}