~ubuntu-branches/ubuntu/utopic/rhythmbox/utopic-proposed

« back to all changes in this revision

Viewing changes to rhythmdb/rhythmdb-gda.c

Tags: upstream-0.9.2
ImportĀ upstreamĀ versionĀ 0.9.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* 
 
2
 *  arch-tag: Implementation of RhythmDB libgda/SQLite database
 
3
 *
 
4
 *  Copyright (C) 2004 Benjamin Otte <otte@gnome.org>
 
5
 *
 
6
 *  This program is free software; you can redistribute it and/or modify
 
7
 *  it under the terms of the GNU General Public License as published by
 
8
 *  the Free Software Foundation; either version 2 of the License, or
 
9
 *  (at your option) any later version.
 
10
 *
 
11
 *  This program is distributed in the hope that it will be useful,
 
12
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
 *  GNU General Public License for more details.
 
15
 *
 
16
 *  You should have received a copy of the GNU General Public License
 
17
 *  along with this program; if not, write to the Free Software
 
18
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
19
 *
 
20
 */
 
21
 
 
22
#include <config.h>
 
23
#include "rhythmdb-gda.h"
 
24
#include "rhythmdb-query-model.h"
 
25
 
 
26
#if 0
 
27
#define g_print(...)
 
28
#endif
 
29
 
 
30
static void rhythmdb_gda_class_init (RhythmDBGdaClass * klass);
 
31
static void rhythmdb_gda_init (RhythmDBGda * shell_player);
 
32
static void rhythmdb_gda_finalize (GObject * object);
 
33
 
 
34
static void rhythmdb_gda_load (RhythmDB * rdb, gboolean * die);
 
35
static void rhythmdb_gda_save (RhythmDB * rdb);
 
36
static RhythmDBEntry *rhythmdb_gda_entry_new (RhythmDB * db,
 
37
    RhythmDBEntryType type, const char *uri);
 
38
static void rhythmdb_gda_entry_set (RhythmDB * db, RhythmDBEntry * entry,
 
39
    guint propid, const GValue * value);
 
40
static void rhythmdb_gda_entry_get (RhythmDB * db, RhythmDBEntry * entry,
 
41
    guint propid, GValue * value);
 
42
static void rhythmdb_gda_entry_delete (RhythmDB * db, RhythmDBEntry * entry);
 
43
static void rhythmdb_gda_entry_delete_by_type (RhythmDB * adb,
 
44
    RhythmDBEntryType type);
 
45
static RhythmDBEntry *rhythmdb_gda_entry_lookup_by_location (RhythmDB * db,
 
46
    const char *uri);
 
47
static void rhythmdb_gda_do_full_query (RhythmDB * db, GPtrArray * query,
 
48
    GtkTreeModel * main_model, gboolean * cancel);
 
49
static gboolean rhythmdb_gda_evaluate_query (RhythmDB * adb, GPtrArray * query,
 
50
    RhythmDBEntry * aentry);
 
51
 
 
52
static GObjectClass *parent_class = NULL;
 
53
 
 
54
GType
 
55
rhythmdb_gda_get_type (void)
 
56
{
 
57
  static GType rhythmdb_gda_type = 0;
 
58
 
 
59
  if (rhythmdb_gda_type == 0) {
 
60
    static const GTypeInfo our_info = {
 
61
      sizeof (RhythmDBGdaClass),
 
62
      NULL,
 
63
      NULL,
 
64
      (GClassInitFunc) rhythmdb_gda_class_init,
 
65
      NULL,
 
66
      NULL,
 
67
      sizeof (RhythmDBGda),
 
68
      0,
 
69
      (GInstanceInitFunc) rhythmdb_gda_init
 
70
    };
 
71
 
 
72
    rhythmdb_gda_type = g_type_register_static (RHYTHMDB_TYPE,
 
73
        "RhythmDBGda", &our_info, 0);
 
74
  }
 
75
 
 
76
  return rhythmdb_gda_type;
 
77
}
 
78
 
 
79
static void
 
80
rhythmdb_gda_class_init (RhythmDBGdaClass * klass)
 
