Merge lp:~midori/midori/makeAstatement into lp:midori

Proposed by Cris Dywan
Status: Merged
Approved by: André Stösel
Approved revision: 6511
Merged at revision: 6514
Proposed branch: lp:~midori/midori/makeAstatement
Merge into: lp:midori
Diff against target: 259 lines (+173/-48)
2 files modified
midori/midori-database.vala (+136/-2)
midori/midori-historydatabase.vala (+37/-46)
To merge this branch: bzr merge lp:~midori/midori/makeAstatement
Reviewer Review Type Date Requested Status
André Stösel Approve
Review via email: mp+198463@code.launchpad.net

Commit message

Introduce high-level prepare/ DatabaseStatement API

To post a comment you must log in.
Revision history for this message
André Stösel (ivaldi) wrote :

"statement = prepare (sqlcmd," is quite confusing if you just look at the diff (I would prefer this.prepare (..) (same for "exec", "exec_script",..)), but I guess it has nothing to do with this patch/branch -> approved

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'midori/midori-database.vala'
--- midori/midori-database.vala 2013-10-12 11:13:09 +0000
+++ midori/midori-database.vala 2013-12-10 21:57:30 +0000
@@ -10,13 +10,120 @@
10*/10*/
1111
12namespace Midori {12namespace Midori {
13 /*
14 * Since: 0.5.6
15 */
13 public errordomain DatabaseError {16 public errordomain DatabaseError {
14 OPEN,17 OPEN,
15 NAMING,18 NAMING,
16 FILENAME,19 FILENAME,
17 EXECUTE,20 EXECUTE,
18 }21 COMPILE,
1922 TYPE,
23 }
24
25 /*
26 * Since: 0.5.7
27 */
28 public class DatabaseStatement : GLib.Object, GLib.Initable {
29 public Sqlite.Statement? stmt { get { return _stmt; } }
30 protected Sqlite.Statement _stmt = null;
31 public Database? database { get; set construct; }
32 public string? query { get; set construct; }
33
34 public DatabaseStatement (Database database, string query) throws DatabaseError {
35 Object (database: database, query: query);
36 init ();
37 }
38
39 public virtual bool init (GLib.Cancellable? cancellable = null) throws DatabaseError {
40 int result = database.db.prepare_v2 (query, -1, out _stmt, null);
41 if (result != Sqlite.OK)
42 throw new DatabaseError.COMPILE ("Failed to compile statement: %s".printf (query));
43 return true;
44 }
45
46 /*
47 * Bind values to named parameters.
48 * SQL: "SELECT foo FROM bar WHERE id = :session_id"
49 * Vala: statement.bind(":session_id", typeof (int64), 12345);
50 * Supported types: string, int64, double
51 */
52 public void bind (string pname, ...) throws DatabaseError {
53 int pindex = stmt.bind_parameter_index (pname);
54 var args = va_list ();
55 Type ptype = args.arg ();
56 if (ptype == typeof (string))
57 stmt.bind_text (pindex, args.arg ());
58 else if (ptype == typeof (int64))
59 stmt.bind_int64 (pindex, args.arg ());
60 else if (ptype == typeof (double))
61 stmt.bind_double (pindex, args.arg ());
62 else
63 throw new DatabaseError.TYPE ("Invalid type '%s' for '%s' in statement: %s".printf (ptype.name (), pname, query));
64 }
65
66 /*
67 * Execute the statement, it's an error if there are more rows.
68 */
69 public bool exec () throws DatabaseError {
70 if (step ())
71 throw new DatabaseError.EXECUTE ("More rows available - use step instead of exec");
72 return true;
73 }
74
75 /*
76 * Proceed to the next row, returns false when the end is nigh.
77 */
78 public bool step () throws DatabaseError {
79 int result = stmt.step ();
80 if (result != Sqlite.DONE && result != Sqlite.ROW)
81 throw new DatabaseError.EXECUTE (database.db.errmsg ());
82 return result == Sqlite.ROW;
83 }
84
85 private int column_index (string name) throws DatabaseError {
86 for (int i = 0; i < stmt.column_count (); i++) {
87 if (name == stmt.column_name (i))
88 return i;
89 }
90 throw new DatabaseError.TYPE ("No such column '%s' in row: %s".printf (name, query));
91 }
92
93 /*
94 * Get a string value by its named parameter, for example ":uri".
95 */
96 public string? get_string (string name) throws DatabaseError {
97 int index = column_index (name);
98 if (stmt.column_type (index) != Sqlite.TEXT)
99 throw new DatabaseError.TYPE ("Getting '%s' with wrong type in row: %s".printf (name, query));
100 return stmt.column_text (index);
101 }
102
103 /*
104 * Get an integer value by its named parameter, for example ":day".
105 */
106 public int64 get_int64 (string name) throws DatabaseError {
107 int index = column_index (name);
108 if (stmt.column_type (index) != Sqlite.INTEGER)
109 throw new DatabaseError.TYPE ("Getting '%s' with wrong type in row: %s".printf (name, query));
110 return stmt.column_int64 (index);
111 }
112
113 /*
114 * Get a double value by its named parameter, for example ":session_id".
115 */
116 public double get_double (string name) throws DatabaseError {
117 int index = column_index (name);
118 if (stmt.column_type (index) != Sqlite.FLOAT)
119 throw new DatabaseError.TYPE ("Getting '%s' with wrong type in row: %s".printf (name, query));
120 return stmt.column_double (index);
121 }
122 }
123
124 /*
125 * Since: 0.5.6
126 */
20 public class Database : GLib.Object, GLib.Initable {127 public class Database : GLib.Object, GLib.Initable {
21 public Sqlite.Database? db { get { return _db; } }128 public Sqlite.Database? db { get { return _db; } }
22 protected Sqlite.Database? _db = null;129 protected Sqlite.Database? _db = null;
@@ -104,5 +211,32 @@
104 throw new DatabaseError.EXECUTE (db.errmsg ());211 throw new DatabaseError.EXECUTE (db.errmsg ());
105 return true;212 return true;
106 }213 }
214
215 /*
216 * Prepare a statement with optionally binding parameters by name.
217 * See also DatabaseStatement.bind().
218 * Since: 0.5.7
219 */
220 public DatabaseStatement prepare (string query, ...) throws DatabaseError {
221 var statement = new DatabaseStatement (this, query);
222 var args = va_list ();
223 unowned string? pname = args.arg ();
224 while (pname != null) {
225 Type ptype = args.arg ();
226 if (ptype == typeof (string)) {
227 string pvalue = args.arg ();
228 statement.bind (pname, ptype, pvalue);
229 } else if (ptype == typeof (int64)) {
230 int64 pvalue = args.arg ();
231 statement.bind (pname, ptype, pvalue);
232 } else if (ptype == typeof (double)) {
233 double pvalue = args.arg ();
234 statement.bind (pname, ptype, pvalue);
235 } else
236 throw new DatabaseError.TYPE ("Invalid type '%s' in statement: %s".printf (ptype.name (), query));
237 pname = args.arg ();
238 }
239 return statement;
240 }
107 }241 }
108}242}
109243
=== modified file 'midori/midori-historydatabase.vala'
--- midori/midori-historydatabase.vala 2013-10-11 22:43:02 +0000
+++ midori/midori-historydatabase.vala 2013-12-10 21:57:30 +0000
@@ -52,58 +52,49 @@
52 public async List<HistoryItem>? query (string sqlcmd, string? filter, int day, int max_items, Cancellable cancellable) {52 public async List<HistoryItem>? query (string sqlcmd, string? filter, int day, int max_items, Cancellable cancellable) {
53 return_val_if_fail (db != null, null);53 return_val_if_fail (db != null, null);
5454
55 Sqlite.Statement stmt;55 Midori.DatabaseStatement statement;
56 int result;56
5757 try {
58 result = db.prepare_v2 (sqlcmd, -1, out stmt, null);
59 if (result != Sqlite.OK) {
60 critical (_("Failed to select from history: %s"), db.errmsg ());
61 return null;
62 }
63
64 if (":filter" in sqlcmd) {
65 string real_filter = "%" + filter.replace (" ", "%") + "%";58 string real_filter = "%" + filter.replace (" ", "%") + "%";
66 stmt.bind_text (stmt.bind_parameter_index (":filter"), real_filter);59 statement = prepare (sqlcmd,
67 }60 ":filter", typeof (string), real_filter,
68 if (":day" in sqlcmd)61 ":day", typeof (int64), day,
69 stmt.bind_int64 (stmt.bind_parameter_index (":day"), day);62 ":limit", typeof (int64), max_items);
70 if (":limit" in sqlcmd)63 } catch (Error error) {
71 stmt.bind_int64 (stmt.bind_parameter_index (":limit"), max_items);64 critical (_("Failed to select from history: %s"), error.message);
72
73 result = stmt.step ();
74 if (!(result == Sqlite.DONE || result == Sqlite.ROW)) {
75 critical (_("Failed to select from history: %s"), db.errmsg ());
76 return null;65 return null;
77 }66 }
7867
79 var items = new List<HistoryItem> ();68 var items = new List<HistoryItem> ();
80 while (result == Sqlite.ROW) {69 try {
81 int64 type = stmt.column_int64 (0);70 while (statement.step ()) {
82 int64 date = stmt.column_int64 (1);71 int64 type = statement.get_int64 ("type");
83 switch (type) {72 int64 date = statement.get_int64 ("date");
84 case 1:73 switch (type) {
85 string uri = stmt.column_text (2);74 case 1:
86 string title = stmt.column_text (3);75 string uri = statement.get_string ("uri");
87 items.append (new HistoryWebsite (uri, title, date));76 string title = statement.get_string ("title");
88 break;77 items.append (new HistoryWebsite (uri, title, date));
89 case 2:78 break;
90 string uri = stmt.column_text (2);79 case 2:
91 string title = stmt.column_text (3);80 string uri = statement.get_string ("uri");
92 items.append (new HistorySearch (uri, title, date));81 string title = statement.get_string ("title");
93 break;82 items.append (new HistorySearch (uri, title, date));
94 default:83 break;
95 warn_if_reached ();84 default:
96 break;85 warn_if_reached ();
86 break;
87 }
88
89 uint src = Idle.add (query.callback);
90 yield;
91 Source.remove (src);
92
93 if (cancellable.is_cancelled ())
94 return null;
97 }95 }
9896 } catch (Error error) {
99 uint src = Idle.add (query.callback);97 critical (_("Failed to select from history: %s"), error.message);
100 yield;
101 Source.remove (src);
102
103 if (cancellable.is_cancelled ())
104 return null;
105
106 result = stmt.step ();
107 }98 }
10899
109 if (cancellable.is_cancelled ())100 if (cancellable.is_cancelled ())

Subscribers

People subscribed via source and target branches

to all changes: