183 if (r->d()->sqlQuery->at() == (
int)index || r->d()->sqlQuery->seek(index)) {
184 QSqlRecord record = r->d()->sqlQuery->record();
186 ScopedObject row(scope, v4->newObject());
187 for (
int ii = 0; ii < record.count(); ++ii) {
188 QVariant v = record.value(ii);
189 ScopedString s(scope, v4->newIdentifier(record.fieldName(ii)));
190 ScopedValue val(scope, v.isNull() ? Encode::null() : v4->fromVariant(v));
191 row->put(s.getPointer(), val);
195 return row.asReturnedValue();
198 *hasProperty =
false;
199 return Encode::undefined();
203ReturnedValue
QQmlSqlDatabaseWrapper::virtualGet(
const Managed *m, PropertyKey id,
const Value *receiver,
bool *hasProperty)
205 if (!id.isArrayIndex())
206 return Object::virtualGet(m, id, receiver, hasProperty);
208 uint index = id.asArrayIndex();
211 if (!r || r->d()->type != Heap::QQmlSqlDatabaseWrapper::Rows)
212 return Object::virtualGet(m, id, receiver, hasProperty);
214 return qmlsqldatabase_rows_index(r, r->engine(), index, hasProperty);
239 QV4::Scoped<QQmlSqlDatabaseWrapper> r(scope, thisObject->as<QQmlSqlDatabaseWrapper>());
240 if (!r || r->d()->type != Heap::QQmlSqlDatabaseWrapper::Query)
243 if (!r->d()->inTransaction)
244 V4THROW_SQL(SQLEXCEPTION_DATABASE_ERR,QQmlEngine::tr(
"executeSql called outside transaction()"));
246 QSqlDatabase db = *r->d()->database;
248 QString sql = argc ? argv[0].toQString() : QString();
250 if (r->d()->readonly && !sql.startsWith(QLatin1String(
"SELECT"),Qt::CaseInsensitive)) {
251 V4THROW_SQL(SQLEXCEPTION_SYNTAX_ERR, QQmlEngine::tr(
"Read-only Transaction"));
257 ScopedValue result(scope, Value::undefinedValue());
259 if (query.prepare(sql)) {
261 ScopedValue values(scope, argv[1]);
262 if (values->as<ArrayObject>()) {
263 ScopedArrayObject array(scope, values);
264 quint32 size = array->getLength();
265 QV4::ScopedValue v(scope);
266 for (quint32 ii = 0; ii < size; ++ii) {
267 query.bindValue(ii, toSqlVariant((v = array->get(ii))));
269 }
else if (values->as<Object>()) {
270 ScopedObject object(scope, values);
271 ObjectIterator it(scope, object, ObjectIterator::EnumerableOnly);
272 ScopedValue key(scope);
273 QV4::ScopedValue val(scope);
275 key = it.nextPropertyName(val);
278 QVariant v = toSqlVariant(val);
279 if (key->isString()) {
280 query.bindValue(key->stringValue()->toQString(), v);
282 Q_ASSERT(key->isInteger());
283 query.bindValue(key->integerValue(), v);
287 query.bindValue(0, toSqlVariant(values));
291 QV4::Scoped<QQmlSqlDatabaseWrapper> rows(scope, QQmlSqlDatabaseWrapper::create(scope.engine));
292 QV4::ScopedObject p(scope, databaseData(scope.engine)->rowsProto.value());
293 rows->setPrototypeUnchecked(p.getPointer());
294 rows->d()->type = Heap::QQmlSqlDatabaseWrapper::Rows;
295 *rows->d()->database = db;
296 *rows->d()->sqlQuery = std::move(query);
297 QSqlQuery *queryPtr = rows->d()->sqlQuery;
299 ScopedObject resultObject(scope, scope.engine->newObject());
300 result = resultObject.asReturnedValue();
302 ScopedString s(scope);
303 ScopedValue v(scope);
304 resultObject->put((s = scope.engine->newIdentifier(QLatin1String(
"rowsAffected"))).getPointer(),
305 (v = Value::fromInt32(queryPtr->numRowsAffected())));
306 resultObject->put((s = scope.engine->newIdentifier(QLatin1String(
"insertId"))).getPointer(),
307 (v = scope.engine->newString(queryPtr->lastInsertId().toString())));
308 resultObject->put((s = scope.engine->newIdentifier(QLatin1String(
"rows"))).getPointer(),
317 V4THROW_SQL(SQLEXCEPTION_DATABASE_ERR,query.lastError().text());
319 RETURN_RESULT(result->asReturnedValue());
357 Scoped<QQmlSqlDatabaseWrapper> r(scope, *thisObject);
358 if (!r || r->d()->type != Heap::QQmlSqlDatabaseWrapper::Database)
361 QSqlDatabase db = *r->d()->database;
362 QString from_version = argv[0].toQString();
363 QString to_version = argv[1].toQString();
364 ScopedFunctionObject callback(scope, argc > 2 ? argv[2] : Value::undefinedValue());
366 if (from_version != *r->d()->version)
367 V4THROW_SQL(SQLEXCEPTION_VERSION_ERR, QQmlEngine::tr(
"Version mismatch: expected %1, found %2").arg(from_version).arg(*r->d()->version));
371 Scoped<QQmlSqlDatabaseWrapper> query(scope, QQmlSqlDatabaseWrapper::create(scope.engine));
372 ScopedObject p(scope, databaseData(scope.engine)->queryProto.value());
373 query->setPrototypeUnchecked(p.getPointer());
374 query->d()->type = Heap::QQmlSqlDatabaseWrapper::Query;
375 *query->d()->database = db;
376 *query->d()->version = *r->d()->version;
381 JSCallArguments jsCall(scope, 1);
382 *jsCall.thisObject = scope.engine->globalObject;
383 jsCall.args[0] = query;
386 callback->call(jsCall);
390 V4THROW_SQL(SQLEXCEPTION_UNKNOWN_ERR,QQmlEngine::tr(
"SQL transaction failed"));
397 Scoped<QQmlSqlDatabaseWrapper> w(scope, QQmlSqlDatabaseWrapper::create(scope.engine));
398 ScopedObject p(scope, databaseData(scope.engine)->databaseProto.value());
399 w->setPrototypeUnchecked(p.getPointer());
400 w->d()->type = Heap::QQmlSqlDatabaseWrapper::Database;
401 *w->d()->database = db;
402 *w->d()->version = to_version;
403#if QT_CONFIG(settings)
404 const QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(scope.engine->qmlEngine());
405 QSettings ini(enginePrivate->offlineStorageDatabaseDirectory() + db.connectionName() + QLatin1String(
".ini"), QSettings::IniFormat);
406 ini.setValue(QLatin1String(
"Version"), to_version);
408 RETURN_RESULT(w.asReturnedValue());
417 QV4::Scoped<QQmlSqlDatabaseWrapper> r(scope, thisObject->as<QQmlSqlDatabaseWrapper>());
418 if (!r || r->d()->type != Heap::QQmlSqlDatabaseWrapper::Database)
421 const FunctionObject *callback = argc ? argv[0].as<FunctionObject>() :
nullptr;
423 V4THROW_SQL(SQLEXCEPTION_UNKNOWN_ERR, QQmlEngine::tr(
"transaction: missing callback"));
425 QSqlDatabase db = *r->d()->database;
427 Scoped<QQmlSqlDatabaseWrapper> w(scope, QQmlSqlDatabaseWrapper::create(scope.engine));
428 QV4::ScopedObject p(scope, databaseData(scope.engine)->queryProto.value());
429 w->setPrototypeUnchecked(p.getPointer());
430 w->d()->type = Heap::QQmlSqlDatabaseWrapper::Query;
431 *w->d()->database = db;
432 *w->d()->version = *r->d()->version;
433 w->d()->readonly = readOnly;
437 JSCallArguments jsCall(scope, 1);
438 *jsCall.thisObject = scope.engine->globalObject;
441 callback->call(jsCall);
465 ScopedObject proto(scope, v4->newObject());
466 proto->defineDefaultProperty(QStringLiteral(
"transaction"), qmlsqldatabase_transaction);
467 proto->defineDefaultProperty(QStringLiteral(
"readTransaction"), qmlsqldatabase_read_transaction);
468 proto->defineAccessorProperty(QStringLiteral(
"version"), qmlsqldatabase_version,
nullptr);
469 proto->defineDefaultProperty(QStringLiteral(
"changeVersion"), qmlsqldatabase_changeVersion);
470 databaseProto = proto;
474 ScopedObject proto(scope, v4->newObject());
475 proto->defineDefaultProperty(QStringLiteral(
"executeSql"), qmlsqldatabase_executeSql);
479 ScopedObject proto(scope, v4->newObject());
480 proto->defineDefaultProperty(QStringLiteral(
"item"), qmlsqldatabase_rows_item);
481 proto->defineAccessorProperty(QStringLiteral(
"length"), qmlsqldatabase_rows_length,
nullptr);
482 proto->defineAccessorProperty(QStringLiteral(
"forwardOnly"),
483 qmlsqldatabase_rows_forwardOnly, qmlsqldatabase_rows_setForwardOnly);
686void QQmlLocalStorage::openDatabaseSync(QQmlV4FunctionPtr args)
688#if QT_CONFIG(settings)
689 QV4::Scope scope(args->v4engine());
690 if (scope.engine->qmlEngine()->offlineStoragePath().isEmpty())
691 V4THROW_SQL2(SQLEXCEPTION_DATABASE_ERR, QQmlEngine::tr(
"SQL: can't create database, offline storage is disabled."));
693 QV4::ScopedValue v(scope);
694 QString dbname = (v = (*args)[0])->toQStringNoThrow();
695 QString dbversion = (v = (*args)[1])->toQStringNoThrow();
696 QString dbdescription = (v = (*args)[2])->toQStringNoThrow();
697 int dbestimatedsize = (v = (*args)[3])->toInt32();
698 FunctionObject *dbcreationCallback = (v = (*args)[4])->as<FunctionObject>();
699 QString basename = args->v4engine()->qmlEngine()->offlineStorageDatabaseFilePath(dbname);
700 QFileInfo dbFile(basename);
701 if (!QDir().mkpath(dbFile.dir().absolutePath())) {
702 const QString message = QQmlEngine::tr(
"LocalStorage: can't create path %1").
703 arg(QDir::toNativeSeparators(dbFile.dir().absolutePath()));
704 V4THROW_SQL2(SQLEXCEPTION_DATABASE_ERR, message);
706 QString dbid = dbFile.fileName();
707 bool created =
false;
708 QString version = dbversion;
709 QSqlDatabase database;
712 QSettings ini(basename+QLatin1String(
".ini"),QSettings::IniFormat);
714 if (QSqlDatabase::connectionNames().contains(dbid)) {
715 database = QSqlDatabase::database(dbid);
716 version = ini.value(QLatin1String(
"Version")).toString();
717 if (version != dbversion && !dbversion.isEmpty() && !version.isEmpty())
718 V4THROW_SQL2(SQLEXCEPTION_VERSION_ERR, QQmlEngine::tr(
"SQL: database version mismatch"));
720 created = !QFile::exists(basename+QLatin1String(
".sqlite"));
722 ini.setValue(QLatin1String(
"Name"), dbname);
723 if (dbcreationCallback)
725 ini.setValue(QLatin1String(
"Version"), version);
726 ini.setValue(QLatin1String(
"Description"), dbdescription);
727 ini.setValue(QLatin1String(
"EstimatedSize"), dbestimatedsize);
728 ini.setValue(QLatin1String(
"Driver"), QLatin1String(
"QSQLITE"));
730 if (!dbversion.isEmpty() && ini.value(QLatin1String(
"Version")) != dbversion) {
732 V4THROW_SQL2(SQLEXCEPTION_VERSION_ERR,QQmlEngine::tr(
"SQL: database version mismatch"));
734 version = ini.value(QLatin1String(
"Version")).toString();
736 database = QSqlDatabase::addDatabase(QLatin1String(
"QSQLITE"), dbid);
737 database.setDatabaseName(basename+QLatin1String(
".sqlite"));
739 if (!database.isOpen() && !database.open())
740 V4THROW_SQL2(SQLEXCEPTION_DATABASE_ERR, QQmlEngine::tr(
"SQL: Cannot open database"));
743 QV4::Scoped<QQmlSqlDatabaseWrapper> db(scope, QQmlSqlDatabaseWrapper::create(scope.engine));
744 QV4::ScopedObject p(scope, databaseData(scope.engine)->databaseProto.value());
745 db->setPrototypeUnchecked(p.getPointer());
746 *db->d()->database = database;
747 *db->d()->version = version;
749 if (created && dbcreationCallback) {
750 JSCallArguments jsCall(scope, 1);
751 *jsCall.thisObject = scope.engine->globalObject;
753 dbcreationCallback->call(jsCall);
756 args->setReturnValue(db.asReturnedValue());