81
{
 
82
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
83
  RhythmDBClass *rhythmdb_class = RHYTHMDB_CLASS (klass);
 
84
 
 
85
  parent_class = g_type_class_peek_parent (klass);
 
86
 
 
87
  object_class->finalize = rhythmdb_gda_finalize;
 
88
 
 
89
  rhythmdb_class->impl_load = rhythmdb_gda_load;
 
90
  rhythmdb_class->impl_save = rhythmdb_gda_save;
 
91
  rhythmdb_class->impl_entry_new = rhythmdb_gda_entry_new;
 
92
  rhythmdb_class->impl_entry_set = rhythmdb_gda_entry_set;
 
93
  rhythmdb_class->impl_entry_get = rhythmdb_gda_entry_get;
 
94
  rhythmdb_class->impl_entry_delete = rhythmdb_gda_entry_delete;
 
95
  rhythmdb_class->impl_entry_delete_by_type = rhythmdb_gda_entry_delete_by_type;
 
96
  rhythmdb_class->impl_lookup_by_location =
 
97
      rhythmdb_gda_entry_lookup_by_location;
 
98
  rhythmdb_class->impl_evaluate_query = rhythmdb_gda_evaluate_query;
 
99
  rhythmdb_class->impl_do_full_query = rhythmdb_gda_do_full_query;
 
100
}
 
101
 
 
102
static void
 
103
rhythmdb_gda_init (RhythmDBGda * db)
 
104
{
 
105
  gint i;
 
106
  /* FIXME: This is a hack to replace '-' with '_' because of SQL column syntax */
 
107
  for (i = 0; i < RHYTHMDB_NUM_PROPERTIES; i++) {
 
108
    gchar *mod = (gchar *) rhythmdb_nice_elt_name_from_propid (RHYTHMDB (db), i);
 
109
    while (*mod) {
 
110
      if (*mod == '-') *mod = '_';
 
111
      mod ++;
 
112
    }
 
113
  }
 
114
  
 
115
  /* we'll set up the Db in the _new function when we actually know the filename */
 
116
}
 
117
 
 
118
static gchar *
 
119
escape_string (const gchar *orig)
 
120
{
 
121
  gchar **strv;
 
122
  gchar *ret, *tmp;
 
123
  /* this is the shortest possible version. it's definitely slow */
 
124
  strv = g_strsplit (orig, "\"", 0);
 
125
  tmp = g_strjoinv ("\"\"", strv);
 
126
  g_strfreev (strv);
 
127
  ret = g_strdup_printf ("\"%s\"", tmp);
 
128
  g_free (tmp);
 
129
  return ret;
 
130
}
 
131
 
 
132
/* debugging */
 
133
static void
 
134
dump_model (GdaDataModel *model)
 
135
{
 
136
  guint i, j;
 
137
 
 
138
  for (i = 0; i < gda_data_model_get_n_rows (model); i++) {
 
139
    for (j = 0; j < gda_data_model_get_n_columns (model); j++) {
 
140
      const GdaValue *value = gda_data_model_get_value_at (model, j, i);
 
141
      
 
142
      if (value) {
 
143
        gchar *str = gda_value_stringify (value);
 
144
        g_print ("(%4u, %4u) - %s (%d)\n", i, j, str, gda_value_get_type (value));
 
145
        g_free (str);
 
146
      } else {
 
147
        g_print ("(%4u, %4u) - (NULL)\n", i, j);
 
148
      }
 
149
    }
 
150
  }
 
151
}
 
152
 
 
153
GStaticMutex my_mutex = G_STATIC_MUTEX_INIT;
 
154
 
 
155
static GdaDataModel *
 
156
execute_query (RhythmDBGda *db, const gchar *query)
 
157
{
 
158
  GdaDataModel *model;
 
159
  GdaCommand *command;
 
160
  
 
161
  g_print ("Executing Query:    %s\n", query);
 
162
  command = gda_command_new (query, GDA_COMMAND_TYPE_SQL, GDA_COMMAND_OPTION_STOP_ON_ERRORS);
 
163
  g_static_mutex_lock (&my_mutex);
 
164
  model = gda_connection_execute_single_command (db->conn, command, NULL);
 
165
  g_static_mutex_unlock (&my_mutex);
 
166
  gda_command_free (command);
 
167
  if (model) {
 
168
    dump_model (model);
 
169
  } else {
 
170
    g_warning ("query '%s' failed", query);
 
171
  }
 
172
  
 
173
  return model;
 
174
}
 
