zathura/database-sqlite.c

681 lines
20 KiB
C
Raw Normal View History

/* See LICENSE file for license and copyright information */
#include <sqlite3.h>
#include <girara/utils.h>
#include <girara/datastructures.h>
#include <girara/input-history.h>
#include <string.h>
#include "database-sqlite.h"
static void zathura_database_interface_init(ZathuraDatabaseInterface* iface);
static void io_interface_init(GiraraInputHistoryIOInterface* iface);
G_DEFINE_TYPE_WITH_CODE(ZathuraSQLDatabase, zathura_sqldatabase, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE(ZATHURA_TYPE_DATABASE, zathura_database_interface_init)
G_IMPLEMENT_INTERFACE(GIRARA_TYPE_INPUT_HISTORY_IO, io_interface_init))
static bool check_column(sqlite3* session, const char* table, const char* col, bool* result);
static void sqlite_finalize(GObject* object);
static bool sqlite_add_bookmark(zathura_database_t* db, const char* file, zathura_bookmark_t* bookmark);
static bool sqlite_remove_bookmark(zathura_database_t* db, const char* file, const char* id);
static girara_list_t* sqlite_load_bookmarks(zathura_database_t* db, const char* file);
static girara_list_t* sqlite_load_jumplist(zathura_database_t* db, const char* file);
static bool sqlite_save_jumplist(zathura_database_t* db, const char* file, girara_list_t* jumplist);
static bool sqlite_set_fileinfo(zathura_database_t* db, const char* file, zathura_fileinfo_t* file_info);
static bool sqlite_get_fileinfo(zathura_database_t* db, const char* file, zathura_fileinfo_t* file_info);
static void sqlite_set_property(GObject* object, guint prop_id, const GValue* value, GParamSpec* pspec);
static void sqlite_io_append(GiraraInputHistoryIO* db, const char*);
static girara_list_t* sqlite_io_read(GiraraInputHistoryIO* db);
typedef struct zathura_sqldatabase_private_s {
sqlite3* session;
} zathura_sqldatabase_private_t;
#define ZATHURA_SQLDATABASE_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), ZATHURA_TYPE_SQLDATABASE, zathura_sqldatabase_private_t))
2012-10-09 01:12:18 +02:00
enum {
PROP_0,
PROP_PATH
};
static void
zathura_database_interface_init(ZathuraDatabaseInterface* iface)
{
/* initialize interface */
2012-03-09 08:04:54 +01:00
iface->add_bookmark = sqlite_add_bookmark;
iface->remove_bookmark = sqlite_remove_bookmark;
2012-03-09 08:04:54 +01:00
iface->load_bookmarks = sqlite_load_bookmarks;
iface->load_jumplist = sqlite_load_jumplist;
iface->save_jumplist = sqlite_save_jumplist;
2012-03-09 08:04:54 +01:00
iface->set_fileinfo = sqlite_set_fileinfo;
iface->get_fileinfo = sqlite_get_fileinfo;
}
static void
io_interface_init(GiraraInputHistoryIOInterface* iface)
{
/* initialize interface */
iface->append = sqlite_io_append;
iface->read = sqlite_io_read;
}
static void
zathura_sqldatabase_class_init(ZathuraSQLDatabaseClass* class)
{
/* add private members */
g_type_class_add_private(class, sizeof(zathura_sqldatabase_private_t));
/* override methods */
GObjectClass* object_class = G_OBJECT_CLASS(class);
2012-03-09 08:04:54 +01:00
object_class->finalize = sqlite_finalize;
object_class->set_property = sqlite_set_property;
g_object_class_install_property(object_class, PROP_PATH,
g_param_spec_string("path", "path", "path to the database", NULL,
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
}
static void
zathura_sqldatabase_init(ZathuraSQLDatabase* db)
{
zathura_sqldatabase_private_t* priv = ZATHURA_SQLDATABASE_GET_PRIVATE(db);
priv->session = NULL;
}
zathura_database_t*
zathura_sqldatabase_new(const char* path)
{
g_return_val_if_fail(path != NULL && strlen(path) != 0, NULL);
zathura_database_t* db = g_object_new(ZATHURA_TYPE_SQLDATABASE, "path", path, NULL);
zathura_sqldatabase_private_t* priv = ZATHURA_SQLDATABASE_GET_PRIVATE(db);
if (priv->session == NULL) {
g_object_unref(G_OBJECT(db));
2011-10-16 23:01:25 +02:00
return NULL;
2011-10-11 15:59:36 +02:00
}
2012-03-09 08:04:54 +01:00
return db;
}
2011-10-11 15:59:36 +02:00
static void
sqlite_finalize(GObject* object)
{
ZathuraSQLDatabase* db = ZATHURA_SQLDATABASE(object);
zathura_sqldatabase_private_t* priv = ZATHURA_SQLDATABASE_GET_PRIVATE(db);
if (priv->session) {
sqlite3_close(priv->session);
2011-10-10 23:46:50 +02:00
}
G_OBJECT_CLASS(zathura_sqldatabase_parent_class)->finalize(object);
}
static void
sqlite_db_init(ZathuraSQLDatabase* db, const char* path)
{
zathura_sqldatabase_private_t* priv = ZATHURA_SQLDATABASE_GET_PRIVATE(db);
2011-09-29 15:23:13 +02:00
/* create bookmarks table */
static const char SQL_BOOKMARK_INIT[] =
"CREATE TABLE IF NOT EXISTS bookmarks ("
2012-10-09 01:12:18 +02:00
"file TEXT,"
"id TEXT,"
"page INTEGER,"
"hadj_ratio FLOAT,"
"vadj_ratio FLOAT,"
2012-10-09 01:12:18 +02:00
"PRIMARY KEY(file, id));";
static const char SQL_JUMPLIST_INIT[] =
"CREATE TABLE IF NOT EXISTS jumplist ("
"id INTEGER PRIMARY KEY AUTOINCREMENT,"
"file TEXT,"
"page INTEGER,"
"hadj_ratio FLOAT,"
"vadj_ratio FLOAT"
");";
/* create fileinfo table */
static const char SQL_FILEINFO_INIT[] =
"CREATE TABLE IF NOT EXISTS fileinfo ("
2012-10-09 01:12:18 +02:00
"file TEXT PRIMARY KEY,"
"page INTEGER,"
"offset INTEGER,"
"scale FLOAT,"
"rotation INTEGER,"
"pages_per_row INTEGER,"
"first_page_column INTEGER,"
"position_x FLOAT,"
"position_y FLOAT"
");";
/* create history table */
static const char SQL_HISTORY_INIT[] =
"CREATE TABLE IF NOT EXISTS history ("
"time TIMESTAMP,"
"line TEXT,"
"PRIMARY KEY(line));";
/* update fileinfo table (part 1) */
static const char SQL_FILEINFO_ALTER[] =
"ALTER TABLE fileinfo ADD COLUMN pages_per_row INTEGER;"
"ALTER TABLE fileinfo ADD COLUMN position_x FLOAT;"
"ALTER TABLE fileinfo ADD COLUMN position_y FLOAT;";
/* update fileinfo table (part 2) */
static const char SQL_FILEINFO_ALTER2[] =
"ALTER TABLE fileinfo ADD COLUMN first_page_column INTEGER;";
/* update bookmark table */
Bookmark the exact position, not just the page number (along with a number of fixes). This patch adds some enhancements/fixes to the bookmarking feature of Zathura: - Bookmark the exact vertical and horizontal adjustments values, along with the page number. This is done in a backward-compatible way for both the plain and sqlite database backends, so that bookmarks that was taken previously (bookmarking only the page number) will still work as expected and won't be lost. - Fix the issue of not being able to remove bookmarks from the plain database; removing a bookmark in plain_remove_bookmark using g_key_file_remove_key corrupts the bookmarks file. This is due to not truncating the entire bookmarks file in zathura_db_write_key_file_to_file prior to overriding it with a new one not containing the removed line. This is why, I guess, plain_remove_bookmark hadn't been implemented as expected using g_key_file_remove_key, because apparently, someone thought that the problem is caused by this API. - Fix not being able to update existing bookmarks persistently; updating a bookmark works only during the current session, but after the file is closed and reopened, the updated bookmark still has it's old value. This is due to changing only the bookmark structure in memory; the proper way to do it, is to call zathura_db_remove_bookmark on the old bookmark, then follow that by a call to zathura_db_add_bookmark on a bookmark structure containing the new position and the same old ID. - Make zathura_bookmark_add updates the bookmark if it already exists, rather than doing this externally in cmd_bookmark_create. This allows us to have all the relevant girara_notify messages in cmd_bookmark_create. Signed-off-by: Sebastian Ramacher <sebastian+dev@ramacher.at>
2013-06-21 06:12:12 +02:00
static const char SQL_BOOKMARK_ALTER[] =
"ALTER TABLE bookmarks ADD COLUMN hadj_ratio FLOAT;"
"ALTER TABLE bookmarks ADD COLUMN vadj_ratio FLOAT;";
sqlite3* session = NULL;
if (sqlite3_open(path, &session) != SQLITE_OK) {
girara_error("Could not open database: %s\n", path);
return;
}
/* create tables if they don't exist */
if (sqlite3_exec(session, SQL_BOOKMARK_INIT, NULL, 0, NULL) != SQLITE_OK) {
girara_error("Failed to initialize database: %s\n", path);
sqlite3_close(session);
return;
}
if (sqlite3_exec(session, SQL_JUMPLIST_INIT, NULL, 0, NULL) != SQLITE_OK) {
girara_error("Failed to initialize database: %s\n", path);
sqlite3_close(session);
return;
}
if (sqlite3_exec(session, SQL_FILEINFO_INIT, NULL, 0, NULL) != SQLITE_OK) {
girara_error("Failed to initialize database: %s\n", path);
sqlite3_close(session);
return;
}
if (sqlite3_exec(session, SQL_HISTORY_INIT, NULL, 0, NULL) != SQLITE_OK) {
girara_error("Failed to initialize database: %s\n", path);
sqlite3_close(session);
return;
}
/* check existing tables for missing columns */
bool res1, res2, ret1, ret2;
ret1 = check_column(session, "fileinfo", "pages_per_row", &res1);
if (ret1 == true && res1 == false) {
girara_debug("old database table layout detected; updating ...");
if (sqlite3_exec(session, SQL_FILEINFO_ALTER, NULL, 0, NULL) != SQLITE_OK) {
girara_warning("failed to update database table layout");
}
}
ret1 = check_column(session, "fileinfo", "first_page_column", &res1);
if (ret1 == true && res1 == false) {
girara_debug("old database table layout detected; updating ...");
if (sqlite3_exec(session, SQL_FILEINFO_ALTER2, NULL, 0, NULL) != SQLITE_OK) {
girara_warning("failed to update database table layout");
}
}
ret1 = check_column(session, "bookmarks", "hadj_ratio", &res1);
ret2 = check_column(session, "bookmarks", "vadj_ratio", &res2);
if (ret1 == true && ret2 == true && res1 == false && res2 == false) {
Bookmark the exact position, not just the page number (along with a number of fixes). This patch adds some enhancements/fixes to the bookmarking feature of Zathura: - Bookmark the exact vertical and horizontal adjustments values, along with the page number. This is done in a backward-compatible way for both the plain and sqlite database backends, so that bookmarks that was taken previously (bookmarking only the page number) will still work as expected and won't be lost. - Fix the issue of not being able to remove bookmarks from the plain database; removing a bookmark in plain_remove_bookmark using g_key_file_remove_key corrupts the bookmarks file. This is due to not truncating the entire bookmarks file in zathura_db_write_key_file_to_file prior to overriding it with a new one not containing the removed line. This is why, I guess, plain_remove_bookmark hadn't been implemented as expected using g_key_file_remove_key, because apparently, someone thought that the problem is caused by this API. - Fix not being able to update existing bookmarks persistently; updating a bookmark works only during the current session, but after the file is closed and reopened, the updated bookmark still has it's old value. This is due to changing only the bookmark structure in memory; the proper way to do it, is to call zathura_db_remove_bookmark on the old bookmark, then follow that by a call to zathura_db_add_bookmark on a bookmark structure containing the new position and the same old ID. - Make zathura_bookmark_add updates the bookmark if it already exists, rather than doing this externally in cmd_bookmark_create. This allows us to have all the relevant girara_notify messages in cmd_bookmark_create. Signed-off-by: Sebastian Ramacher <sebastian+dev@ramacher.at>
2013-06-21 06:12:12 +02:00
girara_debug("old database table layout detected; updating ...");
if (sqlite3_exec(session, SQL_BOOKMARK_ALTER, NULL, 0, NULL) != SQLITE_OK) {
girara_warning("failed to update database table layout");
}
}
priv->session = session;
}
static void
sqlite_set_property(GObject* object, guint prop_id, const GValue* value, GParamSpec* pspec)
{
ZathuraSQLDatabase* db = ZATHURA_SQLDATABASE(object);
zathura_sqldatabase_private_t* priv = ZATHURA_SQLDATABASE_GET_PRIVATE(db);
switch (prop_id) {
case PROP_PATH:
g_return_if_fail(priv->session == NULL);
sqlite_db_init(db, g_value_get_string(value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
2011-10-10 23:46:50 +02:00
}
}
static sqlite3_stmt*
prepare_statement(sqlite3* session, const char* statement)
{
if (session == NULL || statement == NULL) {
return NULL;
}
const char* pz_tail = NULL;
sqlite3_stmt* pp_stmt = NULL;
2011-10-15 18:26:04 +02:00
if (sqlite3_prepare_v2(session, statement, -1, &pp_stmt, &pz_tail) != SQLITE_OK) {
girara_error("Failed to prepare query: %s", statement);
sqlite3_finalize(pp_stmt);
return NULL;
} else if (pz_tail && *pz_tail != '\0') {
girara_error("Unused portion of statement: %s", pz_tail);
sqlite3_finalize(pp_stmt);
return NULL;
}
return pp_stmt;
}
static bool
check_column(sqlite3* session, const char* table, const char* col, bool* res)
{
/* we can't actually bind the argument with sqlite3_bind_text because
* sqlite3_prepare_v2 fails with "PRAGMA table_info(?);" */
char* query = sqlite3_mprintf("PRAGMA table_info(%Q);", table);
if (query == NULL) {
return false;
}
sqlite3_stmt* stmt = prepare_statement(session, query);
if (stmt == NULL) {
return false;
}
*res = false;
while (sqlite3_step(stmt) == SQLITE_ROW) {
if (strcmp((const char*) sqlite3_column_text(stmt, 1), col) == 0) {
*res = true;
break;
}
}
if (*res == false) {
girara_debug("column %s in table %s is NOT found", col, table);
}
sqlite3_finalize(stmt);
sqlite3_free(query);
return true;
}
static bool
sqlite_add_bookmark(zathura_database_t* db, const char* file,
2012-10-09 01:12:18 +02:00
zathura_bookmark_t* bookmark)
{
zathura_sqldatabase_private_t* priv = ZATHURA_SQLDATABASE_GET_PRIVATE(db);
static const char SQL_BOOKMARK_ADD[] =
Bookmark the exact position, not just the page number (along with a number of fixes). This patch adds some enhancements/fixes to the bookmarking feature of Zathura: - Bookmark the exact vertical and horizontal adjustments values, along with the page number. This is done in a backward-compatible way for both the plain and sqlite database backends, so that bookmarks that was taken previously (bookmarking only the page number) will still work as expected and won't be lost. - Fix the issue of not being able to remove bookmarks from the plain database; removing a bookmark in plain_remove_bookmark using g_key_file_remove_key corrupts the bookmarks file. This is due to not truncating the entire bookmarks file in zathura_db_write_key_file_to_file prior to overriding it with a new one not containing the removed line. This is why, I guess, plain_remove_bookmark hadn't been implemented as expected using g_key_file_remove_key, because apparently, someone thought that the problem is caused by this API. - Fix not being able to update existing bookmarks persistently; updating a bookmark works only during the current session, but after the file is closed and reopened, the updated bookmark still has it's old value. This is due to changing only the bookmark structure in memory; the proper way to do it, is to call zathura_db_remove_bookmark on the old bookmark, then follow that by a call to zathura_db_add_bookmark on a bookmark structure containing the new position and the same old ID. - Make zathura_bookmark_add updates the bookmark if it already exists, rather than doing this externally in cmd_bookmark_create. This allows us to have all the relevant girara_notify messages in cmd_bookmark_create. Signed-off-by: Sebastian Ramacher <sebastian+dev@ramacher.at>
2013-06-21 06:12:12 +02:00
"REPLACE INTO bookmarks (file, id, page, hadj_ratio, vadj_ratio) VALUES (?, ?, ?, ?, ?);";
sqlite3_stmt* stmt = prepare_statement(priv->session, SQL_BOOKMARK_ADD);
if (stmt == NULL) {
return false;
}
if (sqlite3_bind_text(stmt, 1, file, -1, NULL) != SQLITE_OK ||
sqlite3_bind_text(stmt, 2, bookmark->id, -1, NULL) != SQLITE_OK ||
Bookmark the exact position, not just the page number (along with a number of fixes). This patch adds some enhancements/fixes to the bookmarking feature of Zathura: - Bookmark the exact vertical and horizontal adjustments values, along with the page number. This is done in a backward-compatible way for both the plain and sqlite database backends, so that bookmarks that was taken previously (bookmarking only the page number) will still work as expected and won't be lost. - Fix the issue of not being able to remove bookmarks from the plain database; removing a bookmark in plain_remove_bookmark using g_key_file_remove_key corrupts the bookmarks file. This is due to not truncating the entire bookmarks file in zathura_db_write_key_file_to_file prior to overriding it with a new one not containing the removed line. This is why, I guess, plain_remove_bookmark hadn't been implemented as expected using g_key_file_remove_key, because apparently, someone thought that the problem is caused by this API. - Fix not being able to update existing bookmarks persistently; updating a bookmark works only during the current session, but after the file is closed and reopened, the updated bookmark still has it's old value. This is due to changing only the bookmark structure in memory; the proper way to do it, is to call zathura_db_remove_bookmark on the old bookmark, then follow that by a call to zathura_db_add_bookmark on a bookmark structure containing the new position and the same old ID. - Make zathura_bookmark_add updates the bookmark if it already exists, rather than doing this externally in cmd_bookmark_create. This allows us to have all the relevant girara_notify messages in cmd_bookmark_create. Signed-off-by: Sebastian Ramacher <sebastian+dev@ramacher.at>
2013-06-21 06:12:12 +02:00
sqlite3_bind_int(stmt, 3, bookmark->page) != SQLITE_OK ||
sqlite3_bind_double(stmt, 4, bookmark->x) != SQLITE_OK ||
sqlite3_bind_double(stmt, 5, bookmark->y) != SQLITE_OK) {
sqlite3_finalize(stmt);
girara_error("Failed to bind arguments.");
return false;
}
int res = sqlite3_step(stmt);
sqlite3_finalize(stmt);
2012-03-09 08:04:54 +01:00
return (res == SQLITE_DONE) ? true : false;
}
static bool
sqlite_remove_bookmark(zathura_database_t* db, const char* file, const char*
2012-10-09 01:12:18 +02:00
id)
{
zathura_sqldatabase_private_t* priv = ZATHURA_SQLDATABASE_GET_PRIVATE(db);
static const char SQL_BOOKMARK_ADD[] =
2011-10-15 18:26:04 +02:00
"DELETE FROM bookmarks WHERE file = ? AND id = ?;";
sqlite3_stmt* stmt = prepare_statement(priv->session, SQL_BOOKMARK_ADD);
if (stmt == NULL) {
return false;
}
if (sqlite3_bind_text(stmt, 1, file, -1, NULL) != SQLITE_OK ||
sqlite3_bind_text(stmt, 2, id, -1, NULL) != SQLITE_OK) {
sqlite3_finalize(stmt);
girara_error("Failed to bind arguments.");
return false;
}
int res = sqlite3_step(stmt);
sqlite3_finalize(stmt);
2012-03-09 08:04:54 +01:00
return (res == SQLITE_DONE) ? true : false;
}
static girara_list_t*
sqlite_load_bookmarks(zathura_database_t* db, const char* file)
{
zathura_sqldatabase_private_t* priv = ZATHURA_SQLDATABASE_GET_PRIVATE(db);
static const char SQL_BOOKMARK_SELECT[] =
Bookmark the exact position, not just the page number (along with a number of fixes). This patch adds some enhancements/fixes to the bookmarking feature of Zathura: - Bookmark the exact vertical and horizontal adjustments values, along with the page number. This is done in a backward-compatible way for both the plain and sqlite database backends, so that bookmarks that was taken previously (bookmarking only the page number) will still work as expected and won't be lost. - Fix the issue of not being able to remove bookmarks from the plain database; removing a bookmark in plain_remove_bookmark using g_key_file_remove_key corrupts the bookmarks file. This is due to not truncating the entire bookmarks file in zathura_db_write_key_file_to_file prior to overriding it with a new one not containing the removed line. This is why, I guess, plain_remove_bookmark hadn't been implemented as expected using g_key_file_remove_key, because apparently, someone thought that the problem is caused by this API. - Fix not being able to update existing bookmarks persistently; updating a bookmark works only during the current session, but after the file is closed and reopened, the updated bookmark still has it's old value. This is due to changing only the bookmark structure in memory; the proper way to do it, is to call zathura_db_remove_bookmark on the old bookmark, then follow that by a call to zathura_db_add_bookmark on a bookmark structure containing the new position and the same old ID. - Make zathura_bookmark_add updates the bookmark if it already exists, rather than doing this externally in cmd_bookmark_create. This allows us to have all the relevant girara_notify messages in cmd_bookmark_create. Signed-off-by: Sebastian Ramacher <sebastian+dev@ramacher.at>
2013-06-21 06:12:12 +02:00
"SELECT id, page, hadj_ratio, vadj_ratio FROM bookmarks WHERE file = ?;";
sqlite3_stmt* stmt = prepare_statement(priv->session, SQL_BOOKMARK_SELECT);
if (stmt == NULL) {
return NULL;
}
if (sqlite3_bind_text(stmt, 1, file, -1, NULL) != SQLITE_OK) {
sqlite3_finalize(stmt);
girara_error("Failed to bind arguments.");
return NULL;
}
2011-10-15 18:42:30 +02:00
girara_list_t* result = girara_sorted_list_new2((girara_compare_function_t) zathura_bookmarks_compare,
2012-10-09 01:12:18 +02:00
(girara_free_function_t) zathura_bookmark_free);
2012-03-09 08:04:54 +01:00
while (sqlite3_step(stmt) == SQLITE_ROW) {
zathura_bookmark_t* bookmark = g_try_malloc0(sizeof(zathura_bookmark_t));
if (bookmark == NULL) {
continue;
}
2011-10-11 23:18:21 +02:00
bookmark->id = g_strdup((const char*) sqlite3_column_text(stmt, 0));
bookmark->page = sqlite3_column_int(stmt, 1);
Bookmark the exact position, not just the page number (along with a number of fixes). This patch adds some enhancements/fixes to the bookmarking feature of Zathura: - Bookmark the exact vertical and horizontal adjustments values, along with the page number. This is done in a backward-compatible way for both the plain and sqlite database backends, so that bookmarks that was taken previously (bookmarking only the page number) will still work as expected and won't be lost. - Fix the issue of not being able to remove bookmarks from the plain database; removing a bookmark in plain_remove_bookmark using g_key_file_remove_key corrupts the bookmarks file. This is due to not truncating the entire bookmarks file in zathura_db_write_key_file_to_file prior to overriding it with a new one not containing the removed line. This is why, I guess, plain_remove_bookmark hadn't been implemented as expected using g_key_file_remove_key, because apparently, someone thought that the problem is caused by this API. - Fix not being able to update existing bookmarks persistently; updating a bookmark works only during the current session, but after the file is closed and reopened, the updated bookmark still has it's old value. This is due to changing only the bookmark structure in memory; the proper way to do it, is to call zathura_db_remove_bookmark on the old bookmark, then follow that by a call to zathura_db_add_bookmark on a bookmark structure containing the new position and the same old ID. - Make zathura_bookmark_add updates the bookmark if it already exists, rather than doing this externally in cmd_bookmark_create. This allows us to have all the relevant girara_notify messages in cmd_bookmark_create. Signed-off-by: Sebastian Ramacher <sebastian+dev@ramacher.at>
2013-06-21 06:12:12 +02:00
bookmark->x = sqlite3_column_double(stmt, 2);
bookmark->y = sqlite3_column_double(stmt, 3);
if (bookmark->page > 1) {
bookmark->x = bookmark->x == 0.0 ? DBL_MIN : bookmark->x;
bookmark->y = bookmark->y == 0.0 ? DBL_MIN : bookmark->y;
}
2011-09-29 15:23:13 +02:00
girara_list_append(result, bookmark);
}
2012-03-09 08:04:54 +01:00
sqlite3_finalize(stmt);
2012-03-09 08:04:54 +01:00
return result;
}
static bool
sqlite_save_jumplist(zathura_database_t* db, const char* file, girara_list_t* jumplist)
{
g_return_val_if_fail(db != NULL && file != NULL && jumplist != NULL, false);
zathura_sqldatabase_private_t* priv = ZATHURA_SQLDATABASE_GET_PRIVATE(db);
static const char SQL_INSERT_JUMP[] = "INSERT INTO jumplist (file, page, hadj_ratio, vadj_ratio) VALUES (?, ?, ?, ?);";
static const char SQL_REMOVE_JUMPLIST[] = "DELETE FROM jumplist WHERE file = ?;";
sqlite3_stmt* stmt = NULL;
int res = 0;
if (sqlite3_exec(priv->session, "BEGIN;", NULL, 0, NULL) != SQLITE_OK) {
return false;
}
stmt = prepare_statement(priv->session, SQL_REMOVE_JUMPLIST);
if (stmt == NULL) {
sqlite3_exec(priv->session, "ROLLBACK;", NULL, 0, NULL);
return false;
}
if (sqlite3_bind_text(stmt, 1, file, -1, NULL) != SQLITE_OK) {
sqlite3_finalize(stmt);
sqlite3_exec(priv->session, "ROLLBACK;", NULL, 0, NULL);
girara_error("Failed to bind arguments.");
return false;
}
res = sqlite3_step(stmt);
sqlite3_finalize(stmt);
if (res != SQLITE_DONE) {
sqlite3_exec(priv->session, "ROLLBACK;", NULL, 0, NULL);
return false;
}
if (girara_list_size(jumplist) == 0) {
sqlite3_exec(priv->session, "COMMIT;", NULL, 0, NULL);
return true;
}
girara_list_iterator_t* cur = girara_list_iterator(jumplist);
bool status = true;
while (true) {
zathura_jump_t* jump = girara_list_iterator_data(cur);
stmt = prepare_statement(priv->session, SQL_INSERT_JUMP);
if (stmt == NULL) {
status = false;
break;
}
if (sqlite3_bind_text(stmt, 1, file, -1, NULL) != SQLITE_OK ||
sqlite3_bind_int(stmt, 2, jump->page) != SQLITE_OK ||
sqlite3_bind_double(stmt, 3, jump->x) != SQLITE_OK ||
sqlite3_bind_double(stmt, 4, jump->y) != SQLITE_OK) {
sqlite3_finalize(stmt);
girara_error("Failed to bind arguments.");
status = false;
break;
}
res = sqlite3_step(stmt);
sqlite3_finalize(stmt);
if (res != SQLITE_DONE) {
status = false;
break;
}
if (girara_list_iterator_has_next(cur) == true) {
girara_list_iterator_next(cur);
} else {
break;
}
}
if (status == false) {
sqlite3_exec(priv->session, "ROLLBACK;", NULL, 0, NULL);
return false;
} else {
sqlite3_exec(priv->session, "COMMIT;", NULL, 0, NULL);
return true;
}
}
static girara_list_t*
sqlite_load_jumplist(zathura_database_t* db, const char* file)
{
g_return_val_if_fail(db != NULL && file != NULL, NULL);
zathura_sqldatabase_private_t* priv = ZATHURA_SQLDATABASE_GET_PRIVATE(db);
static const char SQL_GET_JUMPLIST[] = "SELECT page, hadj_ratio, vadj_ratio FROM jumplist WHERE file = ? ORDER BY id ASC;";
sqlite3_stmt* stmt = prepare_statement(priv->session, SQL_GET_JUMPLIST);
if (stmt == NULL) {
return NULL;
}
if (sqlite3_bind_text(stmt, 1, file, -1, NULL) != SQLITE_OK) {
sqlite3_finalize(stmt);
girara_error("Failed to bind arguments.");
return NULL;
}
girara_list_t* jumplist = girara_list_new2(g_free);
int res = 0;
while ((res = sqlite3_step(stmt)) == SQLITE_ROW) {
zathura_jump_t* jump = g_try_malloc0(sizeof(zathura_jump_t));
if (jump == NULL) {
continue;
}
jump->page = sqlite3_column_int(stmt, 0);
jump->x = sqlite3_column_double(stmt, 1);
jump->y = sqlite3_column_double(stmt, 2);
girara_list_append(jumplist, jump);
}
sqlite3_finalize(stmt);
if (res != SQLITE_DONE) {
girara_list_free(jumplist);
return NULL;
}
return jumplist;
}
static bool
sqlite_set_fileinfo(zathura_database_t* db, const char* file,
2012-10-09 01:12:18 +02:00
zathura_fileinfo_t* file_info)
{
if (db == NULL || file == NULL || file_info == NULL) {
2012-04-22 10:04:46 +02:00
return false;
}
zathura_sqldatabase_private_t* priv = ZATHURA_SQLDATABASE_GET_PRIVATE(db);
static const char SQL_FILEINFO_SET[] =
"REPLACE INTO fileinfo (file, page, offset, scale, rotation, pages_per_row, first_page_column, position_x, position_y) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?);";
sqlite3_stmt* stmt = prepare_statement(priv->session, SQL_FILEINFO_SET);
if (stmt == NULL) {
return false;
}
if (sqlite3_bind_text(stmt, 1, file, -1, NULL) != SQLITE_OK ||
sqlite3_bind_int(stmt, 2, file_info->current_page) != SQLITE_OK ||
sqlite3_bind_int(stmt, 3, file_info->page_offset) != SQLITE_OK ||
sqlite3_bind_double(stmt, 4, file_info->scale) != SQLITE_OK ||
sqlite3_bind_int(stmt, 5, file_info->rotation) != SQLITE_OK ||
sqlite3_bind_int(stmt, 6, file_info->pages_per_row) != SQLITE_OK ||
sqlite3_bind_int(stmt, 7, file_info->first_page_column) != SQLITE_OK ||
sqlite3_bind_double(stmt, 8, file_info->position_x) != SQLITE_OK ||
sqlite3_bind_double(stmt, 9, file_info->position_y) != SQLITE_OK) {
sqlite3_finalize(stmt);
girara_error("Failed to bind arguments.");
return false;
}
int res = sqlite3_step(stmt);
sqlite3_finalize(stmt);
2012-03-09 08:04:54 +01:00
return (res == SQLITE_DONE) ? true : false;
}
2011-09-22 15:47:58 +02:00
static bool
sqlite_get_fileinfo(zathura_database_t* db, const char* file,
2012-10-09 01:12:18 +02:00
zathura_fileinfo_t* file_info)
2011-09-22 15:47:58 +02:00
{
2012-04-22 10:04:46 +02:00
if (db == NULL || file == NULL || file_info == NULL) {
return false;
}
zathura_sqldatabase_private_t* priv = ZATHURA_SQLDATABASE_GET_PRIVATE(db);
2011-09-22 15:47:58 +02:00
static const char SQL_FILEINFO_GET[] =
"SELECT page, offset, scale, rotation, pages_per_row, first_page_column, position_x, position_y FROM fileinfo WHERE file = ?;";
2011-09-22 15:47:58 +02:00
sqlite3_stmt* stmt = prepare_statement(priv->session, SQL_FILEINFO_GET);
2011-09-22 15:47:58 +02:00
if (stmt == NULL) {
2012-04-22 10:04:46 +02:00
return false;
2011-09-22 15:47:58 +02:00
}
2011-09-29 11:46:52 +02:00
if (sqlite3_bind_text(stmt, 1, file, -1, NULL) != SQLITE_OK) {
2011-09-22 15:47:58 +02:00
sqlite3_finalize(stmt);
girara_error("Failed to bind arguments.");
return false;
}
if (sqlite3_step(stmt) != SQLITE_ROW) {
sqlite3_finalize(stmt);
girara_info("No info for file %s available.", file);
return false;
}
file_info->current_page = sqlite3_column_int(stmt, 0);
file_info->page_offset = sqlite3_column_int(stmt, 1);
file_info->scale = sqlite3_column_double(stmt, 2);
file_info->rotation = sqlite3_column_int(stmt, 3);
file_info->pages_per_row = sqlite3_column_int(stmt, 4);
file_info->first_page_column = sqlite3_column_int(stmt, 5);
file_info->position_x = sqlite3_column_double(stmt, 6);
file_info->position_y = sqlite3_column_double(stmt, 7);
2011-09-22 15:47:58 +02:00
sqlite3_finalize(stmt);
2012-03-09 08:04:54 +01:00
2011-09-22 15:47:58 +02:00
return true;
}
static void
sqlite_io_append(GiraraInputHistoryIO* db, const char* input)
{
static const char SQL_HISTORY_SET[] =
"REPLACE INTO history (line, time) VALUES (?, DATETIME('now'));";
zathura_sqldatabase_private_t* priv = ZATHURA_SQLDATABASE_GET_PRIVATE(db);
sqlite3_stmt* stmt = prepare_statement(priv->session, SQL_HISTORY_SET);
if (stmt == NULL) {
return;
}
if (sqlite3_bind_text(stmt, 1, input, -1, NULL) != SQLITE_OK) {
sqlite3_finalize(stmt);
girara_error("Failed to bind arguments.");
return;
}
sqlite3_step(stmt);
sqlite3_finalize(stmt);
}
static girara_list_t*
sqlite_io_read(GiraraInputHistoryIO* db)
{
static const char SQL_HISTORY_GET[] =
"SELECT line FROM history ORDER BY time";
zathura_sqldatabase_private_t* priv = ZATHURA_SQLDATABASE_GET_PRIVATE(db);
sqlite3_stmt* stmt = prepare_statement(priv->session, SQL_HISTORY_GET);
if (stmt == NULL) {
return NULL;
}
girara_list_t* list = girara_list_new2((girara_free_function_t) g_free);
if (list == NULL) {
sqlite3_finalize(stmt);
return NULL;
}
while (sqlite3_step(stmt) == SQLITE_ROW) {
girara_list_append(list, g_strdup((const char*) sqlite3_column_text(stmt, 0)));
}
sqlite3_finalize(stmt);
return list;
}