ermetadb.c File Reference

#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"
Include dependency graph for ermetadb.c:

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 Documentation

#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.


Function Documentation

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 }

Here is the call graph for this function:

Here is the caller graph for this function:

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 }

Here is the call graph for this function:

Here is the caller graph for this function:

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 }

Here is the call graph for this function:

Here is the caller graph for this function:

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 }

Here is the call graph for this function:

Here is the caller graph for this function:

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 }

Here is the call graph for this function:

Here is the caller graph for this function:

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 }

Here is the call graph for this function:

Here is the caller graph for this function:

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 }

Here is the call graph for this function:

Here is the caller graph for this function:

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 }

Here is the call graph for this function:

Here is the caller graph for this function:

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 }

Here is the call graph for this function:

Here is the caller graph for this function:

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 }

Here is the call graph for this function:

Here is the caller graph for this function:

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 }

Here is the caller graph for this function:

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 }

Here is the call graph for this function:

Here is the caller graph for this function:

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 }

Here is the call graph for this function:

Here is the caller graph for this function:

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

Parameters:
[in] thiz - erMetadb object on which to start a transaction
Returns:
ER_OK or error

--------------------------------------------------------------------------

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 }

Here is the call graph for this function:

Here is the caller graph for this function:

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

Parameters:
[in] thiz - erMetadb object on which to start a transaction
Returns:
ER_OK or error

--------------------------------------------------------------------------

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 }

Here is the call graph for this function:

void ermetadb_close ( erMetadb  thiz  ) 

Close and free a metadata database.

---------------------------------------------------------------------------

Name : ermetadb_close

Parameters:
[in] thiz - erMetadb object or NULL
Returns:
ER_OK or error code

--------------------------------------------------------------------------

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 }

Here is the call graph for this function:

Here is the caller graph for this function:

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

Parameters:
[in] thiz - erMetadb object on which to end a transaction
Returns:
ER_OK or error or 'err' value when this is not ER_OK

--------------------------------------------------------------------------

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 }

Here is the call graph for this function:

Here is the caller graph for this function:

const gchar* ermetadb_get_dir ( erMetadb  thiz  ) 

returns path where database was openened

---------------------------------------------------------------------------

Name : ermetadb_get_dir

Parameters:
[in] thiz - erMetadb object
Returns:
path. Does not have to be freed

--------------------------------------------------------------------------

Definition at line 845 of file ermetadb.c.

Referenced by open_global_database().

00846 {
00847     return thiz->directory;
00848 }

Here is the caller graph for this function:

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

Parameters:
[in] folder - directory in which the database file must be located
Returns:
ER_OK or error code

--------------------------------------------------------------------------

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 }

Here is the call graph for this function:

Here is the caller graph for this function:

erMetadb ermetadb_global_open ( const gchar *  folder,
gboolean  readonly 
)

opens a global metadata database

---------------------------------------------------------------------------

Name : ermetadb_global_open

Parameters:
[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
Returns:
Pointer to the newly created object, or NULL

--------------------------------------------------------------------------

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 }

Here is the call graph for this function:

Here is the caller graph for this function:

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 }

Here is the call graph for this function:

Here is the caller graph for this function:

erMetadb ermetadb_local_open ( const gchar *  folder,
gboolean  create 
)

opens a local metadata database

---------------------------------------------------------------------------

Name : ermetadb_local_open

Parameters:
[in] folder,path of .db file
[in] create,whether to create one if it doesn't exist or is corrupt
Returns:
Pointer to the newly created object, or NULL

--------------------------------------------------------------------------

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 }

Here is the call graph for this function:

Here is the caller graph for this function:

erMetadb ermetadb_local_open_custom ( const gchar *  folder,
const gchar *  filename 
)

opens a local metadata database with specified name

---------------------------------------------------------------------------

Name : ermetadb_local_open_custom

Parameters:
[in] folder,path of .db file
[in] filename,name of .db file
Returns:
Pointer to the newly created object, or NULL

--------------------------------------------------------------------------

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 }

Here is the call graph for this function:

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

Parameters:
[in] table - name of the SQL table
Returns:
Pointer to a NULL-terminated array of column names or NULL when error

--------------------------------------------------------------------------

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 }

Here is the caller graph for this function:

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 }

Here is the caller graph for this function:

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 }

Here is the call graph for this function:

Here is the caller graph for this function:

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 }

Here is the call graph for this function:

Here is the caller graph for this function:

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 }

Here is the call graph for this function:

Here is the caller graph for this function:


Variable Documentation

const char* column_names[MAX_COLUMNS+1]

Definition at line 62 of file ermetadb.c.

struct { ... } global_database_tables[] [static]
const char* table_name
Generated by  doxygen 1.6.2-20100208