175
 
 
176
static gboolean
 
177
execute_nonquery (RhythmDBGda *db, const gchar *query)
 
178
{
 
179
  gboolean ret;
 
180
  GdaCommand *command;
 
181
  
 
182
  g_print ("Executing NonQuery: %s\n", query);
 
183
  command = gda_command_new (query, GDA_COMMAND_TYPE_SQL, GDA_COMMAND_OPTION_STOP_ON_ERRORS);
 
184
  g_static_mutex_lock (&my_mutex);
 
185
  ret = gda_connection_execute_non_query (db->conn, command, NULL) != -1;
 
186
  g_static_mutex_unlock (&my_mutex);
 
187
  gda_command_free (command);
 
188
  if (!ret)
 
189
    g_warning ("query '%s' failed", query);
 
190
 
 
191
  return ret;
 
192
}
 
193
 
 
194
#define TABLE "tracks"
 
195
static gboolean
 
196
ensure_table_exists (RhythmDBGda *db)
 
197
{
 
198
  GdaDataModel *model;
 
199
  guint i;
 
200
  GString *s;
 
201
  gboolean ret;
 
202
  
 
203
  model = gda_connection_get_schema (db->conn, GDA_CONNECTION_SCHEMA_TABLES, NULL);
 
204
  g_assert (model);
 
205
  dump_model (model);
 
206
 
 
207
  for (i = 0; i < gda_data_model_get_n_rows (model); i++) {
 
208
    const GdaValue *value = gda_data_model_get_value_at (model, i, 0);
 
209
    if (g_str_equal (gda_value_get_string (value), TABLE)) {
 
210
      g_print ("Table %s already exists. Great!\n", TABLE);
 
211
      return TRUE;
 
212
    }
 
213
  }
 
214
  /* create the table */
 
215
  s = g_string_new ("create table " TABLE " (refcount INTEGER, ");
 
216
  for (i = 0; i < RHYTHMDB_NUM_PROPERTIES; i++) {
 
217
    GType type = rhythmdb_get_property_type (RHYTHMDB (db), i);
 
218
    if (i > 0)
 
219
      g_string_append (s, ", ");
 
220
    g_string_append (s, rhythmdb_nice_elt_name_from_propid (RHYTHMDB (db), i));
 
221
    switch (type) {
 
222
      case G_TYPE_STRING:
 
223
        g_string_append_printf (s, " VARCHAR (200)");
 
224
        break;
 
225
      case G_TYPE_BOOLEAN:
 
226
        g_string_append_printf (s, " BOOLEAN");
 
227
        break;
 
228
      case G_TYPE_INT:
 
229
      case G_TYPE_LONG: /* FIXME */
 
230
      case G_TYPE_UINT64: /* FIXME */
 
231
        g_string_append_printf (s, " INTEGER");
 
232
        break;
 
233
      case G_TYPE_FLOAT:
 
234
      case G_TYPE_DOUBLE:
 
235
        g_string_append_printf (s, " FLOAT");
 
236
        break;
 
237
      default:
 
238
        g_warning ("unknown type %u", (guint) type);
 
239
        g_assert_not_reached ();
 
240
        break;
 
241
    }
 
242
  }
 
243
  /* optimizations */
 
244
  if (i == RHYTHMDB_PROP_LOCATION) {
 
245
    /* location is unique */
 
246
    g_string_append (s, " UNIQUE"); 
 
247
  }
 
248
  g_string_append (s, ")");
 
249
  ret =  execute_nonquery (db, s->str);
 
250
  g_string_free (s, TRUE);
 
251
  if (ret) {
 
252
    /* refcounting with autodelete (woohoo!) */
 
253
    ret = execute_nonquery (db, "create trigger delete_track after update of refcount on "
 
254
        TABLE " when new.refcount = 0 begin delete from " TABLE 
 
255
        " where _rowid_ = new._rowid_; end");
 
256
  }
 
257
  return ret;
 
258
}
 
