#include "config.h"
#include <errno.h>
#include <glib.h>
#include <limits.h>
#include <libgen.h>
#include <sqlite3.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#include "ermetadb_log.h"
#include "ermetadb.h"
#include "ermetadb_error.h"
#include "ermetadb_private.h"
#include "sqlite3_wrapper.h"
Go to the source code of this file.
Defines | |
#define | DATABASE_VERSION_MAJOR 0 |
#define | DATABASE_VERSION_MINOR 6 |
#define | MAX_COLUMNS 17 |
Functions | |
static gboolean | update_version_number (sqlite3 *db, int major, int minor) |
static void | convert_database_01_06 (erMetadb thiz, int *minor) |
static int | add_file_ids (sqlite3 *db, GSList **list, const char *table_name) |
static const char * | get_filename_from_results (const metadata_table *table, int id) |
static void | convert_database_05_06 (erMetadb thiz, int *minor) |
static int | convert_database (erMetadb thiz, const int v_major, const int v_minor) |
static int | check_database_version (erMetadb thiz) |
static int | check_global_database_tables (erMetadb thiz) |
static int | check_global_database_columns (erMetadb thiz) |
static int | check_global_database_consistency (erMetadb thiz) |
static int | check_local_database_consistency (erMetadb thiz) |
static int | open_sqlite_database (const gchar *filename, gboolean do_open_readonly, sqlite3 **database) |
static int | check_database (erMetadb thiz) |
static int | open_sql_database (erMetadb thiz, const char *filename) |
static int | create_db (erMetadb thiz, const char *filename) |
static erMetadb | database_open (const gchar *folder, const gchar *filename, gboolean global, gboolean readonly, gboolean create) |
erMetadb | ermetadb_global_open (const gchar *folder, gboolean readonly) |
opens a global metadata database | |
erMetadb | ermetadb_local_open (const gchar *folder, gboolean create) |
opens a local metadata database | |
erMetadb | ermetadb_local_open_custom (const gchar *folder, const gchar *filename) |
opens a local metadata database with specified name | |
const gchar * | ermetadb_get_dir (erMetadb thiz) |
returns path where database was openened | |
void | ermetadb_close (erMetadb thiz) |
Close and free a metadata database. | |
static int | create_database (const char *source_name, const char *target_dir, const char *target_name) |
int | ermetadb_global_create_database (const gchar *folder) |
Create a new global metadata database, overwriting the existing database if present. | |
int | ermetadb_local_create_database (const gchar *folder, const gchar *filename) |
const char *const * | ermetadb_private_get_global_column_names (const char *table) |
Get column names for a specified SQL table name. | |
int | ermetadb_begin_transaction (erMetadb thiz) |
Start a database transaction Only a single transaction is allowed, as seen from the application. | |
int | ermetadb_begin_transaction_readonly (erMetadb thiz) |
Start a read-only database transaction Only a single transaction is allowed, as seen from the application. | |
int | ermetadb_end_transaction (erMetadb thiz) |
Commit or rollback a database transaction Only a single transaction is allowed, as seen from the application. Library decides whether to commit or to rollback the changes. Basically when any query during this transaction has failed, the entire transaction is rolled back, otherwise the transaction is committed. Superfluous calls to ermetadb_end_transaction are ignored. | |
Variables | |
struct { | |
const char * table_name | |
const char * column_names [MAX_COLUMNS+1] | |
} | global_database_tables [] |
#define DATABASE_VERSION_MAJOR 0 |
Copyright (C) 2008 iRex Technologies B.V. All rights reserved.
Definition at line 55 of file ermetadb.c.
Referenced by check_database_version(), and convert_database().
#define DATABASE_VERSION_MINOR 6 |
Definition at line 56 of file ermetadb.c.
Referenced by check_database_version(), and convert_database().
#define MAX_COLUMNS 17 |
Definition at line 58 of file ermetadb.c.
static int add_file_ids | ( | sqlite3 * | db, | |
GSList ** | list, | |||
const char * | table_name | |||
) | [static] |
Definition at line 248 of file ermetadb.c.
References ER_OK, ERRORPRINTF, METADATA_INT64, metadata_table_free, metadata_table_get_cell(), metadata_table_n_rows, sql3_execute_query(), metadata_cell::type, metadata_cell::v_int64, and metadata_cell::value.
Referenced by convert_database_05_06().
00249 { 00250 char sql[255]; 00251 sprintf(sql, "SELECT DISTINCT file_id FROM %s;", table_name); 00252 metadata_table *result = NULL; 00253 int rc = sql3_execute_query(db, sql, NULL, &result); 00254 if (rc != ER_OK) { 00255 ERRORPRINTF("cannot read file_id's for %s", table_name); 00256 return rc; 00257 } 00258 int n_rows = metadata_table_n_rows(result); 00259 int row; 00260 for (row=0; row<n_rows; row++) { 00261 const metadata_cell *cell = metadata_table_get_cell(result, row); 00262 if (cell->type != METADATA_INT64) { 00263 ERRORPRINTF("invalid data type for file_id [%d]", cell->type); 00264 } else { 00265 int id = cell->value.v_int64; 00266 GSList *found = g_slist_find(*list, (gpointer)id); 00267 if (found == NULL) { 00268 *list = g_slist_append(*list, (gpointer)id); 00269 } 00270 } 00271 } 00272 metadata_table_free(result); 00273 return ER_OK; 00274 }
static int check_database | ( | erMetadb | thiz | ) | [static] |
Definition at line 693 of file ermetadb.c.
References check_global_database_consistency(), and check_local_database_consistency().
Referenced by open_sql_database().
00694 { 00695 if (thiz->is_global) 00696 return check_global_database_consistency(thiz); 00697 else 00698 return check_local_database_consistency(thiz); 00699 }
static int check_database_version | ( | erMetadb | thiz | ) | [static] |
Definition at line 420 of file ermetadb.c.
References convert_database(), DATABASE_VERSION_MAJOR, DATABASE_VERSION_MINOR, ER_OK, ERMETADB_DATABASE_STRUCTURE, ERRORPRINTF, METADATA_INT64, metadata_table_free, metadata_table_get_cell(), sql3_execute_query(), TRACE, metadata_cell::type, metadata_cell::v_int64, and metadata_cell::value.
Referenced by check_global_database_consistency(), and check_local_database_consistency().
00421 { 00422 TRACE("entry: db [%p] global=%d", thiz->database, thiz->is_global); 00423 g_assert(thiz->database); 00424 00425 int ret = ER_OK; 00426 // get current database version 00427 const char* sql = "SELECT version_major, version_minor FROM database_properties;"; 00428 metadata_table *result = NULL; 00429 int rc = sql3_execute_query(thiz->database, sql, NULL, &result); 00430 if (rc != ER_OK) 00431 { 00432 ERRORPRINTF("cannot get version from database"); 00433 ret = rc; 00434 goto out; 00435 } 00436 00437 // extract version numbers 00438 const metadata_cell *cell = metadata_table_get_cell(result, 0); 00439 if (cell->type != METADATA_INT64) 00440 { 00441 ERRORPRINTF("invalid data type database version major [%d]", cell->type); 00442 ret = ERMETADB_DATABASE_STRUCTURE; 00443 goto out; 00444 } 00445 int v_major = cell->value.v_int64; 00446 00447 cell = metadata_table_get_cell(result, 1); 00448 if (cell->type != METADATA_INT64) 00449 { 00450 ERRORPRINTF("invalid data type database version minor [%d]", cell->type); 00451 ret = ERMETADB_DATABASE_STRUCTURE; 00452 goto out; 00453 } 00454 int v_minor = cell->value.v_int64; 00455 00456 // check database version 00457 if (v_major > DATABASE_VERSION_MAJOR) 00458 { 00459 ERRORPRINTF("incompatible database version [%d.%d]", v_major, v_minor); 00460 ret = ERMETADB_DATABASE_STRUCTURE; 00461 goto out; 00462 } 00463 if (v_major != DATABASE_VERSION_MAJOR || v_minor != DATABASE_VERSION_MINOR ) 00464 { 00465 ret = convert_database(thiz, v_major, v_minor); 00466 } 00467 00468 out: 00469 metadata_table_free(result); 00470 return ret; 00471 }
static int check_global_database_columns | ( | erMetadb | thiz | ) | [static] |
Definition at line 533 of file ermetadb.c.
References ER_OK, ERMETADB_DATABASE_STRUCTURE, ERMETADB_FAIL, ERRORPRINTF, global_database_tables, metadata_table_cell_index, metadata_table_find_column(), metadata_table_free, metadata_table_get_string(), metadata_table_n_rows, name, sql3_execute_query(), table_name, and TRACE.
Referenced by check_global_database_consistency().
00534 { 00535 TRACE("entry: thiz [%p]", thiz); 00536 g_assert(thiz->database); 00537 g_assert(thiz->is_global); 00538 00539 // for each table expected 00540 int ret = ER_OK; 00541 int tbl; 00542 for ( tbl = 0 ; global_database_tables[tbl].table_name && ret == ER_OK ; tbl++ ) 00543 { 00544 const char* table_name = global_database_tables[tbl].table_name; 00545 int n_columns = 0; 00546 int col; 00547 metadata_table *result = NULL; 00548 00549 // get column names from database 00550 GString *sql = g_string_new(""); 00551 g_string_printf( sql, "PRAGMA table_info(%s);", table_name ); 00552 ret = sql3_execute_query(thiz->database, sql->str, NULL, &result); 00553 g_string_free(sql, TRUE); 00554 if (ret == ER_OK) 00555 { 00556 n_columns = metadata_table_n_rows(result); 00557 col = metadata_table_find_column(result, "name"); 00558 if (col < 0) 00559 { 00560 ERRORPRINTF("No 'names' column in result"); 00561 ret = ERMETADB_FAIL; 00562 } 00563 } 00564 00565 // check column names 00566 if (ret == ER_OK) 00567 { 00568 // find column name 00569 int i; 00570 for ( i = 0 ; global_database_tables[tbl].column_names[i] ; i++ ) 00571 { 00572 const char* name = global_database_tables[tbl].column_names[i]; 00573 00574 gboolean found = FALSE; 00575 int row; 00576 for ( row = 0 ; row < n_columns && !found ; row++) 00577 { 00578 GString *string = metadata_table_get_string(result, metadata_table_cell_index(result, row, col)); 00579 if (string) 00580 { 00581 if ( string->str && strcmp(string->str, name) == 0 ) 00582 { 00583 found = TRUE; 00584 } 00585 g_string_free(string, TRUE); 00586 } 00587 } 00588 if (!found) 00589 { 00590 ERRORPRINTF("column [%s] not present in table [%s]", name, global_database_tables[tbl].table_name); 00591 ret = ERMETADB_DATABASE_STRUCTURE; 00592 } 00593 } 00594 } 00595 metadata_table_free(result); 00596 } 00597 00598 return ret; 00599 }
static int check_global_database_consistency | ( | erMetadb | thiz | ) | [static] |
Definition at line 606 of file ermetadb.c.
References check_database_version(), check_global_database_columns(), check_global_database_tables(), ER_OK, ERRORPRINTF, and TRACE.
Referenced by check_database().
00607 { 00608 TRACE("entry: thiz [%p]", thiz); 00609 00610 int rc = check_database_version(thiz); 00611 if (rc != ER_OK) 00612 { 00613 ERRORPRINTF("checking database version failed with code [%d]", rc); 00614 return rc; 00615 } 00616 00617 rc = check_global_database_tables(thiz); 00618 if (rc != ER_OK) 00619 { 00620 ERRORPRINTF("checking global tables failed with code [%d]", rc); 00621 return rc; 00622 } 00623 00624 rc = check_global_database_columns(thiz); 00625 if (rc != ER_OK) 00626 { 00627 ERRORPRINTF("checking database columns failed with code [%d]", rc); 00628 return rc; 00629 } 00630 00631 return ER_OK; 00632 }
static int check_global_database_tables | ( | erMetadb | thiz | ) | [static] |
Definition at line 477 of file ermetadb.c.
References ER_OK, ERMETADB_DATABASE_STRUCTURE, ERMETADB_FAIL, ERRORPRINTF, global_database_tables, metadata_table_cell_index, metadata_table_find_column(), metadata_table_free, metadata_table_get_string(), metadata_table_n_rows, name, sql3_execute_query(), and TRACE.
Referenced by check_global_database_consistency().
00478 { 00479 TRACE("entry: thiz [%p]", thiz); 00480 g_assert(thiz->database); 00481 g_assert(thiz->is_global); 00482 00483 // get tablenames from database 00484 metadata_table *result = NULL; // result from query 00485 const char *sql = "SELECT name FROM sqlite_master WHERE type='table';"; 00486 int ret = sql3_execute_query(thiz->database, sql, NULL, &result); 00487 if (ret != ER_OK) goto out; 00488 00489 int n_tables = metadata_table_n_rows(result); 00490 int col = metadata_table_find_column(result, "name"); 00491 if (col < 0) 00492 { 00493 ERRORPRINTF("No 'names' column in result"); 00494 ret = ERMETADB_FAIL; 00495 goto out; 00496 } 00497 00498 // check table names 00499 int i; 00500 for ( i = 0 ; global_database_tables[i].table_name ; i++) 00501 { 00502 const char *name = global_database_tables[i].table_name; 00503 00504 gboolean found = FALSE; 00505 int row; 00506 for (row = 0 ; row < n_tables && !found ; row++) 00507 { 00508 GString *string = metadata_table_get_string(result, metadata_table_cell_index(result, row, col)); 00509 if (string) 00510 { 00511 if ( string->str && strcmp(string->str, name) == 0 ) 00512 { 00513 found = TRUE; 00514 } 00515 g_string_free(string, TRUE); 00516 } 00517 } 00518 if (!found) 00519 { 00520 ERRORPRINTF("table [%s] not present", name); 00521 ret = ERMETADB_DATABASE_STRUCTURE; 00522 } 00523 } 00524 out: 00525 metadata_table_free(result); 00526 return ret; 00527 }
static int check_local_database_consistency | ( | erMetadb | thiz | ) | [static] |
Definition at line 635 of file ermetadb.c.
References check_database_version(), ER_OK, ERRORPRINTF, and TRACE.
Referenced by check_database().
00636 { 00637 TRACE("entry: thiz [%p]", thiz); 00638 00639 int rc = check_database_version(thiz); 00640 if (rc != ER_OK) 00641 { 00642 ERRORPRINTF("checking database version failed with code [%d]", rc); 00643 return rc; 00644 } 00645 00646 return ER_OK; 00647 }
static int convert_database | ( | erMetadb | thiz, | |
const int | v_major, | |||
const int | v_minor | |||
) | [static] |
Definition at line 383 of file ermetadb.c.
References convert_database_01_06(), convert_database_05_06(), DATABASE_VERSION_MAJOR, DATABASE_VERSION_MINOR, ER_OK, ERMETADB_DATABASE_STRUCTURE, ERRORPRINTF, and TRACE.
Referenced by check_database_version().
00384 { 00385 g_assert(thiz->database); 00386 00387 int ret = ER_OK; 00388 int major = v_major; 00389 int minor = v_minor; 00390 00391 TRACE("entry: db [%p] version [%d].[%d] is_global=%d", db, v_major, v_minor, is_global); 00392 00393 if (major == 0 && minor == 1) 00394 { 00395 convert_database_01_06(thiz, &minor); 00396 } 00397 00398 if (major == 0 && minor == 5) 00399 { 00400 convert_database_05_06(thiz, &minor); 00401 } 00402 00403 // check conversion succeeded 00404 if ( major != DATABASE_VERSION_MAJOR 00405 || minor != DATABASE_VERSION_MINOR ) 00406 { 00407 ERRORPRINTF( "cannot convert database version [%d.%d] to %d.%d", 00408 v_major, 00409 v_minor, 00410 DATABASE_VERSION_MAJOR, 00411 DATABASE_VERSION_MINOR ); 00412 ret = ERMETADB_DATABASE_STRUCTURE; 00413 } 00414 00415 return ret; 00416 }
static void convert_database_01_06 | ( | erMetadb | thiz, | |
int * | minor | |||
) | [static] |
Definition at line 132 of file ermetadb.c.
References metadata_table::cell_data, ER_OK, ERRORPRINTF, LOGPRINTF, metadata_table_free, metadata_table::n_rows, sql3_execute_query(), update_version_number(), metadata_cell::v_int64, metadata_cell::v_text, metadata_cell::value, and WARNPRINTF.
Referenced by convert_database().
00133 { 00134 WARNPRINTF("Trying to convert db version 0.1 to 0.6"); 00135 // create temp table for file_metadata 00136 // copy file_metadata to temp table 00137 // drop old file_metadata table 00138 // rename temp to file_metadata 00139 // DROP thumbnails 00140 const char* sql = "CREATE TABLE temp (\n" 00141 " file_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\n" 00142 " filename VARCHAR(250) NOT NULL\n" 00143 ");"; 00144 if (sql3_execute_query(thiz->database, sql, NULL, NULL) != ER_OK) 00145 { 00146 ERRORPRINTF("cannot create temp table to convert version 0.1->0.6, dir %s", thiz->directory); 00147 return; 00148 } 00149 00150 sql = "INSERT INTO temp SELECT file_id, filename FROM file_metadata;\n" 00151 "DROP TABLE file_metadata;"; 00152 if (sql3_execute_query(thiz->database, sql, NULL, NULL) != ER_OK) 00153 { 00154 ERRORPRINTF("cannot fill temp to convert version 0.1->0.6, dir %s", thiz->directory); 00155 return; 00156 } 00157 00158 sql = "ALTER TABLE temp RENAME TO file_metadata;\n" 00159 "DROP TABLE thumbnails;"; 00160 if (sql3_execute_query(thiz->database, sql, NULL, NULL) != ER_OK) 00161 { 00162 ERRORPRINTF("cannot convert version 0.1->0.6, dir %s", thiz->directory); 00163 return; 00164 } 00165 00166 // get list of anchors 00167 sql = "SELECT annotation_id, start_anchor from annotations;"; 00168 metadata_table *result = NULL; 00169 if (sql3_execute_query(thiz->database, sql, NULL, &result) != ER_OK) 00170 { 00171 ERRORPRINTF("cannot get annotations to convert version 0.1->0.6, dir %s", thiz->directory); 00172 return; 00173 } 00174 00175 static const char* begin = "pdf:/page:"; 00176 unsigned int begin_len = strlen(begin); 00177 static const char* new_anchor = "adobe:|type:0|pf_page"; 00178 // convert anchors: pdf:/page:1 -> adobe:|type:0|pf_page:0.000000 00179 if (result) { 00180 const metadata_cell *cell = (const metadata_cell*) result->cell_data->data; 00181 unsigned int row; 00182 for (row=0; row<result->n_rows; row++) { 00183 int id = cell->value.v_int64; 00184 cell++; 00185 const char* anchor = cell->value.v_text->str; 00186 cell++; 00187 if (strncmp(begin, anchor, begin_len) == 0 && strlen(anchor) > begin_len) 00188 { 00189 int page = atoi(anchor + begin_len); 00190 if (page > 0) page--; // new system starts at 0 instead of 1 00191 char query[256]; 00192 sprintf(query, "UPDATE annotations set start_anchor='%s:%d.0000' WHERE annotation_id=%d;", 00193 new_anchor, page, id); 00194 if (sql3_execute_query(thiz->database, query, NULL, NULL) != ER_OK) { 00195 ERRORPRINTF("cannot update annotations"); 00196 } 00197 } 00198 00199 } 00200 metadata_table_free(result); 00201 } 00202 00203 // convert last_read locations in application_data 00204 sql = "SELECT file_id, key, value FROM application_data;"; 00205 result = NULL; 00206 if (sql3_execute_query(thiz->database, sql, NULL, &result) != ER_OK) 00207 { 00208 ERRORPRINTF("cannot get application data to convert version 0.1->0.6, dir %s", thiz->directory); 00209 return; 00210 } 00211 00212 // convert uds_last_read_location anchor: pdf:/page:1 -> adobe:|type:0|pf_page:0.000000 00213 if (result) { 00214 const metadata_cell *cell = (const metadata_cell*) result->cell_data->data; 00215 unsigned int row; 00216 for (row=0; row<result->n_rows; row++) { 00217 int id = cell->value.v_int64; 00218 cell++; 00219 const char* key = cell->value.v_text->str; 00220 cell++; 00221 const char* value = cell->value.v_text->str; 00222 cell++; 00223 static const char* lastread_key = "uds_last_read_location"; 00224 if (strcmp(lastread_key, key) == 0) { 00225 if (strncmp(begin, value, begin_len) == 0 && strlen(value) > begin_len) 00226 { 00227 int page = atoi(value + begin_len); 00228 if (page > 0) page--; // new system starts at 0 instead of 1 00229 char query[256]; 00230 sprintf(query, "UPDATE application_data set value='%s:%d.0000' WHERE file_id=%d AND key='%s';", 00231 new_anchor, page, id, lastread_key); 00232 if (sql3_execute_query(thiz->database, query, NULL, NULL) != ER_OK) { 00233 ERRORPRINTF("cannot update application_data"); 00234 } 00235 } 00236 } 00237 } 00238 metadata_table_free(result); 00239 } 00240 00241 if (update_version_number(thiz->database, 0, 6)) { 00242 LOGPRINTF("version updated to 0.6"); 00243 *minor = 6; 00244 } 00245 }
static void convert_database_05_06 | ( | erMetadb | thiz, | |
int * | minor | |||
) | [static] |
Definition at line 303 of file ermetadb.c.
References add_file_ids(), ER_OK, ermetadb_close(), ermetadb_global_open(), ERRORPRINTF, filename, get_filename_from_results(), local_delete_all_data_for_id(), LOGPRINTF, metadata_table_free, sql3_execute_query(), update_version_number(), and WARNPRINTF.
Referenced by convert_database().
00304 { 00305 WARNPRINTF("Trying to convert %s db version 0.5 to 0.6", (thiz->is_global ? "global" : "local")); 00306 GSList *id_list = NULL; 00307 00308 if (thiz->is_global) 00309 { 00310 // Nothing needs to be done; only update version number 00311 goto ok; 00312 } 00313 00314 // create new file_metadata table 00315 const char *sql = "CREATE TABLE file_metadata (file_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, filename VARCHAR(250) NOT NULL);"; 00316 if (sql3_execute_query(thiz->database, sql, NULL, NULL) != ER_OK) 00317 { 00318 ERRORPRINTF("Failed to create table 'file_metadata'"); 00319 return; 00320 } 00321 00322 // get all used local id's 00323 int rc1 = add_file_ids(thiz->database, &id_list, "application_data"); 00324 int rc2 = add_file_ids(thiz->database, &id_list, "annotations"); 00325 if (rc1 != ER_OK || rc2 != ER_OK) goto err; 00326 00327 if (id_list == NULL) goto ok; // empty database, just update version 00328 00329 // open global db for lookups 00330 // TODO Q: how to get path? (seach upwards?) 00331 const char* global_path = "/media/mmcblk0p1"; 00332 erMetadb global_db = ermetadb_global_open(global_path, TRUE); 00333 if (global_db == NULL) { 00334 ERRORPRINTF("cannot open global db for lookups"); 00335 goto err; 00336 } 00337 00338 // get all filename, id's from global for path 00339 char query[512]; 00340 sprintf(query, "SELECT file_id, filename FROM file_metadata WHERE directory_path = '%s';", thiz->directory); 00341 metadata_table *global_results = NULL; 00342 int rc = sql3_execute_query(global_db->database, query, NULL, &global_results); 00343 ermetadb_close(global_db); 00344 if (rc != ER_OK || global_results == NULL) { 00345 ERRORPRINTF("cannot get file_id's from global"); 00346 goto err; 00347 } 00348 00349 // for all id's, find matching filename and insert into local file_metadata 00350 GSList *iter = id_list; 00351 while (iter) { 00352 int id = (int)iter->data; 00353 const char* filename = get_filename_from_results(global_results, id); 00354 00355 if (filename == NULL) { 00356 WARNPRINTF("cannot find filename for id %d, removing data", id); 00357 local_delete_all_data_for_id(thiz, id); // dont care about result 00358 goto next; 00359 } 00360 00361 // find matching filename from global_resultss 00362 char *sql2 = sqlite3_mprintf("INSERT INTO file_metadata (filename, file_id) VALUES (%Q,%d);", filename, id); 00363 rc = sql3_execute_query(thiz->database, sql2, NULL, NULL); 00364 sqlite3_free(sql2); 00365 if (rc != ER_OK) { 00366 ERRORPRINTF("cannot insert <'%s', %d> into database", filename, id); 00367 } 00368 next: 00369 iter = g_slist_next(iter); 00370 } 00371 metadata_table_free(global_results); 00372 ok: 00373 // update version number 00374 if (update_version_number(thiz->database, 0, 6)) { 00375 LOGPRINTF("version updated to 0.6"); 00376 *minor = 6; 00377 } 00378 err: 00379 if (id_list) g_slist_free(id_list); 00380 }
static int create_database | ( | const char * | source_name, | |
const char * | target_dir, | |||
const char * | target_name | |||
) | [static] |
Definition at line 879 of file ermetadb.c.
References ER_FAIL, ER_OK, ER_READONLY, and ERRORPRINTF.
Referenced by ermetadb_global_create_database(), and ermetadb_local_create_database().
00880 { 00881 // determine path for database files 00882 gchar *file_source = g_strdup_printf("%s/%s", SYSCONFDIR, source_name); 00883 gchar *file_target = g_strdup_printf("%s/%s", target_dir, target_name); 00884 gchar *file_target_old = g_strdup_printf("%s.old", file_target); 00885 00886 // remove existing .old file, if present 00887 unlink(file_target_old); 00888 // rename current file (if any) to .old 00889 rename(file_target, file_target_old); 00890 00891 // copy source database to specified location 00892 unsigned int argc = 0; 00893 const char *argv[10]; 00894 argv[argc++] = "cp"; 00895 argv[argc++] = "-f"; 00896 argv[argc++] = file_source; 00897 argv[argc++] = file_target; 00898 argv[argc] = NULL; 00899 g_assert(argc < sizeof(argv)/sizeof(argv[0])); 00900 gint stat; 00901 GError *err = NULL; 00902 gboolean ok = g_spawn_sync( NULL, // working directory: inherit 00903 (char**)argv, // child's argument vector 00904 NULL, // environment: inherit 00905 G_SPAWN_SEARCH_PATH, // flags 00906 NULL, // child_setup: none 00907 NULL, // child setup data: none 00908 NULL, // stdout: not interested 00909 NULL, // stderr: not interested 00910 &stat, // exit status 00911 &err ); // error return 00912 int ret = ER_OK; 00913 if ( !ok ) 00914 { 00915 // error: command not executed 00916 ERRORPRINTF("g_spawn_sync error [%s] on copy [%s] [%s]", err->message, file_source, file_target); 00917 g_clear_error(&err); 00918 } 00919 else 00920 { 00921 // command executed: check its exit status 00922 if ( !WIFEXITED(stat) ) 00923 { 00924 // error: something weird happened 00925 ERRORPRINTF("g_spawn_sync ok but child not exited, stat [0x%04X]", stat); 00926 ret = ER_FAIL; 00927 } 00928 else 00929 { 00930 // ok: check exit status 00931 int rc = WEXITSTATUS(stat); 00932 if (rc != 0) 00933 { 00934 // command failed 00935 ERRORPRINTF( "Failed to copy [%s] [%s], error [%d] [%s]", 00936 file_source, 00937 file_target, 00938 rc, 00939 strerror(rc) ); 00940 switch (rc) 00941 { 00942 case EROFS: 00943 case EPERM: 00944 ret = ER_READONLY; 00945 break; 00946 default: 00947 ret = ER_FAIL; 00948 } 00949 } 00950 } 00951 } 00952 g_free(file_target_old); 00953 g_free(file_target ); 00954 g_free(file_source ); 00955 return ret; 00956 }
static int create_db | ( | erMetadb | thiz, | |
const char * | filename | |||
) | [static] |
Definition at line 767 of file ermetadb.c.
References ER_OK, ermetadb_global_create_database(), ermetadb_local_create_database(), ERRORPRINTF, and WARNPRINTF.
Referenced by database_open().
00768 { 00769 WARNPRINTF("(re-)generating database in %s", thiz->directory); 00770 int res = ER_OK; 00771 if (thiz->is_global) { 00772 res = ermetadb_global_create_database(thiz->directory); 00773 } else { 00774 res = ermetadb_local_create_database(thiz->directory, filename); 00775 } 00776 if (res != ER_OK) { 00777 ERRORPRINTF("error creating database %s/%s", thiz->directory, filename); 00778 } 00779 return res; 00780 }
static erMetadb database_open | ( | const gchar * | folder, | |
const gchar * | filename, | |||
gboolean | global, | |||
gboolean | readonly, | |||
gboolean | create | |||
) | [static] |
Definition at line 783 of file ermetadb.c.
References create_db(), ER_OK, ermetadb_close(), and open_sql_database().
Referenced by ermetadb_global_open(), ermetadb_local_open(), and ermetadb_local_open_custom().
00788 { 00789 g_assert(folder && folder[0]); 00790 g_assert(filename && filename[0]); 00791 00792 erMetadb thiz = g_new0(struct erMetadb_t, 1); 00793 00794 thiz->database = NULL; 00795 thiz->directory = g_strdup(folder); 00796 thiz->is_global = global; 00797 thiz->readonly = readonly; 00798 thiz->transaction_nesting = 0; 00799 thiz->is_transaction_readonly = FALSE; 00800 thiz->do_force_rollback = FALSE; 00801 00802 int res = open_sql_database(thiz, filename); 00803 if (res != ER_OK) { 00804 // create database on some conditions 00805 if (global && !readonly) res = create_db(thiz, filename); 00806 if (!global && create) res = create_db(thiz, filename); 00807 00808 if (res == ER_OK) { 00809 res = open_sql_database(thiz, filename); 00810 } 00811 } 00812 00813 if (res != ER_OK) { 00814 g_assert(thiz->database == NULL); 00815 ermetadb_close(thiz); 00816 return NULL; 00817 } 00818 g_assert(thiz->database); 00819 return thiz; 00820 00821 }
int ermetadb_begin_transaction | ( | erMetadb | thiz | ) |
Start a database transaction Only a single transaction is allowed, as seen from the application.
---------------------------------------------------------------------------
Name : ermetadb_begin_transaction
[in] | thiz | - erMetadb object on which to start a transaction |
--------------------------------------------------------------------------
Definition at line 998 of file ermetadb.c.
References ER_FORBIDDEN, LOGPRINTF, and sql3_begin_transaction().
Referenced by db_start_transaction().
00999 { 01000 LOGPRINTF("entry nesting [%d]", thiz->transaction_nesting); 01001 01002 g_assert(thiz); 01003 g_assert(thiz->database); 01004 g_return_val_if_fail( thiz->transaction_nesting == 0, ER_FORBIDDEN ); 01005 01006 return sql3_begin_transaction(thiz); 01007 }
int ermetadb_begin_transaction_readonly | ( | erMetadb | thiz | ) |
Start a read-only database transaction Only a single transaction is allowed, as seen from the application.
---------------------------------------------------------------------------
Name : ermetadb_begin_transaction_readonly
[in] | thiz | - erMetadb object on which to start a transaction |
--------------------------------------------------------------------------
Definition at line 1010 of file ermetadb.c.
References ER_FORBIDDEN, LOGPRINTF, and sql3_begin_transaction_readonly().
01011 { 01012 LOGPRINTF("entry nesting [%d]", thiz->transaction_nesting); 01013 01014 g_assert(thiz); 01015 g_assert(thiz->database); 01016 g_return_val_if_fail( thiz->transaction_nesting == 0, ER_FORBIDDEN ); 01017 01018 return sql3_begin_transaction_readonly(thiz); 01019 }
void ermetadb_close | ( | erMetadb | thiz | ) |
Close and free a metadata database.
---------------------------------------------------------------------------
Name : ermetadb_close
[in] | thiz | - erMetadb object or NULL |
--------------------------------------------------------------------------
Definition at line 851 of file ermetadb.c.
References ER_FAIL, ERRORPRINTF, LOGPRINTF, and sql3_commit_or_rollback().
Referenced by add_file_to_metadata(), add_folder_to_metadata(), close_database(), convert_database_05_06(), database_open(), db_close(), delete_local_metadata(), erscribble_doc_free_without_database(), erscribble_doc_new(), erscribble_doc_open(), meta_file_close(), meta_file_open(), and read_directory().
00852 { 00853 LOGPRINTF("entry"); 00854 00855 if (thiz == NULL) return; 00856 00857 if (thiz->database) { // close database if open 00858 // abort transaction, if any 00859 if (thiz->transaction_nesting != 0) 00860 { 00861 thiz->transaction_nesting = 1; 00862 sql3_commit_or_rollback(thiz, ER_FAIL); 00863 } 00864 00865 // close database 00866 int rc = sqlite3_close(thiz->database); 00867 if (rc != SQLITE_OK) 00868 { 00869 ERRORPRINTF("sqlite close error [%d] [%s]", rc, sqlite3_errmsg(thiz->database)); 00870 } 00871 thiz->database = NULL; 00872 } 00873 g_free(thiz->directory); 00874 g_free(thiz); 00875 }
int ermetadb_end_transaction | ( | erMetadb | thiz | ) |
Commit or rollback a database transaction Only a single transaction is allowed, as seen from the application. Library decides whether to commit or to rollback the changes. Basically when any query during this transaction has failed, the entire transaction is rolled back, otherwise the transaction is committed. Superfluous calls to ermetadb_end_transaction are ignored.
---------------------------------------------------------------------------
Name : ermetadb_end_transaction
[in] | thiz | - erMetadb object on which to end a transaction |
--------------------------------------------------------------------------
Definition at line 1022 of file ermetadb.c.
References ER_OK, LOGPRINTF, sql3_commit_or_rollback(), and WARNPRINTF.
Referenced by db_end_transaction().
01023 { 01024 LOGPRINTF("entry nesting [%d]", thiz->transaction_nesting); 01025 01026 g_assert(thiz); 01027 g_assert(thiz->database); 01028 01029 if (thiz->transaction_nesting != 1) 01030 { 01031 // nesting level unbalanced: force rollback 01032 WARNPRINTF("entry with transaction_nesting [%d]", thiz->transaction_nesting); 01033 thiz->transaction_nesting = 1; 01034 thiz->do_force_rollback = TRUE; 01035 } 01036 01037 return sql3_commit_or_rollback(thiz, ER_OK); 01038 }
const gchar* ermetadb_get_dir | ( | erMetadb | thiz | ) |
returns path where database was openened
---------------------------------------------------------------------------
Name : ermetadb_get_dir
[in] | thiz | - erMetadb object |
--------------------------------------------------------------------------
Definition at line 845 of file ermetadb.c.
Referenced by open_global_database().
int ermetadb_global_create_database | ( | const gchar * | folder | ) |
Create a new global metadata database, overwriting the existing database if present.
---------------------------------------------------------------------------
Name : ermetadb_global_create_database
[in] | folder | - directory in which the database file must be located |
--------------------------------------------------------------------------
Definition at line 959 of file ermetadb.c.
References create_database(), ERMETADB_GLOBAL_DATABASE_FILE, and LOGPRINTF.
Referenced by create_db().
00960 { 00961 LOGPRINTF("folder [%s]", folder); 00962 00963 g_assert(folder && folder[0]); 00964 00965 return create_database(ERMETADB_GLOBAL_DATABASE_FILE, folder, ERMETADB_GLOBAL_DATABASE_FILE); 00966 }
erMetadb ermetadb_global_open | ( | const gchar * | folder, | |
gboolean | readonly | |||
) |
opens a global metadata database
---------------------------------------------------------------------------
Name : ermetadb_global_open
[in] | folder,path | of .db file [in] readonly, to open db readonly or not if NOT readonly and db is corrupt/non-existent, a new db will be created |
--------------------------------------------------------------------------
Definition at line 824 of file ermetadb.c.
References database_open(), ERMETADB_GLOBAL_DATABASE_FILE, and LOGPRINTF.
Referenced by add_file_to_metadata(), add_folder_to_metadata(), convert_database_05_06(), db_open_global(), open_database(), and open_global_database().
00825 { 00826 LOGPRINTF("folder [%s]", folder); 00827 return database_open(folder, ERMETADB_GLOBAL_DATABASE_FILE, TRUE, readonly, FALSE); 00828 }
int ermetadb_local_create_database | ( | const gchar * | folder, | |
const gchar * | filename | |||
) |
Definition at line 969 of file ermetadb.c.
References create_database(), ERMETADB_LOCAL_DATABASE_FILE, and LOGPRINTF.
Referenced by create_db().
00970 { 00971 LOGPRINTF("folder [%s] file [%s]", folder, filename); 00972 00973 g_assert(folder && folder[0]); 00974 g_assert(filename && filename[0]); 00975 00976 return create_database(ERMETADB_LOCAL_DATABASE_FILE, folder, filename); 00977 }
erMetadb ermetadb_local_open | ( | const gchar * | folder, | |
gboolean | create | |||
) |
opens a local metadata database
---------------------------------------------------------------------------
Name : ermetadb_local_open
[in] | folder,path | of .db file |
[in] | create,whether | to create one if it doesn't exist or is corrupt |
--------------------------------------------------------------------------
Definition at line 831 of file ermetadb.c.
References database_open(), ERMETADB_LOCAL_DATABASE_FILE, and LOGPRINTF.
Referenced by delete_local_metadata(), erscribble_doc_new(), erscribble_doc_open(), meta_file_close(), meta_file_open(), and read_directory().
00832 { 00833 LOGPRINTF("folder [%s] create [%d]", folder, create); 00834 return database_open(folder, ERMETADB_LOCAL_DATABASE_FILE, FALSE, FALSE, create); 00835 }
erMetadb ermetadb_local_open_custom | ( | const gchar * | folder, | |
const gchar * | filename | |||
) |
opens a local metadata database with specified name
---------------------------------------------------------------------------
Name : ermetadb_local_open_custom
[in] | folder,path | of .db file |
[in] | filename,name | of .db file |
--------------------------------------------------------------------------
Definition at line 838 of file ermetadb.c.
References database_open(), and LOGPRINTF.
00839 { 00840 LOGPRINTF("folder [%s] file [%s]", folder, filename); 00841 return database_open(folder, filename, FALSE, FALSE, FALSE); 00842 }
const char* const* ermetadb_private_get_global_column_names | ( | const char * | table | ) |
Get column names for a specified SQL table name.
---------------------------------------------------------------------------
Name : ermetadb_private_get_global_column_names
[in] | table | - name of the SQL table |
--------------------------------------------------------------------------
Definition at line 980 of file ermetadb.c.
References global_database_tables, LOGPRINTF, and table_name.
Referenced by ermetadb_global_get_file(), and set_file_metadata_impl().
00981 { 00982 LOGPRINTF("entry: table [%s]", table); 00983 g_assert(table); 00984 00985 int i; 00986 for (i = 0 ; global_database_tables[i].table_name; i++) 00987 { 00988 if ( strcmp(global_database_tables[i].table_name, table) == 0 ) 00989 { 00990 return global_database_tables[i].column_names; 00991 } 00992 } 00993 00994 return NULL; 00995 }
static const char* get_filename_from_results | ( | const metadata_table * | table, | |
int | id | |||
) | [static] |
Definition at line 278 of file ermetadb.c.
References metadata_table::cell_data, METADATA_INT64, METADATA_TEXT, metadata_table::n_columns, metadata_table::n_rows, metadata_cell::type, metadata_cell::v_int64, metadata_cell::v_text, and metadata_cell::value.
Referenced by convert_database_05_06().
00279 { 00280 g_assert(table->n_columns == 2); 00281 if (table->n_rows == 0) return NULL; 00282 00283 const metadata_cell *cell = (const metadata_cell*) table->cell_data->data; 00284 unsigned int row; 00285 for (row=0; row<table->n_rows; row++) { 00286 g_assert_cmpint(cell->type, ==, METADATA_INT64); 00287 00288 int id2 = cell->value.v_int64; 00289 if (id == id2) { 00290 cell++; 00291 g_assert_cmpint(cell->type, ==, METADATA_TEXT); 00292 return cell->value.v_text->str; 00293 } 00294 cell += table->n_columns; 00295 } 00296 return NULL; 00297 }
static int open_sql_database | ( | erMetadb | thiz, | |
const char * | filename | |||
) | [static] |
Definition at line 702 of file ermetadb.c.
References check_database(), ER_NOT_FOUND, ER_OK, ERRORPRINTF, LOGPRINTF, metadata_table_free, open_sqlite_database(), sql3_begin_transaction(), sql3_begin_transaction_readonly(), sql3_commit_or_rollback(), and sql3_execute_query().
Referenced by database_open().
00703 { 00704 // check if directory exists 00705 struct stat statbuf; 00706 int rc = stat(thiz->directory, &statbuf); 00707 if (rc != 0 || !S_ISDIR(statbuf.st_mode)) 00708 { 00709 // directory not present or not a directory: report error 00710 LOGPRINTF("folder doesn't exist or is not folder [%s]", thiz->directory); 00711 return ER_NOT_FOUND; 00712 } 00713 00714 // create fullname 00715 char fullname[PATH_MAX]; 00716 sprintf(fullname, "%s/%s", thiz->directory, filename); 00717 00718 // check if database exists 00719 struct stat statbuf2; 00720 rc = stat(fullname, &statbuf2); 00721 if (rc != 0 || !S_ISREG(statbuf2.st_mode)) 00722 { 00723 // database not present: report error 00724 LOGPRINTF("database not present or is not regular file [%s]", fullname); 00725 return ER_NOT_FOUND; 00726 } 00727 00728 sqlite3* db = NULL; 00729 rc = open_sqlite_database(fullname, thiz->readonly, &db); 00730 if (rc != ER_OK) 00731 { 00732 ERRORPRINTF("open sqlite failed, rc [%d] filename [%s] readonly [%d]", 00733 rc, fullname, thiz->readonly); 00734 return rc; 00735 } 00736 thiz->database = db; 00737 00738 int ret = ER_OK; 00739 if (thiz->readonly) 00740 { 00741 ret = sql3_begin_transaction_readonly(thiz); 00742 } 00743 else 00744 { 00745 ret = sql3_begin_transaction(thiz); 00746 } 00747 ret = check_database(thiz); 00748 ret = sql3_commit_or_rollback(thiz, ret); 00749 if (ret != ER_OK) goto error; 00750 00751 // enable asynchronous mode, 00752 // i.e. sqlite writes to filesystem but does not wait for flush to disk 00753 const char *sql = "PRAGMA synchronous = OFF;"; 00754 metadata_table *result = NULL; 00755 ret = sql3_execute_query(thiz->database, sql, NULL, &result); 00756 metadata_table_free(result); 00757 00758 if (ret != ER_OK) goto error; 00759 return ER_OK; 00760 error: 00761 sqlite3_close(thiz->database); 00762 thiz->database = NULL; 00763 return ret; 00764 }
static int open_sqlite_database | ( | const gchar * | filename, | |
gboolean | do_open_readonly, | |||
sqlite3 ** | database | |||
) | [static] |
Definition at line 650 of file ermetadb.c.
References ER_OK, ER_OPEN_ERROR, ERRORPRINTF, sql3_strcase_compare(), SQLITE_COLLATION_STRCASECMP, and TRACE.
Referenced by open_sql_database().
00651 { 00652 g_assert(filename); 00653 g_assert(database && *database == NULL); 00654 00655 // open database read-write 00656 sqlite3 *db = NULL; 00657 int rc = sqlite3_open_v2( filename, 00658 &db, 00659 do_open_readonly ? SQLITE_OPEN_READONLY : SQLITE_OPEN_READWRITE, 00660 NULL ); 00661 int ret = ER_OK; 00662 if (rc != SQLITE_OK) 00663 { 00664 ERRORPRINTF("sqlite open error [%d] [%s] on [%s]", rc, sqlite3_errmsg(db), filename); 00665 ret = ER_OPEN_ERROR; 00666 sqlite3_close(db); 00667 db = NULL; 00668 } 00669 00670 // install custom collation sequence 00671 if (ret == ER_OK) 00672 { 00673 rc = sqlite3_create_collation( db, // database 00674 SQLITE_COLLATION_STRCASECMP, // collation name 00675 SQLITE_UTF8, // text representation 00676 NULL, // user data 00677 sql3_strcase_compare ); // compare function 00678 if (rc != SQLITE_OK) 00679 { 00680 ERRORPRINTF("sqlite collation install error [%d] [%s]", rc, sqlite3_errmsg(db)); 00681 } 00682 } 00683 00684 if (ret == ER_OK) 00685 { 00686 *database = db; 00687 } 00688 TRACE("leave: ret [%d]", ret); 00689 return ret; 00690 }
static gboolean update_version_number | ( | sqlite3 * | db, | |
int | major, | |||
int | minor | |||
) | [static] |
Definition at line 119 of file ermetadb.c.
References ER_OK, ERRORPRINTF, and sql3_execute_query().
Referenced by convert_database_01_06(), and convert_database_05_06().
00120 { 00121 char query[255]; 00122 sprintf(query, "UPDATE database_properties SET version_major=%d, version_minor=%d;", 00123 major, minor); 00124 int rc = sql3_execute_query(db, query, NULL, NULL); 00125 if (rc != ER_OK) { 00126 ERRORPRINTF("cannot update version number to %d.%d", major, minor); 00127 } 00128 return (rc == ER_OK); 00129 }
const char* column_names[MAX_COLUMNS+1] |
Definition at line 62 of file ermetadb.c.
struct { ... } global_database_tables[] [static] |
const char* table_name |
Definition at line 61 of file ermetadb.c.
Referenced by check_global_database_columns(), ermetadb_private_get_global_column_names(), and get_local_column_names().