2 * Copyright (C) 2003-2010 The Music Player Daemon Project
3 * http://www.musicpd.org
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
29 #define G_LOG_DOMAIN "sticker"
31 #if SQLITE_VERSION_NUMBER < 3003009
32 #define sqlite3_prepare_v2 sqlite3_prepare
45 STICKER_SQL_DELETE_VALUE
,
49 static const char *const sticker_sql
[] = {
51 "SELECT value FROM sticker WHERE type=? AND uri=? AND name=?",
53 "SELECT name,value FROM sticker WHERE type=? AND uri=?",
54 [STICKER_SQL_UPDATE
] =
55 "UPDATE sticker SET value=? WHERE type=? AND uri=? AND name=?",
56 [STICKER_SQL_INSERT
] =
57 "INSERT INTO sticker(type,uri,name,value) VALUES(?, ?, ?, ?)",
58 [STICKER_SQL_DELETE
] =
59 "DELETE FROM sticker WHERE type=? AND uri=?",
60 [STICKER_SQL_DELETE_VALUE
] =
61 "DELETE FROM sticker WHERE type=? AND uri=? AND name=?",
63 "SELECT uri,value FROM sticker WHERE type=? AND uri LIKE (? || '%') AND name=?",
66 static const char sticker_sql_create
[] =
67 "CREATE TABLE IF NOT EXISTS sticker("
68 " type VARCHAR NOT NULL, "
69 " uri VARCHAR NOT NULL, "
70 " name VARCHAR NOT NULL, "
71 " value VARCHAR NOT NULL"
73 "CREATE UNIQUE INDEX IF NOT EXISTS"
74 " sticker_value ON sticker(type, uri, name);"
77 static sqlite3
*sticker_db
;
78 static sqlite3_stmt
*sticker_stmt
[G_N_ELEMENTS(sticker_sql
)];
83 return g_quark_from_static_string("sticker");
87 sticker_prepare(const char *sql
, GError
**error_r
)
92 ret
= sqlite3_prepare_v2(sticker_db
, sql
, -1, &stmt
, NULL
);
93 if (ret
!= SQLITE_OK
) {
94 g_set_error(error_r
, sticker_quark(), ret
,
95 "sqlite3_prepare_v2() failed: %s",
96 sqlite3_errmsg(sticker_db
));
104 sticker_global_init(const char *path
, GError
**error_r
)
112 /* open/create the sqlite database */
114 ret
= sqlite3_open(path
, &sticker_db
);
115 if (ret
!= SQLITE_OK
) {
116 g_set_error(error_r
, sticker_quark(), ret
,
117 "Failed to open sqlite database '%s': %s",
118 path
, sqlite3_errmsg(sticker_db
));
122 /* create the table and index */
124 ret
= sqlite3_exec(sticker_db
, sticker_sql_create
, NULL
, NULL
, NULL
);
125 if (ret
!= SQLITE_OK
) {
126 g_set_error(error_r
, sticker_quark(), ret
,
127 "Failed to create sticker table: %s",
128 sqlite3_errmsg(sticker_db
));
132 /* prepare the statements we're going to use */
134 for (unsigned i
= 0; i
< G_N_ELEMENTS(sticker_sql
); ++i
) {
135 assert(sticker_sql
[i
] != NULL
);
137 sticker_stmt
[i
] = sticker_prepare(sticker_sql
[i
], error_r
);
138 if (sticker_stmt
[i
] == NULL
)
146 sticker_global_finish(void)
148 if (sticker_db
== NULL
)
152 for (unsigned i
= 0; i
< G_N_ELEMENTS(sticker_stmt
); ++i
) {
153 assert(sticker_stmt
[i
] != NULL
);
155 sqlite3_finalize(sticker_stmt
[i
]);
158 sqlite3_close(sticker_db
);
162 sticker_enabled(void)
164 return sticker_db
!= NULL
;
168 sticker_load_value(const char *type
, const char *uri
, const char *name
)
170 sqlite3_stmt
*const stmt
= sticker_stmt
[STICKER_SQL_GET
];
174 assert(sticker_enabled());
175 assert(type
!= NULL
);
177 assert(name
!= NULL
);
184 ret
= sqlite3_bind_text(stmt
, 1, type
, -1, NULL
);
185 if (ret
!= SQLITE_OK
) {
186 g_warning("sqlite3_bind_text() failed: %s",
187 sqlite3_errmsg(sticker_db
));
191 ret
= sqlite3_bind_text(stmt
, 2, uri
, -1, NULL
);
192 if (ret
!= SQLITE_OK
) {
193 g_warning("sqlite3_bind_text() failed: %s",
194 sqlite3_errmsg(sticker_db
));
198 ret
= sqlite3_bind_text(stmt
, 3, name
, -1, NULL
);
199 if (ret
!= SQLITE_OK
) {
200 g_warning("sqlite3_bind_text() failed: %s",
201 sqlite3_errmsg(sticker_db
));
206 ret
= sqlite3_step(stmt
);
207 } while (ret
== SQLITE_BUSY
);
209 if (ret
== SQLITE_ROW
) {
211 value
= g_strdup((const char*)sqlite3_column_text(stmt
, 0));
212 } else if (ret
== SQLITE_DONE
) {
213 /* no record found */
217 g_warning("sqlite3_step() failed: %s",
218 sqlite3_errmsg(sticker_db
));
223 sqlite3_clear_bindings(stmt
);
229 sticker_list_values(GHashTable
*hash
, const char *type
, const char *uri
)
231 sqlite3_stmt
*const stmt
= sticker_stmt
[STICKER_SQL_LIST
];
235 assert(hash
!= NULL
);
236 assert(type
!= NULL
);
238 assert(sticker_enabled());
242 ret
= sqlite3_bind_text(stmt
, 1, type
, -1, NULL
);
243 if (ret
!= SQLITE_OK
) {
244 g_warning("sqlite3_bind_text() failed: %s",
245 sqlite3_errmsg(sticker_db
));
249 ret
= sqlite3_bind_text(stmt
, 2, uri
, -1, NULL
);
250 if (ret
!= SQLITE_OK
) {
251 g_warning("sqlite3_bind_text() failed: %s",
252 sqlite3_errmsg(sticker_db
));
257 ret
= sqlite3_step(stmt
);
260 name
= g_strdup((const char*)sqlite3_column_text(stmt
, 0));
261 value
= g_strdup((const char*)sqlite3_column_text(stmt
, 1));
262 g_hash_table_insert(hash
, name
, value
);
270 g_warning("sqlite3_step() failed: %s",
271 sqlite3_errmsg(sticker_db
));
274 } while (ret
!= SQLITE_DONE
);
277 sqlite3_clear_bindings(stmt
);
283 sticker_update_value(const char *type
, const char *uri
,
284 const char *name
, const char *value
)
286 sqlite3_stmt
*const stmt
= sticker_stmt
[STICKER_SQL_UPDATE
];
289 assert(type
!= NULL
);
291 assert(name
!= NULL
);
293 assert(value
!= NULL
);
295 assert(sticker_enabled());
299 ret
= sqlite3_bind_text(stmt
, 1, value
, -1, NULL
);
300 if (ret
!= SQLITE_OK
) {
301 g_warning("sqlite3_bind_text() failed: %s",
302 sqlite3_errmsg(sticker_db
));
306 ret
= sqlite3_bind_text(stmt
, 2, type
, -1, NULL
);
307 if (ret
!= SQLITE_OK
) {
308 g_warning("sqlite3_bind_text() failed: %s",
309 sqlite3_errmsg(sticker_db
));
313 ret
= sqlite3_bind_text(stmt
, 3, uri
, -1, NULL
);
314 if (ret
!= SQLITE_OK
) {
315 g_warning("sqlite3_bind_text() failed: %s",
316 sqlite3_errmsg(sticker_db
));
320 ret
= sqlite3_bind_text(stmt
, 4, name
, -1, NULL
);
321 if (ret
!= SQLITE_OK
) {
322 g_warning("sqlite3_bind_text() failed: %s",
323 sqlite3_errmsg(sticker_db
));
328 ret
= sqlite3_step(stmt
);
329 } while (ret
== SQLITE_BUSY
);
331 if (ret
!= SQLITE_DONE
) {
332 g_warning("sqlite3_step() failed: %s",
333 sqlite3_errmsg(sticker_db
));
337 ret
= sqlite3_changes(sticker_db
);
340 sqlite3_clear_bindings(stmt
);
342 idle_add(IDLE_STICKER
);
347 sticker_insert_value(const char *type
, const char *uri
,
348 const char *name
, const char *value
)
350 sqlite3_stmt
*const stmt
= sticker_stmt
[STICKER_SQL_INSERT
];
353 assert(type
!= NULL
);
355 assert(name
!= NULL
);
357 assert(value
!= NULL
);
359 assert(sticker_enabled());
363 ret
= sqlite3_bind_text(stmt
, 1, type
, -1, NULL
);
364 if (ret
!= SQLITE_OK
) {
365 g_warning("sqlite3_bind_text() failed: %s",
366 sqlite3_errmsg(sticker_db
));
370 ret
= sqlite3_bind_text(stmt
, 2, uri
, -1, NULL
);
371 if (ret
!= SQLITE_OK
) {
372 g_warning("sqlite3_bind_text() failed: %s",
373 sqlite3_errmsg(sticker_db
));
377 ret
= sqlite3_bind_text(stmt
, 3, name
, -1, NULL
);
378 if (ret
!= SQLITE_OK
) {
379 g_warning("sqlite3_bind_text() failed: %s",
380 sqlite3_errmsg(sticker_db
));
384 ret
= sqlite3_bind_text(stmt
, 4, value
, -1, NULL
);
385 if (ret
!= SQLITE_OK
) {
386 g_warning("sqlite3_bind_text() failed: %s",
387 sqlite3_errmsg(sticker_db
));
392 ret
= sqlite3_step(stmt
);
393 } while (ret
== SQLITE_BUSY
);
395 if (ret
!= SQLITE_DONE
) {
396 g_warning("sqlite3_step() failed: %s",
397 sqlite3_errmsg(sticker_db
));
402 sqlite3_clear_bindings(stmt
);
405 idle_add(IDLE_STICKER
);
410 sticker_store_value(const char *type
, const char *uri
,
411 const char *name
, const char *value
)
413 assert(sticker_enabled());
414 assert(type
!= NULL
);
416 assert(name
!= NULL
);
417 assert(value
!= NULL
);
422 return sticker_update_value(type
, uri
, name
, value
) ||
423 sticker_insert_value(type
, uri
, name
, value
);
427 sticker_delete(const char *type
, const char *uri
)
429 sqlite3_stmt
*const stmt
= sticker_stmt
[STICKER_SQL_DELETE
];
432 assert(sticker_enabled());
433 assert(type
!= NULL
);
438 ret
= sqlite3_bind_text(stmt
, 1, type
, -1, NULL
);
439 if (ret
!= SQLITE_OK
) {
440 g_warning("sqlite3_bind_text() failed: %s",
441 sqlite3_errmsg(sticker_db
));
445 ret
= sqlite3_bind_text(stmt
, 2, uri
, -1, NULL
);
446 if (ret
!= SQLITE_OK
) {
447 g_warning("sqlite3_bind_text() failed: %s",
448 sqlite3_errmsg(sticker_db
));
453 ret
= sqlite3_step(stmt
);
454 } while (ret
== SQLITE_BUSY
);
456 if (ret
!= SQLITE_DONE
) {
457 g_warning("sqlite3_step() failed: %s",
458 sqlite3_errmsg(sticker_db
));
463 sqlite3_clear_bindings(stmt
);
465 idle_add(IDLE_STICKER
);
470 sticker_delete_value(const char *type
, const char *uri
, const char *name
)
472 sqlite3_stmt
*const stmt
= sticker_stmt
[STICKER_SQL_DELETE_VALUE
];
475 assert(sticker_enabled());
476 assert(type
!= NULL
);
481 ret
= sqlite3_bind_text(stmt
, 1, type
, -1, NULL
);
482 if (ret
!= SQLITE_OK
) {
483 g_warning("sqlite3_bind_text() failed: %s",
484 sqlite3_errmsg(sticker_db
));
488 ret
= sqlite3_bind_text(stmt
, 2, uri
, -1, NULL
);
489 if (ret
!= SQLITE_OK
) {
490 g_warning("sqlite3_bind_text() failed: %s",
491 sqlite3_errmsg(sticker_db
));
495 ret
= sqlite3_bind_text(stmt
, 3, name
, -1, NULL
);
496 if (ret
!= SQLITE_OK
) {
497 g_warning("sqlite3_bind_text() failed: %s",
498 sqlite3_errmsg(sticker_db
));
503 ret
= sqlite3_step(stmt
);
504 } while (ret
== SQLITE_BUSY
);
506 if (ret
!= SQLITE_DONE
) {
507 g_warning("sqlite3_step() failed: %s",
508 sqlite3_errmsg(sticker_db
));
512 ret
= sqlite3_changes(sticker_db
);
515 sqlite3_clear_bindings(stmt
);
517 idle_add(IDLE_STICKER
);
521 static struct sticker
*
524 struct sticker
*sticker
= g_new(struct sticker
, 1);
526 sticker
->table
= g_hash_table_new_full(g_str_hash
, g_str_equal
,
532 sticker_free(struct sticker
*sticker
)
534 assert(sticker
!= NULL
);
535 assert(sticker
->table
!= NULL
);
537 g_hash_table_destroy(sticker
->table
);
542 sticker_get_value(const struct sticker
*sticker
, const char *name
)
544 return g_hash_table_lookup(sticker
->table
, name
);
547 struct sticker_foreach_data
{
548 void (*func
)(const char *name
, const char *value
,
554 sticker_foreach_func(gpointer key
, gpointer value
, gpointer user_data
)
556 struct sticker_foreach_data
*data
= user_data
;
558 data
->func(key
, value
, data
->user_data
);
562 sticker_foreach(const struct sticker
*sticker
,
563 void (*func
)(const char *name
, const char *value
,
567 struct sticker_foreach_data data
= {
569 .user_data
= user_data
,
572 g_hash_table_foreach(sticker
->table
, sticker_foreach_func
, &data
);
576 sticker_load(const char *type
, const char *uri
)
578 struct sticker
*sticker
= sticker_new();
581 success
= sticker_list_values(sticker
->table
, type
, uri
);
585 if (g_hash_table_size(sticker
->table
) == 0) {
586 /* don't return empty sticker objects */
587 sticker_free(sticker
);
595 sticker_find(const char *type
, const char *base_uri
, const char *name
,
596 void (*func
)(const char *uri
, const char *value
,
600 sqlite3_stmt
*const stmt
= sticker_stmt
[STICKER_SQL_FIND
];
603 assert(type
!= NULL
);
604 assert(name
!= NULL
);
605 assert(func
!= NULL
);
606 assert(sticker_enabled());
610 ret
= sqlite3_bind_text(stmt
, 1, type
, -1, NULL
);
611 if (ret
!= SQLITE_OK
) {
612 g_warning("sqlite3_bind_text() failed: %s",
613 sqlite3_errmsg(sticker_db
));
617 if (base_uri
== NULL
)
620 ret
= sqlite3_bind_text(stmt
, 2, base_uri
, -1, NULL
);
621 if (ret
!= SQLITE_OK
) {
622 g_warning("sqlite3_bind_text() failed: %s",
623 sqlite3_errmsg(sticker_db
));
627 ret
= sqlite3_bind_text(stmt
, 3, name
, -1, NULL
);
628 if (ret
!= SQLITE_OK
) {
629 g_warning("sqlite3_bind_text() failed: %s",
630 sqlite3_errmsg(sticker_db
));
635 ret
= sqlite3_step(stmt
);
638 func((const char*)sqlite3_column_text(stmt
, 0),
639 (const char*)sqlite3_column_text(stmt
, 1),
648 g_warning("sqlite3_step() failed: %s",
649 sqlite3_errmsg(sticker_db
));
652 } while (ret
!= SQLITE_DONE
);
655 sqlite3_clear_bindings(stmt
);