259
 
 
260
static gchar *
 
261
collect_value_for_sql (const GValue *val) 
 
262
{
 
263
  gchar *value;
 
264
  
 
265
  switch (G_VALUE_TYPE (val)) {
 
266
    case G_TYPE_STRING:
 
267
      value = escape_string (g_value_get_string (val));
 
268
      break;
 
269
    case G_TYPE_BOOLEAN:
 
270
      value = g_strdup (g_value_get_boolean (val) ? "\"TRUE\"" : "\"FALSE\"");
 
271
      break;
 
272
    case G_TYPE_INT:
 
273
      value = g_strdup_printf ("%d", g_value_get_int (val));
 
274
      break;
 
275
    case G_TYPE_LONG:
 
276
      value = g_strdup_printf ("%ld", g_value_get_long (val));
 
277
      break;
 
278
    case G_TYPE_UINT64:
 
279
      value = g_strdup_printf ("%"G_GUINT64_FORMAT, g_value_get_uint64 (val));
 
280
      break;
 
281
    case G_TYPE_FLOAT:
 
282
      value = g_strdup_printf ("%f", g_value_get_float (val));
 
283
      break;
 
284
    case G_TYPE_DOUBLE:
 
285
      value = g_strdup_printf ("%g", g_value_get_double (val));
 
286
      break;
 
287
    default:
 
288
      g_assert_not_reached ();
 
289
      return NULL;
 
290
  }
 
291
  return value;
 
292
}
 
293
 
 
294
static void
 
295
collect_value_from_sql (GValue *dest, const GdaValue *src)
 
296
{
 
297
  const gchar *str;
 
298
  
 
299
  if (gda_value_isa (src, GDA_VALUE_TYPE_NULL))
 
300
    return;
 
301
  g_assert (gda_value_isa (src, GDA_VALUE_TYPE_STRING));
 
302
  str = gda_value_get_string (src);
 
303
  
 
304
  /* keep in sync with create table */
 
305
  switch (G_VALUE_TYPE (dest)) {
 
306
    case G_TYPE_STRING:
 
307
      g_value_set_string (dest, str);
 
308
      break;
 
309
    case G_TYPE_BOOLEAN:
 
310
      g_value_set_boolean (dest, g_str_equal (str, "TRUE"));
 
311
      break;
 
312
    case G_TYPE_INT:
 
313
      g_value_set_int (dest, strtol (str, NULL, 10));
 
314
      break;
 
315
    case G_TYPE_LONG:
 
316
      g_value_set_long (dest, strtol (str, NULL, 10));
 
317
      break;
 
318
    case G_TYPE_UINT64:
 
319
      g_value_set_uint64 (dest, strtoul (str, NULL, 10));
 
320
      break;
 
321
    case G_TYPE_FLOAT:
 
322
      g_value_set_float (dest, atof (str));
 
323
      break;
 
324
    case G_TYPE_DOUBLE:
 
325
      g_value_set_double (dest, atof (str));
 
326
      break;
 
327
    default:
 
328
      g_assert_not_reached ();
 
329
      break;
 
330
  }
 
331
}
 
332
  
 
333
static gboolean
 
334
_initialize (RhythmDBGda *db)
 
335
{
 
336
  /* check songs table */
 
337
  if (!ensure_table_exists (db))
 
338
    return FALSE;
 
339
  
 
340
  return execute_nonquery (db, "update " TABLE " set refcount=1");
 
341
}
 
342
 
 
343
RhythmDB *
 
344
rhythmdb_gda_new (const char *name)
 
345
{
 
346
  RhythmDBGda *db = g_object_new (RHYTHMDB_TYPE_GDA, "name", name, NULL);
 
347
  gchar *conn_str = g_strdup_printf ("URI=%s", name);
 
348
 
 
349
  g_print ("opening Db with conn string: %s\n", conn_str);
 
350
  db->client = gda_client_new ();
 
351
  g_return_val_if_fail (db->client, NULL);
 
352
  db->conn = gda_client_open_connection_from_string (db->client, "SQLite",
 
353
      conn_str, 0);
 
354
  g_free (conn_str);
 
355
  if (!db->conn) {
 
356
    g_warning ("GDA: error opening the library");
 
357
    g_object_unref (db->client);
 
358
    g_object_unref (db);
 
359
    return NULL;
 
360
  }
 
361
  if (!_initialize (db)) {
 
362
    g_warning ("GDA: error initializing the library");
 
363
    g_object_unref (db->conn);
 
364
    g_object_unref (db->client);
 
365
    g_object_unref (db);
 
366
    return NULL;
 
367
  }
 
368
  
 
369
  return RHYTHMDB (db);
 
370
}
 
