summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWarwick Allison <warwick.allison@nokia.com>2009-09-16 08:21:12 (GMT)
committerWarwick Allison <warwick.allison@nokia.com>2009-09-16 08:21:12 (GMT)
commit5d35dbc3552f722cf4de220d8737e8201e4f61e5 (patch)
tree382aa85b2b63c109b0307f327e6cf4befb7a40d9
parent4937e80baf3cce7444a007f5b3fa4979ea93f3fc (diff)
downloadQt-5d35dbc3552f722cf4de220d8737e8201e4f61e5.zip
Qt-5d35dbc3552f722cf4de220d8737e8201e4f61e5.tar.gz
Qt-5d35dbc3552f722cf4de220d8737e8201e4f61e5.tar.bz2
Better SQL database performance / memory usage.
Rows accessible incrementally. Rows.forwardOnly for optimization.
-rw-r--r--examples/declarative/sql/README7
-rw-r--r--examples/declarative/sql/hello.qml12
-rw-r--r--src/declarative/qml/qmlengine.cpp4
-rw-r--r--src/declarative/qml/qmlengine_p.h2
-rw-r--r--src/declarative/qml/qmlsqldatabase.cpp100
5 files changed, 109 insertions, 16 deletions
diff --git a/examples/declarative/sql/README b/examples/declarative/sql/README
new file mode 100644
index 0000000..a7baab2
--- /dev/null
+++ b/examples/declarative/sql/README
@@ -0,0 +1,7 @@
+Simple demonstration of HTML5-compatible SQL database interface.
+Adds another "hello, world" every time you run it.
+Database is stored in:
+ - %APPDATA%/Nokia/Qt/QML/Databases/ (Windows)
+ - ~/.local/share/Nokia/Qt/QML/Databases/ (Unix)
+ - ~/Library/Application Support/Nokia/Qt/QML/Databases/ (Mac OS X)
+No quota management.
diff --git a/examples/declarative/sql/hello.qml b/examples/declarative/sql/hello.qml
index fb6d21c..e43d320 100644
--- a/examples/declarative/sql/hello.qml
+++ b/examples/declarative/sql/hello.qml
@@ -2,10 +2,9 @@ import Qt 4.6
Text {
Script {
- function test()
+ function allGreetings()
{
var db = openDatabase("QmlExampleDB", "", "The Example QML SQL!", 1000000);
- print(db)
var r = ""
db.transaction(function(tx) {
@@ -13,9 +12,16 @@ Text {
tx.executeSql('INSERT INTO Greeting VALUES(?, ?)', [ 'hello', 'world' ]);
tx.executeSql('SELECT * FROM Greeting', [],
function(tx, rs) {
+ /* Inefficient HTML5-compatible way
for(var i = 0; i < rs.rows.length; i++) {
r += rs.rows[i][0] + ", " + rs.rows[i][1] + "\n"
}
+ */
+ /* Efficient way: forward only, not "length" query */
+ rs.rows.forwardOnly = true;
+ for(var i = 0; rs.rows[i]; i++) {
+ r += rs.rows[i][0] + ", " + rs.rows[i][1] + "\n"
+ }
},
function(tx, error) {
print("ERROR:", error.message)
@@ -26,5 +32,5 @@ Text {
return r
}
}
- text: test()
+ text: allGreetings()
}
diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp
index efe1a89..c0dd1a8 100644
--- a/src/declarative/qml/qmlengine.cpp
+++ b/src/declarative/qml/qmlengine.cpp
@@ -111,7 +111,7 @@ QScriptValue desktopOpenUrl(QScriptContext *ctxt, QScriptEngine *e)
QmlEnginePrivate::QmlEnginePrivate(QmlEngine *e)
: rootContext(0), currentExpression(0),
isDebugging(false), contextClass(0), objectClass(0), valueTypeClass(0),
- nodeListClass(0), namedNodeMapClass(0), scriptEngine(this), rootComponent(0),
+ nodeListClass(0), namedNodeMapClass(0), sqlQueryClass(0), scriptEngine(this), rootComponent(0),
networkAccessManager(0), typeManager(e), uniqueId(1)
{
QScriptValue qtObject =
@@ -156,6 +156,8 @@ QmlEnginePrivate::~QmlEnginePrivate()
nodeListClass = 0;
delete namedNodeMapClass;
namedNodeMapClass = 0;
+ delete sqlQueryClass;
+ sqlQueryClass = 0;
for(int ii = 0; ii < bindValues.count(); ++ii)
clear(bindValues[ii]);
diff --git a/src/declarative/qml/qmlengine_p.h b/src/declarative/qml/qmlengine_p.h
index 15ab40d..0eeae0c 100644
--- a/src/declarative/qml/qmlengine_p.h
+++ b/src/declarative/qml/qmlengine_p.h
@@ -154,6 +154,8 @@ public:
// Used by DOM Core 3 API
QScriptClass *nodeListClass;
QScriptClass *namedNodeMapClass;
+ // Used by SQL database API
+ QScriptClass *sqlQueryClass;
struct QmlScriptEngine : public QScriptEngine
{
diff --git a/src/declarative/qml/qmlsqldatabase.cpp b/src/declarative/qml/qmlsqldatabase.cpp
index 90d6e3e..4a7c3a3 100644
--- a/src/declarative/qml/qmlsqldatabase.cpp
+++ b/src/declarative/qml/qmlsqldatabase.cpp
@@ -65,6 +65,84 @@
#endif
Q_DECLARE_METATYPE(QSqlDatabase)
+Q_DECLARE_METATYPE(QSqlQuery)
+
+class QmlSqlQueryScriptClass: public QScriptClass {
+public:
+ QmlSqlQueryScriptClass(QScriptEngine *engine) : QScriptClass(engine)
+ {
+ str_length = engine->toStringHandle(QLatin1String("length"));
+ str_forwardOnly = engine->toStringHandle(QLatin1String("forwardOnly")); // not in HTML5 (optimization)
+ }
+
+ QueryFlags queryProperty(const QScriptValue &object,
+ const QScriptString &name,
+ QueryFlags flags, uint *id)
+ {
+ if (flags & HandlesReadAccess) {
+ if (name == str_length) {
+ return HandlesReadAccess;
+ } else if (name == str_forwardOnly) {
+ return flags;
+ } else {
+ bool ok;
+ qint32 pos = name.toString().toInt(&ok);
+ if (pos < 0 || !ok)
+ return 0;
+ QSqlQuery query = qscriptvalue_cast<QSqlQuery>(object.data());
+ *id = pos;
+ if (*id < (uint)query.size())
+ return HandlesReadAccess;
+ }
+ }
+ if (flags & HandlesWriteAccess)
+ if (name == str_forwardOnly)
+ return flags;
+ return 0;
+ }
+
+ QScriptValue property(const QScriptValue &object,
+ const QScriptString &name, uint id)
+ {
+ QSqlQuery query = qscriptvalue_cast<QSqlQuery>(object.data());
+ if (name == str_length) {
+ int s = query.size();
+ if (s<0) {
+ // Inefficient.
+ query.last();
+ return query.at()+1;
+ } else {
+ return s;
+ }
+ } else if (name == str_forwardOnly) {
+ return query.isForwardOnly();
+ } else {
+ if (query.at() == id || query.seek(id)) { // Qt 4.6 doesn't optimize at()==id
+ QSqlRecord r = query.record();
+ QScriptValue row = engine()->newArray(r.count());
+ for (int j=0; j<r.count(); ++j) {
+ // XXX only strings
+ row.setProperty(j, QScriptValue(engine(),r.value(j).toString()));
+ }
+ return row;
+ }
+ }
+ return engine()->undefinedValue();
+ }
+
+ void setProperty(QScriptValue &object,
+ const QScriptString &name, uint, const QScriptValue & value)
+ {
+ if (name == str_forwardOnly) {
+ QSqlQuery query = qscriptvalue_cast<QSqlQuery>(object.data());
+ query.setForwardOnly(value.toBool());
+ }
+ }
+
+private:
+ QScriptString str_length;
+ QScriptString str_forwardOnly;
+};
static QScriptValue qmlsqldatabase_executeSql(QScriptContext *context, QScriptEngine *engine)
{
@@ -85,18 +163,14 @@ static QScriptValue qmlsqldatabase_executeSql(QScriptContext *context, QScriptEn
query.bindValue(0,values.toVariant());
}
if (query.exec()) {
- QScriptValue rows = engine->newArray();
- int i=0;
- for (; query.next(); ++i) {
- QSqlRecord r = query.record();
- QScriptValue row = engine->newArray(r.count());
- for (int j=0; j<r.count(); ++j) {
- row.setProperty(j, QScriptValue(engine,r.value(j).toString()));
- }
- rows.setProperty(i, row);
- }
QScriptValue rs = engine->newObject();
- rs.setProperty(QLatin1String("rows"), rows);
+ if (!QmlEnginePrivate::get(engine)->sqlQueryClass)
+ QmlEnginePrivate::get(engine)->sqlQueryClass= new QmlSqlQueryScriptClass(engine);
+ QScriptValue rows = engine->newObject(QmlEnginePrivate::get(engine)->sqlQueryClass);
+ rows.setData(engine->newVariant(qVariantFromValue(query)));
+ rs.setProperty(QLatin1String("rows"),rows);
+ rs.setProperty(QLatin1String("rowsAffected"),query.numRowsAffected());
+ rs.setProperty(QLatin1String("insertId"),query.lastInsertId().toString()); // XXX only string
cb.call(QScriptValue(), QScriptValueList() << context->thisObject() << rs);
} else {
err = true;
@@ -142,7 +216,7 @@ static QScriptValue qmlsqldatabase_transaction(QScriptContext *context, QScriptE
return engine->undefinedValue();
}
-// XXX Something like this belongs in Qt.
+// XXX Something like this should be exported by Qt.
static QString userLocalDataPath(const QString& app)
{
QString result;
@@ -196,6 +270,8 @@ static QScriptValue qmlsqldatabase_open(QScriptContext *context, QScriptEngine *
md5.addData(dbversion.utf8());
QString dbid(QLatin1String(md5.result().toHex()));
+ // Uses SQLLITE (like HTML5), but any could be used.
+
if (QSqlDatabase::connectionNames().contains(dbid)) {
database = QSqlDatabase::database(dbid);
} else {