371
 
 
372
static void 
 
373
rhythmdb_gda_finalize (GObject * object)
 
374
{
 
375
  RhythmDBGda *db = RHYTHMDB_GDA (object);
 
376
 
 
377
  g_object_unref (db->conn);
 
378
  g_object_unref (db->client);
 
379
 
 
380
  parent_class->finalize (object);
 
381
}
 
382
 
 
383
static void
 
384
rhythmdb_gda_load (RhythmDB * rdb, gboolean * die)
 
385
{
 
386
  guint i, j;
 
387
  static guint types[] = { RHYTHMDB_PROP_TITLE, RHYTHMDB_PROP_ARTIST, 
 
388
      RHYTHMDB_PROP_ALBUM, RHYTHMDB_PROP_LAST_PLAYED };
 
389
  RhythmDBGda *db = RHYTHMDB_GDA (rdb);
 
390
  GdaDataModel *model = execute_query (db, "select _rowid_, title, artist, album, last_played from " TABLE);
 
391
  g_return_if_fail (model);
 
392
    
 
393
  for (i = 0; i < gda_data_model_get_n_rows (model); i++) {
 
394
    gpointer entry = GINT_TO_POINTER ((gint) strtol (gda_value_get_string (
 
395
            gda_data_model_get_value_at (model, 0, i)), NULL, 10));
 
396
    for (j = 0; j < G_N_ELEMENTS (types); j++) {
 
397
      GValue val = {0, };
 
398
      g_value_init (&val, rhythmdb_get_property_type (rdb, types [j]));
 
399
      collect_value_from_sql (&val,  gda_data_model_get_value_at (model, j + 1, i));
 
400
      rhythmdb_entry_sync_mirrored (rdb, entry, types [j], &val);
 
401
      g_value_unset (&val);
 
402
    }
 
403
    rhythmdb_emit_entry_restored (rdb, entry);
 
404
  }
 
405
}
 
406
 
 
407
static void
 
408
rhythmdb_gda_save (RhythmDB * rdb)
 
409
{
 
410
  /* nothing to do here */
 
411
}
 
412
 
 
413
static RhythmDBEntry *
 
414
rhythmdb_gda_entry_new (RhythmDB * rdb, RhythmDBEntryType type, const char *uri)
 
415
{
 
416
  RhythmDBGda *db = RHYTHMDB_GDA (rdb);
 
417
  gchar *query = g_strdup_printf ("insert into " TABLE 
 
418
      " (type, refcount, location) values (%d, 1, \"%s\")", (gint) type, uri);
 
419
  
 
420
  if (!execute_nonquery (db, query)) {
 
421
    g_free (query);
 
422
    return NULL;
 
423
  }
 
424
  g_free (query);
 
425
  return rhythmdb_gda_entry_lookup_by_location (rdb, uri);
 
426
}
 
427
 
 
428
static void
 
429
rhythmdb_gda_entry_set (RhythmDB * rdb, RhythmDBEntry * entry,
 
430
    guint propid, const GValue * value)
 
431
{
 
432
  RhythmDBGda *db = RHYTHMDB_GDA (rdb);
 
433
  gchar *collect = collect_value_for_sql (value);
 
434
  gchar *query = g_strdup_printf ("update " TABLE " set %s = %s where _rowid_ = %d",
 
435
      rhythmdb_nice_elt_name_from_propid (rdb, propid), collect,
 
436
      GPOINTER_TO_INT (entry));
 
437
 
 
438
  execute_nonquery (db, query);
 
439
  g_free (query);  
 
440
}
 
441
 
 
442
static void
 
443
rhythmdb_gda_entry_get (RhythmDB * rdb, RhythmDBEntry * entry,
 
444
    guint propid, GValue * value)
 
445
{
 
446
  RhythmDBGda *db = RHYTHMDB_GDA (rdb);
 
447
  gchar *query = g_strdup_printf ("select %s from " TABLE 
 
448
      " where _ROWID_ = %d", rhythmdb_nice_elt_name_from_propid (rdb, propid),
 
449
      GPOINTER_TO_INT (entry));
 
450
  GdaDataModel *model = execute_query (db, query);
 
451
 
 
452
  g_free (query);
 
453
  if (!model) return;
 
454
  
 
455
  if (gda_data_model_get_n_rows (model) > 0) {
 
456
    g_assert (gda_data_model_get_n_rows (model) == 1);
 
457
    collect_value_from_sql (value, gda_data_model_get_value_at (model, 0, 0));
 
458
  }
 
459
  g_object_unref (G_OBJECT (model));
 
460
}
 
461
 
 
462
void
 
463
rhythmdb_gda_ref (RhythmDBGda *db, gint id, gint count)
 
464
{
 
465
  gchar *query = g_strdup_printf ("select refcount from " TABLE 
 
466
      " where _ROWID_ = %d", id);
 
467
  GdaDataModel *model = execute_query (db, query);
 
468
 
 
469
  g_free (query);
 
470
  g_assert (model);
 
471
  
 
472
  g_assert (gda_data_model_get_n_rows (model) == 1);
 
473
  count += strtol (gda_value_get_string (
 
474
        gda_data_model_get_value_at (model, 0, 0)), NULL, 10);
 
475
  g_object_unref (model);
 
476
  
 
477
  query = g_strdup_printf ("update " TABLE " set refcount = %d where _ROWID_ = %d",
 
478
      count, id);
 
479
  execute_nonquery (db, query);
 
480
  g_free (query);
 
481
}
 
482
 
 
483
static void
 
484
rhythmdb_gda_entry_delete (RhythmDB * rdb, RhythmDBEntry * entry)
 
485
{
 
486
  rhythmdb_gda_ref (RHYTHMDB_GDA (rdb), GPOINTER_TO_INT (entry), -1);
 
487
}
 
488
 
 
489
static void
 
490
rhythmdb_gda_entry_delete_by_type (RhythmDB * rdb, RhythmDBEntryType type)
 
491
{
 
492
  g_assert_not_reached ();
 
493
}
 
494
 
 
495
static RhythmDBEntry *
 
496
rhythmdb_gda_entry_lookup_by_location (RhythmDB * rdb, const char *uri)
 
497
{
 
498
  gpointer ret;
 
499
  RhythmDBGda *db = RHYTHMDB_GDA (rdb);
 
500
  gchar *escaped_uri = escape_string (uri);
 
501
  gchar *query = g_strdup_printf ("select _ROWID_ from " TABLE 
 
502
      " where location = %s", escaped_uri);
 
503
  GdaDataModel *model = execute_query (db, query);
 
504
 
 
505
  g_free (escaped_uri);
 
506
  g_free (query);
 
507
  if (!model) return NULL;
 
508
  
 
509
  if (gda_data_model_get_n_rows (model) > 0) {
 
510
    g_assert (gda_data_model_get_n_rows (model) == 1);
 
511
    ret = GINT_TO_POINTER (strtol (gda_value_get_string (
 
512
            gda_data_model_get_value_at (model, 0, 0)), NULL, 10));
 
513
  } else {
 
514
    ret = NULL;
 
515
  }
 
516
  g_object_unref (G_OBJECT (model));
 
517
  g_print ("FOUND ENTRY %p\n", ret);
 
518
  return ret;
 
519
}
 
520
 
 
521
static gchar *
 
522
translate_query (RhythmDBGda *db, RhythmDBQueryData *data)
 
523
{
 
524
  gchar *operation = NULL, *value, *ret;
 
525
  
 
526
  switch (data->type) {
 
527
    case RHYTHMDB_QUERY_DISJUNCTION:
 
528
    case RHYTHMDB_QUERY_SUBQUERY:
 
529
      g_assert_not_reached (); /* FIXME */
 
530
      return NULL;
 
531
    case RHYTHMDB_QUERY_PROP_EQUALS:
 
532
      operation = "%s = %s";
 
533
      break;
 
534
    case RHYTHMDB_QUERY_PROP_LIKE:
 
535
    case RHYTHMDB_QUERY_PROP_NOT_LIKE:
 
536
      g_assert_not_reached (); /* FIXME */
 
537
      break;
 
538
    case RHYTHMDB_QUERY_PROP_GREATER:
 
539
      operation = "%s > %s";
 
540
      break;
 
541
    case RHYTHMDB_QUERY_PROP_LESS:
 
542
      operation = "%s < %s";
 
543
      break;
 
544
    case RHYTHMDB_QUERY_END:
 
545
    default:
 
546
      g_assert_not_reached ();
 
547
      return NULL;
 
548
  }
 
549
  /* collect value */
 
550
  value = collect_value_for_sql (data->val);
 
551
  ret = g_strdup_printf (operation, rhythmdb_nice_elt_name_from_propid (RHYTHMDB (db), data->propid),
 
552
      value);
 
553
  g_free (value);
 
554
  
 
555
  return ret;
 
556
}
 
557
 
 
558
/* set rowid to 0 for all rows */
 
559
static GdaDataModel *
 
560
do_query (RhythmDBGda *db, GPtrArray * query, gint rowid)
 
561
{
 
562
  guint i;
 
563
  RhythmDBQueryData *data;
 
564
  GString *s = g_string_new (NULL);
 
565
  GdaDataModel *model;
 
566
  gchar *tmp;
 
567
  
 
568
  g_assert (query->len == 1);
 
569
  g_string_append (s, "select _ROWID_ from " TABLE " where ");
 
570
  if (rowid)
 
571
    g_string_append_printf (s, "rowid == %d AND (", rowid);
 
572
  for (i = 0; i < query->len; i++) {
 
573
    data = (RhythmDBQueryData *) g_ptr_array_index (query, i);
 
574
    tmp = translate_query (db, data);
 
575
    if (i > 0)
 
576
      g_string_append (s, " and ");
 
577
    g_string_append (s, tmp);
 
578
    g_free (tmp);
 
579
  }
 
580
  if (rowid)
 
581
    g_string_append (s, ")");
 
582
 
 
583
  model = execute_query (db, s->str);
 
584
  g_string_free (s, TRUE);
 
585
  return model;
 
586
}
 
587
 
 
588
static void
 
589
rhythmdb_gda_do_full_query (RhythmDB * rdb, GPtrArray * query,
 
590
    GtkTreeModel * main_model, gboolean * cancel)
 
591
{
 
592
  RhythmDBGda *db = RHYTHMDB_GDA (rdb);
 
593
  GdaDataModel *model = do_query (db, query, 0);
 
594
  g_return_if_fail (model);
 
595
 
 
596
  /* now the cludge */
 
597
  {
 
598
    int j;
 
599
    GPtrArray *queue;
 
600
    
 
601
    queue = g_ptr_array_sized_new (gda_data_model_get_n_rows (model));
 
602
    for (j = 0; j < gda_data_model_get_n_rows (model); j++) {
 
603
      g_ptr_array_add (queue, GINT_TO_POINTER (strtol (gda_value_get_string (
 
604
            gda_data_model_get_value_at (model, 0, j)), NULL, 10)));
 
605
    }
 
606
    rhythmdb_query_model_add_entries (RHYTHMDB_QUERY_MODEL (main_model), queue);
 
607
  }
 
608
}
 
609
 
 
610
static gboolean
 
611
rhythmdb_gda_evaluate_query (RhythmDB * rdb, GPtrArray * query,
 
612
    RhythmDBEntry * aentry)
 
613
{
 
614
  gboolean ret;
 
615
  RhythmDBGda *db = RHYTHMDB_GDA (rdb);
 
616
  GdaDataModel *model = do_query (db, query, GPOINTER_TO_INT (aentry));
 
617
 
 
618
  if (!model) return FALSE;
 
619
  ret = gda_data_model_get_n_rows (model) > 0;
 
620
  g_object_unref (model);
 
621
  return ret;
 
622
}