Fawkes API Fawkes Development Version

sqlite.cpp

00001 
00002 /***************************************************************************
00003  *  sqlite.cpp - Fawkes configuration stored in a SQLite database
00004  *
00005  *  Created: Wed Dec 06 17:23:00 2006
00006  *  Copyright  2006-2009  Tim Niemueller [www.niemueller.de]
00007  *
00008  ****************************************************************************/
00009 
00010 /*  This program is free software; you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation; either version 2 of the License, or
00013  *  (at your option) any later version. A runtime exception applies to
00014  *  this software (see LICENSE.GPL_WRE file mentioned below for details).
00015  *
00016  *  This program is distributed in the hope that it will be useful,
00017  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  *  GNU Library General Public License for more details.
00020  *
00021  *  Read the full text in the LICENSE.GPL_WRE file in the doc directory.
00022  */
00023 
00024 #include <config/sqlite.h>
00025 #include <core/threading/mutex.h>
00026 #include <core/exceptions/system.h>
00027 
00028 #include <sqlite3.h>
00029 
00030 #ifndef _GNU_SOURCE
00031 #define _GNU_SOURCE
00032 #endif
00033 #include <cstdio>
00034 #include <cstdlib>
00035 #include <cstring>
00036 #include <cerrno>
00037 #include <unistd.h>
00038 #include <fnmatch.h>
00039 
00040 namespace fawkes {
00041 
00042 /* SQLite statements */
00043 
00044 #define TABLE_HOST_CONFIG "config"
00045 #define TABLE_DEFAULT_CONFIG "defaults.config"
00046 #define TABLE_HOST_TAGGED "tagged_config"
00047 
00048 #define SQL_CREATE_TABLE_HOST_CONFIG                                    \
00049   "CREATE TABLE IF NOT EXISTS config (\n"                               \
00050   "  path      TEXT NOT NULL,\n"                                        \
00051   "  type      TEXT NOT NULL,\n"                                        \
00052   "  value     NOT NULL,\n"                                             \
00053   "  comment   TEXT,\n"                                                 \
00054   "  PRIMARY KEY (path)\n"                                              \
00055   ")"
00056 
00057 #define SQL_CREATE_TABLE_DEFAULT_CONFIG                                 \
00058   "CREATE TABLE IF NOT EXISTS defaults.config (\n"                      \
00059   "  path      TEXT NOT NULL,\n"                                        \
00060   "  type      TEXT NOT NULL,\n"                                        \
00061   "  value     NOT NULL,\n"                                             \
00062   "  comment   TEXT,\n"                                                 \
00063   "  PRIMARY KEY (path)\n"                                              \
00064   ")"
00065 
00066 #define SQL_CREATE_TABLE_TAGGED_CONFIG                                  \
00067   "CREATE TABLE IF NOT EXISTS tagged_config (\n"                        \
00068   "  tag       TEXT NOT NULL,\n"                                        \
00069   "  path      TEXT NOT NULL,\n"                                        \
00070   "  type      TEXT NOT NULL,\n"                                        \
00071   "  value     NOT NULL,\n"                                             \
00072   "  comment   TEXT,\n"                                                 \
00073   "  PRIMARY KEY (tag, path)\n"                                         \
00074   ")"
00075 
00076 #define SQL_CREATE_TABLE_MODIFIED_CONFIG                                \
00077   "CREATE TABLE IF NOT EXISTS modified.config (\n"                      \
00078   "  path      TEXT NOT NULL,\n"                                        \
00079   "  type      TEXT NOT NULL,\n"                                        \
00080   "  value     NOT NULL,\n"                                             \
00081   "  comment   TEXT,\n"                                                 \
00082   "  modtype   TEXT NOT NULL,\n"                                        \
00083   "  oldvalue  NOT NULL,\n"                                             \
00084   "  PRIMARY KEY (path)\n"                                              \
00085   ")"
00086 
00087 #define SQL_ATTACH_DEFAULTS                                             \
00088   "ATTACH DATABASE '%s' AS defaults"
00089 
00090 #define SQL_ATTACH_MODIFIED                                             \
00091   "ATTACH DATABASE ':memory:' AS modified"
00092 
00093 #define SQL_ATTACH_DUMPED                                               \
00094   "ATTACH DATABASE '%s' AS dumped"
00095 
00096 #define SQL_DETACH_DUMPED                                               \
00097   "DETACH DATABASE dumped"
00098 
00099 #define SQL_SELECT_VALUE_TYPE                                           \
00100   "SELECT type, value, 0 AS is_default FROM config WHERE path=? UNION " \
00101   "SELECT type, value, 1 AS is_default FROM defaults.config AS dc "     \
00102   "WHERE path=? AND NOT EXISTS "                                        \
00103   "(SELECT path FROM config WHERE dc.path=path)"
00104 
00105 #define SQL_SELECT_COMPLETE                                             \
00106   "SELECT *, 0 AS is_default FROM config WHERE path LIKE ? UNION "      \
00107   "SELECT *, 1 AS is_default FROM defaults.config AS dc "               \
00108   "WHERE path LIKE ? AND NOT EXISTS "                                   \
00109   "(SELECT path FROM config WHERE dc.path = path) "                     \
00110   "ORDER BY path"
00111 
00112 #define SQL_SELECT_TYPE                                                 \
00113   "SELECT type, 0 AS is_default FROM config WHERE path=? UNION "        \
00114   "SELECT type, 1 AS is_default FROM defaults.config AS dc "            \
00115   "WHERE path=? AND NOT EXISTS "                                        \
00116   "(SELECT path FROM config WHERE dc.path = path)"
00117 
00118 #define SQL_SELECT_COMMENT                                              \
00119   "SELECT comment, 0 AS is_default FROM config WHERE path=?"
00120 
00121 #define SQL_SELECT_DEFAULT_COMMENT                                      \
00122   "SELECT comment, 1 AS is_default FROM defaults.config AS dc "         \
00123   "WHERE dc.path=?"
00124 
00125 #define SQL_UPDATE_VALUE                                                \
00126   "UPDATE config SET value=? WHERE path=?"
00127 
00128 #define SQL_UPDATE_DEFAULT_VALUE                                        \
00129   "UPDATE defaults.config SET value=? WHERE path=?"
00130 
00131 #define SQL_UPDATE_COMMENT                                              \
00132   "UPDATE config SET comment=? WHERE path=?"
00133 
00134 #define SQL_UPDATE_DEFAULT_COMMENT                                      \
00135   "UPDATE defaults.config SET comment=? WHERE path=?"
00136 
00137 #define SQL_INSERT_VALUE                                                \
00138   "INSERT INTO config (path, type, value) VALUES (?, ?, ?)"
00139 
00140 #define SQL_INSERT_DEFAULT_VALUE                                        \
00141   "INSERT INTO defaults.config (path, type, value) VALUES (?, ?, ?)"
00142 
00143 #define SQL_SELECT_TAGS                                                 \
00144   "SELECT tag FROM tagged_config GROUP BY tag"
00145 
00146 #define SQL_INSERT_TAG                                                  \
00147   "INSERT INTO tagged_config "                                          \
00148   "(tag, path, type, value, comment) "                                  \
00149   "SELECT \"%s\",* FROM config"
00150 
00151 #define SQL_SELECT_ALL                                                  \
00152   "SELECT *, 0 AS is_default FROM config UNION "                        \
00153   "SELECT *, 1 AS is_default FROM defaults.config AS dc "               \
00154   "WHERE NOT EXISTS "                                                   \
00155   "(SELECT path FROM config WHERE dc.path = path) "                     \
00156   "ORDER BY path"
00157 
00158 #define SQL_SELECT_ALL_DEFAULT                                          \
00159   "SELECT *, 1 AS is_default FROM defaults.config"
00160 
00161 #define SQL_SELECT_ALL_HOSTSPECIFIC                                     \
00162   "SELECT *, 0 AS is_default FROM config"
00163 
00164 #define SQL_DELETE_VALUE                                                \
00165   "DELETE FROM config WHERE path=?"
00166 
00167 #define SQL_DELETE_DEFAULT_VALUE                                        \
00168   "DELETE FROM defaults.config WHERE path=?"
00169 
00170 #define SQL_UPDATE_DEFAULT_DB                                           \
00171   "INSERT INTO config SELECT * FROM defaults.config AS dc "             \
00172   "WHERE NOT EXISTS (SELECT path from config WHERE path = dc.path)"
00173 
00174 #define SQL_UPDATE_MODIFIED_DB_ADDED                                    \
00175   "INSERT INTO modified.config "                                        \
00176   "  SELECT duc.*,'added' AS modtype, duc.value "                       \
00177   "    FROM dumped.config AS duc "                                      \
00178   "    WHERE NOT EXISTS (SELECT dc.path FROM defaults.config AS dc "    \
00179   "                        WHERE dc.path=duc.path) "                    \
00180   "    ORDER BY path"
00181 
00182 #define SQL_UPDATE_MODIFIED_DB_ERASED                                   \
00183   "INSERT INTO modified.config "                                        \
00184   "  SELECT dc.*,'erased' AS modtype, dc.value "                        \
00185   "    FROM defaults.config AS dc "                                     \
00186   "    WHERE NOT EXISTS (SELECT duc.path FROM dumped.config AS duc "    \
00187   "                        WHERE duc.path=dc.path) "                    \
00188   "    ORDER BY path"
00189 
00190 #define SQL_UPDATE_MODIFIED_DB_CHANGED                                  \
00191   "INSERT INTO modified.config "                                        \
00192   "  SELECT duc.*,'changed' AS modtype, dc.value "                      \
00193   "    FROM dumped.config AS duc, defaults.config AS dc "               \
00194   "    WHERE duc.path = dc.path "                                       \
00195   "      AND (dc.type != duc.type OR dc.value != duc.value) "           \
00196   "    ORDER BY duc.path"
00197 
00198 #define SQL_COPY_DUMP                                                   \
00199   "DELETE FROM defaults.config; "                                       \
00200   "INSERT INTO defaults.config SELECT * FROM dumped.config"
00201 
00202 #define SQL_SELECT_MODIFIED_ALL                                         \
00203   "SELECT * FROM modified.config"
00204 
00205 /** @class SQLiteConfiguration <config/sqlite.h>
00206  * Configuration storage using SQLite.
00207  * This implementation of the Configuration interface uses SQLite to store the
00208  * configuration.
00209  *
00210  * The configuration uses two databases, one is used to store the host-specific
00211  * configuration and the other one is used to store the default values. Only the
00212  * default database is meant to reside under version control.
00213  *
00214  * See init() for the structure of the databases. This class strictly serializes
00215  * all accesses to the database such that only one thread at a time can modify the
00216  * database.
00217  */
00218 
00219 
00220 /** Constructor. */
00221 SQLiteConfiguration::SQLiteConfiguration()
00222 {
00223   opened = false;
00224   mutex = new Mutex();
00225 
00226   __sysconfdir   = NULL;
00227   __userconfdir  = NULL;
00228   __default_file = NULL;
00229   __default_sql  = NULL;
00230 
00231 }
00232 
00233 /** Constructor.
00234  * @param sysconfdir system configuration directory, will be searched for
00235  * default configuration file, and system will try to create host-specific
00236  * database if writable
00237  * @param userconfdir user configuration directory, will be searched preferably
00238  * for default configuration file, and will be used to create host-specific
00239  * database if sysconfdir is not writable. This directory will be created
00240  * if it does not exist during load().
00241  */
00242 SQLiteConfiguration::SQLiteConfiguration(const char *sysconfdir,
00243                                          const char *userconfdir)
00244 {
00245   opened = false;
00246   mutex = new Mutex();
00247 
00248   __sysconfdir   = strdup(sysconfdir);
00249   __default_file = NULL;
00250   __default_sql  = NULL;
00251 
00252   if (userconfdir != NULL) {
00253     __userconfdir  = strdup(userconfdir);
00254   } else {
00255     const char *homedir = getenv("HOME");
00256     if (homedir == NULL) {
00257       __userconfdir = strdup(sysconfdir);
00258     } else {
00259       if (asprintf(&__userconfdir, "%s/%s", homedir, USERDIR) == -1) {
00260         __userconfdir = strdup(sysconfdir);
00261       }
00262     }
00263   }
00264 }
00265 
00266 /** Destructor. */
00267 SQLiteConfiguration::~SQLiteConfiguration()
00268 {
00269   if (opened) {
00270     opened = false;
00271     if ( sqlite3_close(db) == SQLITE_BUSY ) {
00272       printf("Boom, we are dead, database cannot be closed "
00273              "because there are open handles\n");
00274     }
00275   }
00276 
00277   if (__host_file)    free(__host_file);
00278   if (__default_file) free(__default_file);
00279   if (__default_sql)  free(__default_sql);
00280   if (__sysconfdir)   free(__sysconfdir);
00281   if (__userconfdir)  free(__userconfdir);
00282   delete mutex;
00283 }
00284 
00285 
00286 /** Initialize the configuration database(s).
00287  * Initialize databases. If the host-specific database already exists
00288  * an exception is thrown. You have to delete it before calling init().
00289  * First the host-specific database is created. It will contain two tables,
00290  * on is named 'config' and the other one is named 'tagged'. The 'config'
00291  * table will hold the current configuration for this machine. The 'tagged'
00292  * table contains the same fields as config with an additional "tag" field.
00293  * To tag a given revision of the config you give it a name, copy all values
00294  * over to the 'tagged' table with "tag" set to the desired name.
00295  *
00296  * The 'config' table is created with the following schema:
00297  * @code
00298  * CREATE TABLE IF NOT EXISTS config (
00299  *   path      TEXT NOT NULL,
00300  *   type      TEXT NOT NULL,
00301  *   value     NOT NULL,
00302  *   comment   TEXT,
00303  *   PRIMARY KEY (path)
00304  * )
00305  * @endcode
00306  * If a default database is found the values from this database are copied
00307  * to the config table.
00308  * The defaults config database is created with the following structure:
00309  * @code
00310  * CREATE TABLE IF NOT EXISTS defaults.config (
00311  *   path      TEXT NOT NULL,
00312  *   type      TEXT NOT NULL,
00313  *   value     NOT NULL,
00314  *   comment   TEXT,
00315  *   PRIMARY KEY (path)
00316  * )
00317  * @endcode
00318  *
00319  * After this the 'tagged' table is created with the following schema:
00320  * @code
00321  * CREATE TABLE IF NOT EXISTS tagged_config (
00322  *   tag       TEXT NOT NULL,
00323  *   path      TEXT NOT NULL,
00324  *   type      TEXT NOT NULL,
00325  *   value     NOT NULL,
00326  *   comment   TEXT
00327  *   PRIMARY KEY (tag, path)
00328  * )
00329  * @endcode
00330  *
00331  * If no default database exists it is created. The database is kept in a file
00332  * called default.db. It contains a single table called 'config' with the same
00333  * structure as the 'config' table in the host-specific database.
00334  */
00335 void
00336 SQLiteConfiguration::init_dbs()
00337 {
00338   char *errmsg;
00339   if ( (sqlite3_exec(db, SQL_CREATE_TABLE_HOST_CONFIG, NULL, NULL, &errmsg) != SQLITE_OK) ||
00340        (sqlite3_exec(db, SQL_CREATE_TABLE_DEFAULT_CONFIG, NULL, NULL, &errmsg) != SQLITE_OK) ||
00341        (sqlite3_exec(db, SQL_CREATE_TABLE_TAGGED_CONFIG, NULL, NULL, &errmsg) != SQLITE_OK) ) {
00342     CouldNotOpenConfigException ce(sqlite3_errmsg(db));
00343     sqlite3_close(db);
00344     throw ce;
00345   }
00346 }
00347 
00348 
00349 /** Dump table.
00350  * Dumps a table to the given file.
00351  * @param f file to write to
00352  * @param tdb SQLite3 database to read from
00353  * @param table_name Name of the table to dump
00354  */
00355 static void
00356 dump_table(FILE *f, ::sqlite3 *tdb, const char *table_name)
00357 {
00358   std::string tisql = "PRAGMA table_info(\"";
00359   tisql += table_name;
00360   tisql += "\");";
00361 
00362   sqlite3_stmt *stmt;
00363   if ( sqlite3_prepare(tdb, tisql.c_str(), -1, &stmt, 0) != SQLITE_OK ) {
00364     throw ConfigurationException("dump_table/prepare", sqlite3_errmsg(tdb));
00365   }
00366   std::string value_query = "SELECT 'INSERT INTO ' || '\"";
00367   value_query += table_name;
00368   value_query += "\"' || ' VALUES(' || ";
00369   int rv = sqlite3_step(stmt);
00370   while ( rv == SQLITE_ROW ) {
00371     value_query += "quote(\"";
00372     value_query += (const char *)sqlite3_column_text(stmt, 1);
00373     value_query += "\") || ";
00374     rv = sqlite3_step(stmt);
00375     if ( rv == SQLITE_ROW ) {
00376       value_query += " ',' || ";
00377     }
00378   }
00379   value_query += "')' FROM ";
00380   value_query += table_name;
00381   sqlite3_finalize(stmt);
00382 
00383   sqlite3_stmt *vstmt;
00384   if ( sqlite3_prepare(tdb, value_query.c_str(), -1, &vstmt, 0) != SQLITE_OK ) {
00385     throw ConfigurationException("dump_table/prepare 2", sqlite3_errmsg(tdb));
00386   }
00387   while ( sqlite3_step(vstmt) == SQLITE_ROW ) {
00388     fprintf(f, "%s;\n", sqlite3_column_text(vstmt, 0));
00389   }
00390   sqlite3_finalize(vstmt);
00391 }
00392 
00393 void
00394 SQLiteConfiguration::dump(::sqlite3 *tdb, const char *dumpfile)
00395 {
00396   FILE *f = fopen(dumpfile, "w");
00397   if ( ! f ) {
00398     throw CouldNotOpenFileException(dumpfile, errno, "Could not open dump file");
00399   }
00400 
00401   fprintf(f, "BEGIN TRANSACTION;\n");
00402 
00403   const char *sql = "SELECT name, sql FROM sqlite_master "
00404                     "WHERE sql NOT NULL AND type=='table'";
00405   sqlite3_stmt *stmt;
00406   if ( (sqlite3_prepare(tdb, sql, -1, &stmt, 0) != SQLITE_OK) || ! stmt ) {
00407     throw ConfigurationException("dump_query/prepare", sqlite3_errmsg(tdb));
00408   }
00409   while ( sqlite3_step(stmt) == SQLITE_ROW ) {
00410     fprintf(f, "%s;\n", sqlite3_column_text(stmt, 1));
00411     dump_table(f, tdb, (const char *)sqlite3_column_text(stmt, 0));
00412   }
00413   sqlite3_finalize(stmt);
00414 
00415   fprintf(f, "COMMIT;\n");
00416   fclose(f);
00417 }
00418 
00419 
00420 /** Try to dump default configuration.
00421  * This method will try to open the SQL dump file for writing and dump
00422  * the current content of the default database into the file.
00423  * @exception Exception thrown if dumping fails
00424  */
00425 void
00426 SQLiteConfiguration::try_dump()
00427 {
00428   if ( __default_sql ) {
00429     sqlite3 *tdb;
00430     if ( sqlite3_open(__default_file, &tdb) == SQLITE_OK ) {
00431       try {
00432         dump(tdb, __default_sql);
00433         sqlite3_close(tdb);
00434       } catch (Exception &e) {
00435         sqlite3_close(tdb);
00436         throw;
00437       }
00438     }
00439   }
00440 }
00441 
00442 void
00443 SQLiteConfiguration::import(::sqlite3 *tdb, const char *dumpfile)
00444 {
00445   FILE *f = fopen(dumpfile, "r");
00446 
00447   if (! f) {
00448     throw CouldNotOpenConfigException("Import failed, could not open dump file");
00449   }
00450 
00451   char line[4096];
00452   char *errmsg;
00453   while (! feof(f) ) {
00454     line[0] = 0;
00455     unsigned int i = 0;
00456     while (! feof(f) && (i < sizeof(line) - 1)) {
00457       if (fread(&(line[i]), 1, 1, f) == 1) {
00458         ++i;
00459         if ( (i > 2) && (line[i-1] == '\n') && (line[i-2] == ';') ) {
00460           break;
00461         }
00462       } else {
00463         break;
00464       }
00465     }
00466     line[i] = 0;
00467     if ( line[0] != 0 ) {
00468       if ( sqlite3_exec(tdb, line, 0, 0, &errmsg) != SQLITE_OK ) {
00469         ConfigurationException e(errmsg, line);
00470         sqlite3_free(errmsg);
00471         throw e;
00472       }
00473     }
00474   }
00475 
00476   fclose(f);
00477 }
00478 
00479 
00480 void
00481 SQLiteConfiguration::import_default(const char *default_sql)
00482 {
00483   char *tmpfile = strdup(TMPDIR"/tmp_default_XXXXXX");
00484   tmpfile = mktemp(tmpfile);
00485   if ( tmpfile[0] == 0 ) {
00486     throw CouldNotOpenConfigException("Failed to create temp file for default DB import");
00487   }
00488 
00489   // Import .sql file into dump database (temporary file)
00490   sqlite3 *dump_db;
00491   if ( sqlite3_open(tmpfile, &dump_db) == SQLITE_OK ) {
00492     import(dump_db, default_sql);
00493     sqlite3_close(dump_db);
00494   } else {
00495     throw CouldNotOpenConfigException("Failed to import dump file into temp DB");
00496   }
00497 
00498   // Attach dump database as "dumped"
00499   char *attach_sql;
00500   char *errmsg;
00501   if ( asprintf(&attach_sql, SQL_ATTACH_DUMPED, tmpfile) == -1 ) {
00502     throw CouldNotOpenConfigException("Could not create attachment SQL in merge");
00503   }
00504   if ( sqlite3_exec(db, attach_sql, NULL, NULL, &errmsg) != SQLITE_OK ) {
00505     free(attach_sql);
00506     CouldNotOpenConfigException e("Could not attach dump DB in merge: %s", errmsg);
00507     sqlite3_free(errmsg);
00508     throw e;
00509   }
00510   free(attach_sql);
00511 
00512   // Create "modified" database for a list of modified values, only stored in RAM
00513   if ( (sqlite3_exec(db, SQL_ATTACH_MODIFIED, NULL, NULL, &errmsg) != SQLITE_OK) ||
00514        (sqlite3_exec(db, SQL_CREATE_TABLE_MODIFIED_CONFIG, NULL, NULL, &errmsg) != SQLITE_OK) ) {
00515     CouldNotOpenConfigException ce("Could not create or attach modified memory database: %s", errmsg);
00516     sqlite3_free(errmsg);
00517     throw ce;
00518   }
00519 
00520   // Compare old and new database, copying modifications to "modified" database
00521   if ( (sqlite3_exec(db, SQL_UPDATE_MODIFIED_DB_ADDED, NULL, NULL, &errmsg) != SQLITE_OK) ||
00522        (sqlite3_exec(db, SQL_UPDATE_MODIFIED_DB_ERASED, NULL, NULL, &errmsg) != SQLITE_OK) ||
00523        (sqlite3_exec(db, SQL_UPDATE_MODIFIED_DB_CHANGED, NULL, NULL, &errmsg) != SQLITE_OK) ) {
00524     CouldNotOpenConfigException ce("Could not update modified memory database: %s", errmsg);
00525     sqlite3_free(errmsg);
00526     throw ce;
00527   }
00528 
00529   // Copy dump to defaults DB, overwriting everything
00530   if ( (sqlite3_exec(db, SQL_COPY_DUMP, NULL, NULL, &errmsg) != SQLITE_OK) ) {
00531     CouldNotOpenConfigException ce("Could not copy dump to default: %s", errmsg);
00532     sqlite3_free(errmsg);
00533     throw ce;
00534   }
00535 
00536   // Detach dumped DB, no longer required
00537   if ( sqlite3_exec(db, SQL_DETACH_DUMPED, NULL, NULL, &errmsg) != SQLITE_OK ) {
00538     CouldNotOpenConfigException e("Could not detach dump DB in import: %s", errmsg);
00539     sqlite3_free(errmsg);
00540     throw e;
00541   }
00542 
00543   unlink(tmpfile);
00544   free(tmpfile);
00545 }
00546 
00547 
00548 /** Begin SQL Transaction.
00549  * @param ttype transaction type
00550  */
00551 void
00552 SQLiteConfiguration::transaction_begin(transaction_type_t ttype)
00553 {
00554   const char *sql = "BEGIN DEFERRED TRANSACTION;";
00555   if (ttype == TRANSACTION_IMMEDIATE) {
00556     sql = "BEGIN IMMEDIATE TRANSACTION;";
00557   } else if (ttype == TRANSACTION_EXCLUSIVE) {
00558     sql = "BEGIN EXCLUSIVE TRANSACTION;";
00559   }
00560 
00561   char *errmsg;
00562   if ( (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK) ) {
00563     throw ConfigurationException("Could not begin transaction (%s)", errmsg);
00564   }
00565 }
00566 
00567 /** Commit SQL Transaction. */
00568 void
00569 SQLiteConfiguration::transaction_commit()
00570 {
00571   const char *sql = "COMMIT TRANSACTION;";
00572 
00573   char *errmsg;
00574   if ( (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK) ) {
00575     throw ConfigurationException("Could not commit transaction (%s)", errmsg);
00576   }
00577 }
00578 
00579 
00580 /** Rollback SQL Transaction. */
00581 void
00582 SQLiteConfiguration::transaction_rollback()
00583 {
00584   const char *sql = "ROLLBACK TRANSACTION;";
00585 
00586   char *errmsg;
00587   if ( (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK) ) {
00588     throw ConfigurationException("Could not rollback transaction (%s)", errmsg);
00589   }
00590 }
00591 
00592 void
00593 SQLiteConfiguration::attach_default(const char *db_file)
00594 {
00595   char *errmsg;
00596   char *attach_sql;
00597   if ( asprintf(&attach_sql, SQL_ATTACH_DEFAULTS, db_file) == -1 ) {
00598     throw CouldNotOpenConfigException("Could not create attachment SQL");
00599   }
00600   if (sqlite3_exec(db, attach_sql, NULL, NULL, &errmsg) != SQLITE_OK) {
00601     CouldNotOpenConfigException ce(sqlite3_errmsg(db));
00602     ce.append("Failed to attach default file (%s)",  db_file);
00603     free(attach_sql);
00604     throw ce;
00605   }
00606   free(attach_sql);
00607 }
00608 
00609 
00610 void
00611 SQLiteConfiguration::load(const char *name, const char *defaults_name,
00612                           const char *tag)
00613 {
00614   mutex->lock();
00615 
00616   if (__default_file) free(__default_file);
00617   if (__default_sql)  free(__default_sql);
00618   __default_file = NULL;
00619   __default_sql  = NULL;
00620 
00621   const char *try_paths[] = {__sysconfdir, __userconfdir};
00622   int try_paths_len = 2;
00623 
00624   char *host_name;
00625 
00626   if (name == NULL) {
00627     HostInfo hostinfo;
00628     if ( asprintf(&host_name, "%s.db", hostinfo.short_name()) == -1 ) {
00629       host_name = strdup(hostinfo.short_name());
00630     }
00631   } else {
00632     host_name = strdup(name);
00633   }
00634 
00635   // determine host file
00636   if (strcmp(host_name, ":memory:") == 0) {
00637     if (sqlite3_open(host_name, &db) != SQLITE_OK) {
00638       CouldNotOpenConfigException ce(sqlite3_errmsg(db));
00639       ce.append("Failed to open host db (memory)");
00640       throw ce;
00641     }
00642   } else if (host_name[0] == '/') {
00643     // absolute path, take as is
00644     if (sqlite3_open(host_name, &db) == SQLITE_OK) {
00645       __host_file = strdup(host_name);
00646     } else {
00647       CouldNotOpenConfigException ce(sqlite3_errmsg(db));
00648       ce.append("Failed to open host db (absolute)");
00649       throw ce;
00650     }
00651   } else {
00652     // try sysconfdir and userconfdir
00653     for (int i = 0; i < try_paths_len; ++i) {
00654       char *path;
00655       if (asprintf(&path, "%s/%s", try_paths[i], host_name) != -1) {
00656         if (sqlite3_open(path, &db) == SQLITE_OK) {
00657           __host_file = path;
00658           break;
00659         } else {
00660           free(path);
00661         }
00662       }
00663     }
00664     if (__host_file == NULL) {
00665       CouldNotOpenConfigException ce(sqlite3_errmsg(db));
00666       ce.append("Failed to open host db (paths)");
00667       free(host_name);
00668       throw ce;
00669     }
00670   }
00671 
00672   if (defaults_name == NULL) {
00673     defaults_name = "default.sql";
00674   }
00675 
00676   // determine default file
00677   if (strcmp(defaults_name, ":memory:") == 0) {
00678     try {
00679       attach_default(":memory:");
00680     } catch (...) {
00681       free(host_name);
00682       throw;
00683     }
00684     __default_file = strdup(":memory:");
00685   } else {
00686     if (defaults_name[0] == '/') {
00687       // absolute path, take as is
00688       __default_sql = strdup(defaults_name);
00689     } else {
00690       // try sysconfdir and userconfdir
00691       for (int i = 0; i < try_paths_len; ++i) {
00692         char *path;
00693         if (asprintf(&path, "%s/%s", try_paths[i], defaults_name) != -1) {
00694           if (access(path, F_OK | R_OK) == 0) {
00695             __default_sql = path;
00696             break;
00697           } else {
00698             free(path);
00699           }
00700         }
00701       }
00702     }
00703 
00704     // Now go for the .db filename
00705 
00706     // generate filename
00707     char *defaults_db;
00708     size_t len = strlen(defaults_name);
00709     if (fnmatch("*.sql", defaults_name, FNM_PATHNAME) == 0) {
00710       defaults_db = (char *)calloc(1, len); // yes, that's one byte less!
00711       strncpy(defaults_db, defaults_name, len - 3);
00712       strcat(defaults_db, "db");
00713     } else {
00714       defaults_db = (char *)calloc(1, len + 4);
00715       strcpy(defaults_db, defaults_name);
00716       strcat(defaults_db, ".db");
00717     }
00718 
00719     if (defaults_db[0] == '/') {
00720       try {
00721         attach_default(defaults_db);
00722         __default_file = defaults_db;
00723       } catch (...) {
00724         free(host_name);
00725         free(defaults_db);
00726         throw;
00727       }
00728     } else {
00729       // check directories
00730       for (int i = 0; i < try_paths_len; ++i) {
00731         char *path;
00732         if (asprintf(&path, "%s/%s", try_paths[i], defaults_db) != -1) {
00733           try {
00734             attach_default(path);
00735             __default_file = path;
00736             break;
00737           } catch (CouldNotOpenConfigException &e) {
00738             free(path);
00739           }
00740         }
00741       }
00742     }
00743     free(defaults_db);
00744 
00745     if (__default_file == NULL) {
00746       free(host_name);
00747       throw CouldNotOpenConfigException("Could not create default filename");
00748     }
00749   }
00750 
00751   init_dbs();
00752 
00753   if ( __default_sql )  import_default(__default_sql);
00754   free(host_name);
00755 
00756   opened = true;
00757 
00758   mutex->unlock();
00759 }
00760 
00761 
00762 /** Load config from default files.
00763  * Default file is "shorthostname.db" (shorthostname replaced by the
00764  * short host name returned by uname) and default.db).
00765  * @param tag optional tag to restore
00766  */
00767 void
00768 SQLiteConfiguration::load(const char *tag)
00769 {
00770   load(NULL, NULL, tag);
00771 }
00772 
00773 
00774 /** Copy all values from the given configuration.
00775  * All values from the given configuration are copied. Old values are not erased
00776  * so that the copied values will overwrite existing values, new values are
00777  * created, but values existent in current config but not in the copie config
00778  * will remain unchanged.
00779  * @param copyconf configuration to copy
00780  */
00781 void
00782 SQLiteConfiguration::copy(Configuration *copyconf)
00783 {
00784   copyconf->lock();
00785   transaction_begin();
00786   Configuration::ValueIterator *i = copyconf->iterator();
00787   while ( i->next() ) {
00788     if ( i->is_float() ) {
00789       set_float(i->path(), i->get_float());
00790     } else if ( i->is_int() ) {
00791       set_int(i->path(), i->get_int());
00792     } else if ( i->is_uint() ) {
00793       set_uint(i->path(), i->get_uint());
00794     } else if ( i->is_bool() ) {
00795       set_bool(i->path(), i->get_bool());
00796     } else if ( i->is_string() ) {
00797       std::string s = i->get_string();
00798       set_string(i->path(), s);
00799     }
00800   }
00801   delete i;
00802   transaction_commit();
00803   copyconf->unlock();
00804 }
00805 
00806 
00807 /** Tag this configuration version.
00808  * This creates a new tagged version of the current config. The tagged config can be
00809  * accessed via load().
00810  * @param tag tag for this version
00811  */
00812 void
00813 SQLiteConfiguration::tag(const char *tag)
00814 {
00815   char *insert_sql;
00816   char *errmsg;
00817 
00818   mutex->lock();
00819 
00820   if ( asprintf(&insert_sql, SQL_INSERT_TAG, tag) == -1 ) {
00821     mutex->unlock();
00822     throw ConfigurationException("Could not create insert statement for tagging");
00823   }
00824 
00825   if (sqlite3_exec(db, insert_sql, NULL, NULL, &errmsg) != SQLITE_OK) {
00826     ConfigurationException ce("Could not insert tag", sqlite3_errmsg(db));
00827     free(insert_sql);
00828     mutex->unlock();
00829     throw ce;
00830   }
00831 
00832   free(insert_sql);
00833   mutex->unlock();
00834 }
00835 
00836 
00837 std::list<std::string>
00838 SQLiteConfiguration::tags()
00839 {
00840   mutex->lock();
00841   std::list<std::string> l;
00842   sqlite3_stmt *stmt;
00843   const char   *tail;
00844   if ( sqlite3_prepare(db, SQL_SELECT_TAGS, -1, &stmt, &tail) != SQLITE_OK ) {
00845     mutex->unlock();
00846     throw ConfigurationException("get_type: Preparation SQL failed");
00847   }
00848   while ( sqlite3_step(stmt) == SQLITE_ROW ) {
00849     l.push_back((char *)sqlite3_column_text(stmt, 0));
00850   }
00851   sqlite3_finalize(stmt);
00852   mutex->unlock();
00853   return l;
00854 }
00855 
00856 
00857 bool
00858 SQLiteConfiguration::exists(const char *path)
00859 {
00860   mutex->lock();
00861   sqlite3_stmt *stmt;
00862   const char   *tail;
00863   bool e;
00864 
00865   if ( sqlite3_prepare(db, SQL_SELECT_TYPE, -1, &stmt, &tail) != SQLITE_OK ) {
00866     mutex->unlock();
00867     throw ConfigurationException("exists/prepare", sqlite3_errmsg(db));
00868   }
00869   if ( sqlite3_bind_text(stmt, 1, path, -1, NULL) != SQLITE_OK ) {
00870     mutex->unlock();
00871     throw ConfigurationException("exists/bind/path", sqlite3_errmsg(db));
00872   }
00873   if ( sqlite3_bind_text(stmt, 2, path, -1, NULL) != SQLITE_OK ) {
00874     mutex->unlock();
00875     throw ConfigurationException("exists/bind/path", sqlite3_errmsg(db));
00876   }
00877   e = ( sqlite3_step(stmt) == SQLITE_ROW );
00878   sqlite3_finalize(stmt);
00879 
00880   mutex->unlock();
00881   return e;
00882 }
00883 
00884 
00885 std::string
00886 SQLiteConfiguration::get_type(const char *path)
00887 {
00888   sqlite3_stmt *stmt;
00889   const char   *tail;
00890   std::string   s = "";
00891 
00892   mutex->lock();
00893 
00894   if ( sqlite3_prepare(db, SQL_SELECT_TYPE, -1, &stmt, &tail) != SQLITE_OK ) {
00895     mutex->unlock();
00896     throw ConfigurationException("get_type: Preparation SQL failed");
00897   }
00898   if ( sqlite3_bind_text(stmt, 1, path, -1, NULL) != SQLITE_OK ) {
00899     mutex->unlock();
00900     throw ConfigurationException("get_type: Binding text for path failed (1)");
00901   }
00902   if ( sqlite3_bind_text(stmt, 2, path, -1, NULL) != SQLITE_OK ) {
00903     mutex->unlock();
00904     throw ConfigurationException("get_type: Binding text for path failed (2)");
00905   }
00906   if ( sqlite3_step(stmt) == SQLITE_ROW ) {
00907     s = (char *)sqlite3_column_text(stmt, 0);
00908     sqlite3_finalize(stmt);
00909     mutex->unlock();
00910     return s;
00911   } else {
00912     sqlite3_finalize(stmt);
00913     mutex->unlock();
00914     throw ConfigEntryNotFoundException(path);
00915   }
00916 }
00917 
00918 
00919 std::string
00920 SQLiteConfiguration::get_comment(const char *path)
00921 {
00922   sqlite3_stmt *stmt;
00923   const char   *tail;
00924   std::string   s = "";
00925 
00926   mutex->lock();
00927 
00928   if ( sqlite3_prepare(db, SQL_SELECT_COMMENT, -1, &stmt, &tail) != SQLITE_OK ) {
00929     mutex->unlock();
00930     throw ConfigurationException("get_comment: Preparation SQL failed");
00931   }
00932   if ( sqlite3_bind_text(stmt, 1, path, -1, NULL) != SQLITE_OK ) {
00933     mutex->unlock();
00934     throw ConfigurationException("get_comment: Binding text for path failed (1)");
00935   }
00936   if ( sqlite3_step(stmt) == SQLITE_ROW ) {
00937     s = (char *)sqlite3_column_text(stmt, 0);
00938     sqlite3_finalize(stmt);
00939     mutex->unlock();
00940     return s;
00941   } else {
00942     sqlite3_finalize(stmt);
00943     mutex->unlock();
00944     throw ConfigEntryNotFoundException(path);
00945   }
00946 }
00947 
00948 
00949 std::string
00950 SQLiteConfiguration::get_default_comment(const char *path)
00951 {
00952   sqlite3_stmt *stmt;
00953   const char   *tail;
00954   std::string   s = "";
00955 
00956   mutex->lock();
00957 
00958   if ( sqlite3_prepare(db, SQL_SELECT_DEFAULT_COMMENT, -1, &stmt, &tail) != SQLITE_OK ) {
00959     mutex->unlock();
00960     throw ConfigurationException("get_default_comment: Preparation SQL failed");
00961   }
00962   if ( sqlite3_bind_text(stmt, 1, path, -1, NULL) != SQLITE_OK ) {
00963     mutex->unlock();
00964     throw ConfigurationException("get_default_comment: Binding text for path failed (1)");
00965   }
00966   if ( sqlite3_step(stmt) == SQLITE_ROW ) {
00967     s = (char *)sqlite3_column_text(stmt, 0);
00968     sqlite3_finalize(stmt);
00969     mutex->unlock();
00970     return s;
00971   } else {
00972     sqlite3_finalize(stmt);
00973     mutex->unlock();
00974     throw ConfigEntryNotFoundException(path);
00975   }
00976 }
00977 
00978 
00979 bool
00980 SQLiteConfiguration::is_float(const char *path)
00981 {
00982   return (get_type(path) == "float");
00983 }
00984 
00985 
00986 bool
00987 SQLiteConfiguration::is_uint(const char *path)
00988 {
00989   return (get_type(path) == "unsigned int");
00990 }
00991 
00992 
00993 bool
00994 SQLiteConfiguration::is_int(const char *path)
00995 {
00996   return (get_type(path) == "int");
00997 }
00998 
00999 
01000 bool
01001 SQLiteConfiguration::is_bool(const char *path)
01002 {
01003   return (get_type(path) == "bool");
01004 }
01005 
01006 
01007 bool
01008 SQLiteConfiguration::is_string(const char *path)
01009 {
01010   return (get_type(path) == "string");
01011 }
01012 
01013 
01014 bool
01015 SQLiteConfiguration::is_default(const char *path)
01016 {
01017   mutex->lock();
01018   sqlite3_stmt *stmt;
01019   const char   *tail;
01020   bool e;
01021 
01022   if ( sqlite3_prepare(db, SQL_SELECT_TYPE, -1, &stmt, &tail) != SQLITE_OK ) {
01023     mutex->unlock();
01024     throw ConfigurationException("is_default/prepare", sqlite3_errmsg(db));
01025   }
01026   if ( sqlite3_bind_text(stmt, 1, path, -1, NULL) != SQLITE_OK ) {
01027     mutex->unlock();
01028     throw ConfigurationException("is_default/bind/path", sqlite3_errmsg(db));
01029   }
01030   if ( sqlite3_bind_text(stmt, 2, path, -1, NULL) != SQLITE_OK ) {
01031     mutex->unlock();
01032     throw ConfigurationException("is_default/bind/path", sqlite3_errmsg(db));
01033   }
01034   e = ( (sqlite3_step(stmt) == SQLITE_ROW) && (sqlite3_column_int(stmt, 1) == 1 ));
01035   sqlite3_finalize(stmt);
01036 
01037   mutex->unlock();
01038   return e;
01039 }
01040 
01041 
01042 /** Get value.
01043  * Get a value from the database.
01044  * @param path path
01045  * @param type desired value, NULL to omit type check
01046  */
01047 sqlite3_stmt *
01048 SQLiteConfiguration::get_value(const char *path,
01049                                const char *type)
01050 {
01051   sqlite3_stmt *stmt;
01052   const char   *tail;
01053 
01054   if ( sqlite3_prepare(db, SQL_SELECT_VALUE_TYPE, -1, &stmt, &tail) != SQLITE_OK ) {
01055     throw ConfigurationException("get_value/prepare", sqlite3_errmsg(db));
01056   }
01057   if ( sqlite3_bind_text(stmt, 1, path, -1, NULL) != SQLITE_OK ) {
01058     throw ConfigurationException("get_value/bind/path (1)", sqlite3_errmsg(db));
01059   }
01060   if ( sqlite3_bind_text(stmt, 2, path, -1, NULL) != SQLITE_OK ) {
01061     throw ConfigurationException("get_value/bind/path (2)", sqlite3_errmsg(db));
01062   }
01063 
01064   if ( sqlite3_step(stmt) == SQLITE_ROW ) {
01065     if ( type == NULL ) {
01066       // type check omitted
01067       return stmt;
01068     } else {
01069       if (strcmp((char *)sqlite3_column_text(stmt, 0), type) != 0) {
01070         ConfigTypeMismatchException ce(path, (char *)sqlite3_column_text(stmt, 0), type);
01071         sqlite3_finalize(stmt);
01072         throw ce;
01073       } else {
01074         return stmt;
01075       }
01076     }
01077   } else {
01078     sqlite3_finalize(stmt);
01079     throw ConfigEntryNotFoundException(path);
01080   }
01081 }
01082 
01083 
01084 float
01085 SQLiteConfiguration::get_float(const char *path)
01086 {
01087   sqlite3_stmt *stmt;
01088   mutex->lock();
01089   try {
01090     stmt = get_value(path, "float");
01091     float f = (float)sqlite3_column_double(stmt, 1);
01092     sqlite3_finalize(stmt);
01093     mutex->unlock();
01094     return f;
01095   } catch (Exception &e) {
01096     // we can't handle
01097     mutex->unlock();
01098     throw;
01099   }
01100 }
01101 
01102 
01103 unsigned int
01104 SQLiteConfiguration::get_uint(const char *path)
01105 {
01106   sqlite3_stmt *stmt;
01107   mutex->lock();
01108   try {
01109     stmt = get_value(path, "unsigned int");
01110     int i = sqlite3_column_int(stmt, 1);
01111     sqlite3_finalize(stmt);
01112     if ( i < 0 ) {
01113       mutex->unlock();
01114       throw ConfigTypeMismatchException(path, "int", "unsigned int");
01115     }
01116     mutex->unlock();
01117     return i;
01118   } catch (Exception &e) {
01119     // we can't handle
01120     mutex->unlock();
01121     throw;
01122   }
01123 }
01124 
01125 
01126 int
01127 SQLiteConfiguration::get_int(const char *path)
01128 {
01129   sqlite3_stmt *stmt;
01130   mutex->lock();
01131   try {
01132     stmt = get_value(path, "int");
01133     int i = sqlite3_column_int(stmt, 1);
01134     sqlite3_finalize(stmt);
01135     mutex->unlock();
01136     return i;
01137   } catch (Exception &e) {
01138     // we can't handle
01139     mutex->unlock();
01140     throw;
01141   }
01142 }
01143 
01144 
01145 bool
01146 SQLiteConfiguration::get_bool(const char *path)
01147 {
01148   sqlite3_stmt *stmt;
01149   mutex->lock();
01150   try {
01151     stmt = get_value(path, "bool");
01152     int i = sqlite3_column_int(stmt, 1);
01153     sqlite3_finalize(stmt);
01154     mutex->unlock();
01155     return (i != 0);
01156   } catch (Exception &e) {
01157     // we can't handle
01158     mutex->unlock();
01159     throw;
01160   }
01161 }
01162 
01163 std::string
01164 SQLiteConfiguration::get_string(const char *path)
01165 {
01166   sqlite3_stmt *stmt;
01167   mutex->lock();
01168   try {
01169     stmt = get_value(path, "string");
01170     const char *c = (char *)sqlite3_column_text(stmt, 1);
01171     std::string rv = c;
01172     sqlite3_finalize(stmt);
01173     mutex->unlock();
01174     return rv;
01175   } catch (Exception &e) {
01176     // we can't handle
01177     e.append("SQLiteConfiguration::get_string: Fetching %s failed.", path);
01178     mutex->unlock();
01179     throw;
01180   }
01181 }
01182 
01183 
01184 Configuration::ValueIterator *
01185 SQLiteConfiguration::get_value(const char *path)
01186 {
01187   sqlite3_stmt *stmt;
01188   const char   *tail;
01189 
01190   if ( sqlite3_prepare(db, SQL_SELECT_COMPLETE, -1, &stmt, &tail) != SQLITE_OK ) {
01191     throw ConfigurationException("get_value/prepare", sqlite3_errmsg(db));
01192   }
01193   if ( sqlite3_bind_text(stmt, 1, path, -1, NULL) != SQLITE_OK ) {
01194     throw ConfigurationException("get_value/bind/path (1)", sqlite3_errmsg(db));
01195   }
01196   if ( sqlite3_bind_text(stmt, 2, path, -1, NULL) != SQLITE_OK ) {
01197     throw ConfigurationException("get_value/bind/path (2)", sqlite3_errmsg(db));
01198   }
01199 
01200   return new SQLiteValueIterator(stmt);
01201 }
01202 
01203 
01204 sqlite3_stmt *
01205 SQLiteConfiguration::prepare_update(const char *sql,
01206                                           const char *path)
01207 {
01208   sqlite3_stmt *stmt;
01209   const char   *tail;
01210 
01211   if ( sqlite3_prepare(db, sql, -1, &stmt, &tail) != SQLITE_OK ) {
01212     throw ConfigurationException("prepare_update/prepare", sqlite3_errmsg(db));
01213   }
01214   if ( sqlite3_bind_text(stmt, 2, path, -1, NULL) != SQLITE_OK ) {
01215     ConfigurationException ce("prepare_update/bind", sqlite3_errmsg(db));
01216     sqlite3_finalize(stmt);
01217     throw ce;
01218   }
01219 
01220   return stmt;
01221 }
01222 
01223 
01224 sqlite3_stmt *
01225 SQLiteConfiguration::prepare_insert_value(const char *sql, const char *type,
01226                                           const char *path)
01227 {
01228   sqlite3_stmt *stmt;
01229   const char   *tail;
01230 
01231   if ( sqlite3_prepare(db, sql, -1, &stmt, &tail) != SQLITE_OK ) {
01232     throw ConfigurationException("prepare_insert_value/prepare", sqlite3_errmsg(db));
01233   }
01234   if ( (sqlite3_bind_text(stmt, 1, path, -1, NULL) != SQLITE_OK) ||
01235        (sqlite3_bind_text(stmt, 2, type, -1, NULL) != SQLITE_OK) ) {
01236     ConfigurationException ce("prepare_insert_value/bind", sqlite3_errmsg(db));
01237     sqlite3_finalize(stmt);
01238     throw ce;
01239   }
01240 
01241   return stmt;
01242 }
01243 
01244 
01245 void
01246 SQLiteConfiguration::execute_insert_or_update(sqlite3_stmt *stmt)
01247 {
01248   if ( sqlite3_step(stmt) != SQLITE_DONE ) {
01249     ConfigurationException ce("execute_insert_or_update", sqlite3_errmsg(db));
01250     sqlite3_finalize(stmt);
01251     throw ce;
01252   }
01253 }
01254 
01255 
01256 void
01257 SQLiteConfiguration::set_float(const char *path, float f)
01258 {
01259   sqlite3_stmt *stmt = NULL;
01260 
01261   mutex->lock();
01262 
01263   try {
01264     stmt = prepare_update(SQL_UPDATE_VALUE, path);
01265     if ( (sqlite3_bind_double(stmt, 1, f) != SQLITE_OK) ) {
01266       ConfigurationException ce("set_float/update/bind", sqlite3_errmsg(db));
01267       sqlite3_finalize(stmt);
01268       mutex->unlock();
01269       throw ce;
01270     }
01271     execute_insert_or_update(stmt);
01272     sqlite3_finalize(stmt);
01273   } catch (Exception &e) {
01274     if ( stmt != NULL ) sqlite3_finalize(stmt);
01275     mutex->unlock();
01276     throw;
01277   }
01278 
01279   if ( sqlite3_changes(db) == 0 ) {
01280     // value did not exist, insert
01281 
01282     try {
01283       stmt = prepare_insert_value(SQL_INSERT_VALUE, "float", path);
01284       if ( (sqlite3_bind_double(stmt, 3, f) != SQLITE_OK) ) {
01285         ConfigurationException ce("set_float/insert/bind", sqlite3_errmsg(db));
01286         sqlite3_finalize(stmt);
01287         mutex->unlock();
01288         throw ce;
01289       }
01290       execute_insert_or_update(stmt);
01291       sqlite3_finalize(stmt);
01292     } catch (Exception &e) {
01293       if ( stmt != NULL ) sqlite3_finalize(stmt);
01294       mutex->unlock();
01295       throw;
01296     }
01297   }
01298 
01299   mutex->unlock();
01300 
01301   ChangeHandlerList *h = find_handlers(path);
01302   for (ChangeHandlerList::const_iterator i = h->begin(); i != h->end(); ++i) {
01303     (*i)->config_value_changed(path, false, f);
01304   }
01305   delete h;
01306 }
01307 
01308 
01309 void
01310 SQLiteConfiguration::set_uint(const char *path, unsigned int uint)
01311 {
01312   sqlite3_stmt *stmt = NULL;
01313 
01314   mutex->lock();
01315 
01316   try {
01317     stmt = prepare_update(SQL_UPDATE_VALUE, path);
01318     if ( (sqlite3_bind_int(stmt, 1, uint) != SQLITE_OK) ) {
01319       ConfigurationException ce("set_uint/update/bind", sqlite3_errmsg(db));
01320       sqlite3_finalize(stmt);
01321       mutex->unlock();
01322       throw ce;
01323     }
01324     execute_insert_or_update(stmt);
01325     sqlite3_finalize(stmt);
01326   } catch (Exception &e) {
01327     if ( stmt != NULL ) sqlite3_finalize(stmt);
01328     mutex->unlock();
01329     throw;
01330   }
01331 
01332   if ( sqlite3_changes(db) == 0 ) {
01333     // value did not exist, insert
01334 
01335     try {
01336       stmt = prepare_insert_value(SQL_INSERT_VALUE, "unsigned int", path);
01337       if ( (sqlite3_bind_int(stmt, 3, uint) != SQLITE_OK) ) {
01338         ConfigurationException ce("set_uint/insert/bind", sqlite3_errmsg(db));
01339         sqlite3_finalize(stmt);
01340         mutex->unlock();
01341         throw ce;
01342       }
01343       execute_insert_or_update(stmt);
01344       sqlite3_finalize(stmt);
01345     } catch (Exception &e) {
01346       if ( stmt != NULL ) sqlite3_finalize(stmt);
01347       mutex->unlock();
01348       throw;
01349     }
01350   }
01351   mutex->unlock();
01352 
01353   ChangeHandlerList *h = find_handlers(path);
01354   for (ChangeHandlerList::const_iterator i = h->begin(); i != h->end(); ++i) {
01355     (*i)->config_value_changed(path, false, uint);
01356   }
01357   delete h;
01358 }
01359 
01360 
01361 void
01362 SQLiteConfiguration::set_int(const char *path, int i)
01363 {
01364   sqlite3_stmt *stmt = NULL;
01365 
01366   mutex->lock();
01367 
01368   try {
01369     stmt = prepare_update(SQL_UPDATE_VALUE, path);
01370     if ( (sqlite3_bind_int(stmt, 1, i) != SQLITE_OK) ) {
01371       ConfigurationException ce("set_int/update/bind", sqlite3_errmsg(db));
01372       sqlite3_finalize(stmt);
01373       mutex->unlock();
01374       throw ce;
01375     }
01376     execute_insert_or_update(stmt);
01377     sqlite3_finalize(stmt);
01378   } catch (Exception &e) {
01379     if ( stmt != NULL ) sqlite3_finalize(stmt);
01380     mutex->unlock();
01381     throw;
01382   }
01383 
01384   if ( sqlite3_changes(db) == 0 ) {
01385     // value did not exist, insert
01386 
01387     try {
01388       stmt = prepare_insert_value(SQL_INSERT_VALUE, "int", path);
01389       if ( (sqlite3_bind_int(stmt, 3, i) != SQLITE_OK) ) {
01390         ConfigurationException ce("set_int/insert/bind", sqlite3_errmsg(db));
01391         sqlite3_finalize(stmt);
01392         mutex->unlock();
01393         throw ce;
01394       }
01395       execute_insert_or_update(stmt);
01396       sqlite3_finalize(stmt);
01397     } catch (Exception &e) {
01398       if ( stmt != NULL ) sqlite3_finalize(stmt);
01399       mutex->unlock();
01400       throw;
01401     }
01402   }
01403 
01404   mutex->unlock();
01405 
01406   ChangeHandlerList *h = find_handlers(path);
01407   for (ChangeHandlerList::const_iterator j = h->begin(); j != h->end(); ++j) {
01408     (*j)->config_value_changed(path, false, i);
01409   }
01410   delete h;
01411 }
01412 
01413 
01414 void
01415 SQLiteConfiguration::set_bool(const char *path, bool b)
01416 {
01417   sqlite3_stmt *stmt = NULL;
01418 
01419   mutex->lock();
01420 
01421   try {
01422     stmt = prepare_update(SQL_UPDATE_VALUE, path);
01423     if ( (sqlite3_bind_int(stmt, 1, (b ? 1 : 0)) != SQLITE_OK) ) {
01424       ConfigurationException ce("set_bool/update/bind", sqlite3_errmsg(db));
01425       sqlite3_finalize(stmt);
01426       mutex->unlock();
01427       throw ce;
01428     }
01429     execute_insert_or_update(stmt);
01430     sqlite3_finalize(stmt);
01431   } catch (Exception &e) {
01432     if ( stmt != NULL ) sqlite3_finalize(stmt);
01433     mutex->unlock();
01434     throw;
01435   }
01436 
01437   if ( sqlite3_changes(db) == 0 ) {
01438     // value did not exist, insert
01439 
01440     try {
01441       stmt = prepare_insert_value(SQL_INSERT_VALUE, "bool", path);
01442       if ( (sqlite3_bind_int(stmt, 3, (b ? 1 : 0)) != SQLITE_OK) ) {
01443         ConfigurationException ce("set_bool/insert/bind", sqlite3_errmsg(db));
01444         sqlite3_finalize(stmt);
01445         mutex->unlock();
01446         throw ce;
01447       }
01448       execute_insert_or_update(stmt);
01449       sqlite3_finalize(stmt);
01450     } catch (Exception &e) {
01451       if ( stmt != NULL ) sqlite3_finalize(stmt);
01452       mutex->unlock();
01453       throw;
01454     }
01455   }
01456 
01457   mutex->unlock();
01458 
01459   ChangeHandlerList *h = find_handlers(path);
01460   for (ChangeHandlerList::const_iterator i = h->begin(); i != h->end(); ++i) {
01461     (*i)->config_value_changed(path, false, b);
01462   }
01463   delete h;
01464 }
01465 
01466 
01467 void
01468 SQLiteConfiguration::set_string(const char *path,
01469                                 const char *s)
01470 {
01471   sqlite3_stmt *stmt = NULL;
01472 
01473   mutex->lock();
01474 
01475   size_t s_length = strlen(s);
01476 
01477   try {
01478     stmt = prepare_update(SQL_UPDATE_VALUE, path);
01479     if ( (sqlite3_bind_text(stmt, 1, s, s_length, SQLITE_STATIC) != SQLITE_OK) ) {
01480       ConfigurationException ce("set_string/update/bind", sqlite3_errmsg(db));
01481       sqlite3_finalize(stmt);
01482       mutex->unlock();
01483       throw ce;
01484     }
01485     execute_insert_or_update(stmt);
01486     sqlite3_finalize(stmt);
01487   } catch (Exception &e) {
01488     if ( stmt != NULL ) sqlite3_finalize(stmt);
01489     mutex->unlock();
01490     throw;
01491   }
01492 
01493   if ( sqlite3_changes(db) == 0 ) {
01494     // value did not exist, insert
01495 
01496     try {
01497       stmt = prepare_insert_value(SQL_INSERT_VALUE, "string", path);
01498       if ( (sqlite3_bind_text(stmt, 3, s, s_length, SQLITE_STATIC) != SQLITE_OK) ) {
01499         ConfigurationException ce("set_string/insert/bind", sqlite3_errmsg(db));
01500         sqlite3_finalize(stmt);
01501         mutex->unlock();
01502         throw ce;
01503       }
01504       execute_insert_or_update(stmt);
01505       sqlite3_finalize(stmt);
01506     } catch (Exception &e) {
01507       if ( stmt != NULL ) sqlite3_finalize(stmt);
01508       mutex->unlock();
01509       throw;
01510     }
01511   }
01512 
01513   mutex->unlock();
01514 
01515   ChangeHandlerList *h = find_handlers(path);
01516   for (ChangeHandlerList::const_iterator i = h->begin(); i != h->end(); ++i) {
01517     (*i)->config_value_changed(path, false, s);
01518   }
01519   delete h;
01520 }
01521 
01522 
01523 void
01524 SQLiteConfiguration::set_string(const char *path, std::string &s)
01525 {
01526   set_string(path, s.c_str());
01527 }
01528 
01529 
01530 void
01531 SQLiteConfiguration::set_comment(const char *path, const char *comment)
01532 {
01533   sqlite3_stmt *stmt = NULL;
01534 
01535   mutex->lock();
01536 
01537   size_t s_length = strlen(comment);
01538 
01539   try {
01540     stmt = prepare_update(SQL_UPDATE_COMMENT, path);
01541     if ( (sqlite3_bind_text(stmt, 1, comment, s_length, SQLITE_STATIC) != SQLITE_OK) ) {
01542       ConfigurationException ce("set_string/update/bind", sqlite3_errmsg(db));
01543       sqlite3_finalize(stmt);
01544       mutex->unlock();
01545       throw ce;
01546     }
01547     execute_insert_or_update(stmt);
01548     sqlite3_finalize(stmt);
01549   } catch (Exception &e) {
01550     if ( stmt != NULL ) sqlite3_finalize(stmt);
01551     mutex->unlock();
01552     throw;
01553   }
01554 
01555   if ( sqlite3_changes(db) == 0 ) {
01556     // value did not exist, insert
01557     mutex->unlock();
01558     throw ConfigurationException("set_comment", "Cannot set comment for inexistent path");
01559   }
01560 
01561   mutex->unlock();
01562 
01563   ChangeHandlerList *h = find_handlers(path);
01564   for (ChangeHandlerList::const_iterator i = h->begin(); i != h->end(); ++i) {
01565     (*i)->config_comment_changed(path, false, comment);
01566   }
01567   delete h;
01568 }
01569 
01570 
01571 void
01572 SQLiteConfiguration::set_comment(const char *path, std::string &comment)
01573 {
01574   set_comment(path, comment.c_str());
01575 }
01576 
01577 
01578 void
01579 SQLiteConfiguration::erase(const char *path)
01580 {
01581   sqlite3_stmt *stmt;
01582   const char   *tail;
01583 
01584   if ( sqlite3_prepare(db, SQL_DELETE_VALUE, -1, &stmt, &tail) != SQLITE_OK ) {
01585     throw ConfigurationException("erase/prepare", sqlite3_errmsg(db));
01586   }
01587   if ( sqlite3_bind_text(stmt, 1, path, -1, NULL) != SQLITE_OK ) {
01588     ConfigurationException ce("erase/bind", sqlite3_errmsg(db));
01589     sqlite3_finalize(stmt);
01590     throw ce;
01591   }
01592 
01593   if ( sqlite3_step(stmt) != SQLITE_DONE ) {
01594     ConfigurationException ce("erase/execute", sqlite3_errmsg(db));
01595     sqlite3_finalize(stmt);
01596     throw ce;    
01597   }
01598 
01599   sqlite3_finalize(stmt);
01600 
01601   ChangeHandlerList *h = find_handlers(path);
01602   for (ChangeHandlerList::const_iterator i = h->begin(); i != h->end(); ++i) {
01603     (*i)->config_value_erased(path, false);
01604   }
01605   delete h;
01606 }
01607 
01608 
01609 void
01610 SQLiteConfiguration::set_default_float(const char *path, float f)
01611 {
01612   sqlite3_stmt *stmt = NULL;
01613 
01614   mutex->lock();
01615 
01616   try {
01617     stmt = prepare_update(SQL_UPDATE_DEFAULT_VALUE, path);
01618     if ( (sqlite3_bind_double(stmt, 1, f) != SQLITE_OK) ) {
01619       ConfigurationException ce("set_default_float/update/bind", sqlite3_errmsg(db));
01620       sqlite3_finalize(stmt);
01621       mutex->unlock();
01622       throw ce;
01623     }
01624     execute_insert_or_update(stmt);
01625     sqlite3_finalize(stmt);
01626   } catch (Exception &e) {
01627     if ( stmt != NULL ) sqlite3_finalize(stmt);
01628     mutex->unlock();
01629     throw;
01630   }
01631 
01632   if ( sqlite3_changes(db) == 0 ) {
01633     // value did not exist, insert
01634 
01635     try {
01636       stmt = prepare_insert_value(SQL_INSERT_DEFAULT_VALUE, "float", path);
01637       if ( (sqlite3_bind_double(stmt, 3, f) != SQLITE_OK) ) {
01638         ConfigurationException ce("set_default_float/insert/bind", sqlite3_errmsg(db));
01639         sqlite3_finalize(stmt);
01640         mutex->unlock();
01641         throw ce;
01642       }
01643       execute_insert_or_update(stmt);
01644       sqlite3_finalize(stmt);
01645     } catch (Exception &e) {
01646       if ( stmt != NULL ) sqlite3_finalize(stmt);
01647       mutex->unlock();
01648       throw;
01649     }
01650   }
01651 
01652   mutex->unlock();
01653 
01654   ChangeHandlerList *h = find_handlers(path);
01655   for (ChangeHandlerList::const_iterator i = h->begin(); i != h->end(); ++i) {
01656     (*i)->config_value_changed(path, true, f);
01657   }
01658   delete h;
01659 }
01660 
01661 
01662 void
01663 SQLiteConfiguration::set_default_uint(const char *path, unsigned int uint)
01664 {
01665   sqlite3_stmt *stmt = NULL;
01666 
01667   mutex->lock();
01668 
01669   try {
01670     stmt = prepare_update(SQL_UPDATE_DEFAULT_VALUE, path);
01671     if ( (sqlite3_bind_int(stmt, 1, uint) != SQLITE_OK) ) {
01672       ConfigurationException ce("set_default_uint/update/bind", sqlite3_errmsg(db));
01673       sqlite3_finalize(stmt);
01674       mutex->unlock();
01675       throw ce;
01676     }
01677     execute_insert_or_update(stmt);
01678     sqlite3_finalize(stmt);
01679   } catch (Exception &e) {
01680     if ( stmt != NULL ) sqlite3_finalize(stmt);
01681     mutex->unlock();
01682     throw;
01683   }
01684 
01685   if ( sqlite3_changes(db) == 0 ) {
01686     // value did not exist, insert
01687 
01688     try {
01689       stmt = prepare_insert_value(SQL_INSERT_DEFAULT_VALUE, "unsigned int", path);
01690       if ( (sqlite3_bind_int(stmt, 3, uint) != SQLITE_OK) ) {
01691         ConfigurationException ce("set_default_uint/insert/bind", sqlite3_errmsg(db));
01692         sqlite3_finalize(stmt);
01693         mutex->unlock();
01694         throw ce;
01695       }
01696       execute_insert_or_update(stmt);
01697       sqlite3_finalize(stmt);
01698     } catch (Exception &e) {
01699       if ( stmt != NULL ) sqlite3_finalize(stmt);
01700       mutex->unlock();
01701       throw;
01702     }
01703   }
01704   mutex->unlock();
01705 
01706   ChangeHandlerList *h = find_handlers(path);
01707   for (ChangeHandlerList::const_iterator i = h->begin(); i != h->end(); ++i) {
01708     (*i)->config_value_changed(path, true, uint);
01709   }
01710   delete h;
01711 }
01712 
01713 
01714 void
01715 SQLiteConfiguration::set_default_int(const char *path, int i)
01716 {
01717   sqlite3_stmt *stmt = NULL;
01718   mutex->lock();
01719 
01720   try {
01721     stmt = prepare_update(SQL_UPDATE_DEFAULT_VALUE, path);
01722     if ( (sqlite3_bind_int(stmt, 1, i) != SQLITE_OK) ) {
01723       ConfigurationException ce("set_default_int/update/bind", sqlite3_errmsg(db));
01724       sqlite3_finalize(stmt);
01725       mutex->unlock();
01726       throw ce;
01727     }
01728     execute_insert_or_update(stmt);
01729     sqlite3_finalize(stmt);
01730   } catch (Exception &e) {
01731     if ( stmt != NULL ) sqlite3_finalize(stmt);
01732     mutex->unlock();
01733     throw;
01734   }
01735 
01736   if ( sqlite3_changes(db) == 0 ) {
01737     // value did not exist, insert
01738     try {
01739       stmt = prepare_insert_value(SQL_INSERT_DEFAULT_VALUE, "int", path);
01740       if ( (sqlite3_bind_int(stmt, 3, i) != SQLITE_OK) ) {
01741         ConfigurationException ce("set_default_int/insert/bind", sqlite3_errmsg(db));
01742         sqlite3_finalize(stmt);
01743         mutex->unlock();
01744         throw ce;
01745       }
01746       execute_insert_or_update(stmt);
01747       sqlite3_finalize(stmt);
01748     } catch (Exception &e) {
01749       if ( stmt != NULL ) sqlite3_finalize(stmt);
01750       mutex->unlock();
01751       throw;
01752     }
01753   }
01754 
01755   mutex->unlock();
01756 
01757   ChangeHandlerList *h = find_handlers(path);
01758   for (ChangeHandlerList::const_iterator j = h->begin(); j != h->end(); ++j) {
01759     (*j)->config_value_changed(path, true, i);
01760   }
01761   delete h;
01762 }
01763 
01764 
01765 void
01766 SQLiteConfiguration::set_default_bool(const char *path, bool b)
01767 {
01768   sqlite3_stmt *stmt = NULL;
01769 
01770   mutex->lock();
01771 
01772   try {
01773     stmt = prepare_update(SQL_UPDATE_DEFAULT_VALUE, path);
01774     if ( (sqlite3_bind_int(stmt, 1, (b ? 1 : 0)) != SQLITE_OK) ) {
01775       ConfigurationException ce("set_default_bool/update/bind", sqlite3_errmsg(db));
01776       sqlite3_finalize(stmt);
01777       mutex->unlock();
01778       throw ce;
01779     }
01780     execute_insert_or_update(stmt);
01781     sqlite3_finalize(stmt);
01782   } catch (Exception &e) {
01783     if ( stmt != NULL ) sqlite3_finalize(stmt);
01784     mutex->unlock();
01785     throw;
01786   }
01787 
01788   if ( sqlite3_changes(db) == 0 ) {
01789     // value did not exist, insert
01790 
01791     try {
01792       stmt = prepare_insert_value(SQL_INSERT_DEFAULT_VALUE, "bool", path);
01793       if ( (sqlite3_bind_int(stmt, 3, (b ? 1 : 0)) != SQLITE_OK) ) {
01794         ConfigurationException ce("set_default_bool/insert/bind", sqlite3_errmsg(db));
01795         sqlite3_finalize(stmt);
01796         mutex->unlock();
01797         throw ce;
01798       }
01799       execute_insert_or_update(stmt);
01800       sqlite3_finalize(stmt);
01801     } catch (Exception &e) {
01802       if ( stmt != NULL ) sqlite3_finalize(stmt);
01803       mutex->unlock();
01804       throw;
01805     }
01806   }
01807 
01808   mutex->unlock();
01809 
01810   ChangeHandlerList *h = find_handlers(path);
01811   for (ChangeHandlerList::const_iterator i = h->begin(); i != h->end(); ++i) {
01812     (*i)->config_value_changed(path, true, b);
01813   }
01814   delete h;
01815 }
01816 
01817 
01818 void
01819 SQLiteConfiguration::set_default_string(const char *path,
01820                                         const char *s)
01821 {
01822   sqlite3_stmt *stmt = NULL;
01823 
01824   mutex->lock();
01825   size_t s_length = strlen(s);
01826 
01827   try {
01828     stmt = prepare_update(SQL_UPDATE_DEFAULT_VALUE, path);
01829     if ( (sqlite3_bind_text(stmt, 1, s, s_length, SQLITE_STATIC) != SQLITE_OK) ) {
01830       ConfigurationException ce("set_default_string/update/bind", sqlite3_errmsg(db));
01831       sqlite3_finalize(stmt);
01832       mutex->unlock();
01833       throw ce;
01834     }
01835     execute_insert_or_update(stmt);
01836     sqlite3_finalize(stmt);
01837   } catch (Exception &e) {
01838     if ( stmt != NULL ) sqlite3_finalize(stmt);
01839     mutex->unlock();
01840     throw;
01841   }
01842 
01843   if ( sqlite3_changes(db) == 0 ) {
01844     // value did not exist, insert
01845 
01846     try {
01847       stmt = prepare_insert_value(SQL_INSERT_DEFAULT_VALUE, "string", path);
01848       if ( (sqlite3_bind_text(stmt, 3, s, s_length, SQLITE_STATIC) != SQLITE_OK) ) {
01849         ConfigurationException ce("set_default_string/insert/bind", sqlite3_errmsg(db));
01850         sqlite3_finalize(stmt);
01851         mutex->unlock();
01852         throw ce;
01853       }
01854       execute_insert_or_update(stmt);
01855       sqlite3_finalize(stmt);
01856     } catch (Exception &e) {
01857       if ( stmt != NULL ) sqlite3_finalize(stmt);
01858       mutex->unlock();
01859       throw;
01860     }
01861   }
01862 
01863   mutex->unlock();
01864 
01865   ChangeHandlerList *h = find_handlers(path);
01866   for (ChangeHandlerList::const_iterator i = h->begin(); i != h->end(); ++i) {
01867     (*i)->config_value_changed(path, true, s);
01868   }
01869   delete h;
01870 }
01871 
01872 
01873 void
01874 SQLiteConfiguration::set_default_string(const char *path, std::string &s)
01875 {
01876   set_default_string(path, s.c_str());
01877 }
01878 
01879 
01880 void
01881 SQLiteConfiguration::set_default_comment(const char *path, const char *comment)
01882 {
01883   sqlite3_stmt *stmt = NULL;
01884 
01885   mutex->lock();
01886   size_t s_length = strlen(comment);
01887 
01888   try {
01889     stmt = prepare_update(SQL_UPDATE_DEFAULT_COMMENT, path);
01890     if ( (sqlite3_bind_text(stmt, 1, comment, s_length, SQLITE_STATIC) != SQLITE_OK) ) {
01891       ConfigurationException ce("set_default_comment/update/bind", sqlite3_errmsg(db));
01892       sqlite3_finalize(stmt);
01893       mutex->unlock();
01894       throw ce;
01895     }
01896     execute_insert_or_update(stmt);
01897     sqlite3_finalize(stmt);
01898   } catch (Exception &e) {
01899     if ( stmt != NULL ) sqlite3_finalize(stmt);
01900     mutex->unlock();
01901     throw;
01902   }
01903 
01904   if ( sqlite3_changes(db) == 0 ) {
01905     // value did not exist, insert
01906     mutex->unlock();
01907     throw ConfigurationException("set_default_comment", "Cannot set comment for inexistent path");
01908   }
01909 
01910   mutex->unlock();
01911 
01912   ChangeHandlerList *h = find_handlers(path);
01913   for (ChangeHandlerList::const_iterator i = h->begin(); i != h->end(); ++i) {
01914     (*i)->config_comment_changed(path, true, comment);
01915   }
01916   delete h;
01917 }
01918 
01919 
01920 void
01921 SQLiteConfiguration::set_default_comment(const char *path, std::string &comment)
01922 {
01923   set_default_comment(path, comment.c_str());
01924 }
01925 
01926 
01927 void
01928 SQLiteConfiguration::erase_default(const char *path)
01929 {
01930   sqlite3_stmt *stmt;
01931   const char   *tail;
01932 
01933   if ( sqlite3_prepare(db, SQL_DELETE_DEFAULT_VALUE, -1, &stmt, &tail) != SQLITE_OK ) {
01934     throw ConfigurationException("erase_default/prepare", sqlite3_errmsg(db));
01935   }
01936   if ( sqlite3_bind_text(stmt, 1, path, -1, NULL) != SQLITE_OK ) {
01937     ConfigurationException ce("erase_default/bind", sqlite3_errmsg(db));
01938     sqlite3_finalize(stmt);
01939     throw ce;
01940   }
01941 
01942   if ( sqlite3_step(stmt) != SQLITE_DONE ) {
01943     ConfigurationException ce("erase_default/execute", sqlite3_errmsg(db));
01944     sqlite3_finalize(stmt);
01945     throw ce;    
01946   }
01947 
01948   sqlite3_finalize(stmt);
01949 
01950   ChangeHandlerList *h = find_handlers(path);
01951   for (ChangeHandlerList::const_iterator i = h->begin(); i != h->end(); ++i) {
01952     (*i)->config_value_erased(path, true);
01953   }
01954   delete h;
01955 }
01956 
01957 
01958 /** Lock the config.
01959  * No further changes or queries can be executed on the configuration and will block until
01960  * the config is unlocked.
01961  */
01962 void
01963 SQLiteConfiguration::lock()
01964 {
01965   mutex->lock();
01966 }
01967 
01968 
01969 /** Try to lock the config.
01970  * @see Configuration::lock()
01971  * @return true, if the lock has been aquired, false otherwise
01972  */
01973 bool
01974 SQLiteConfiguration::try_lock()
01975 {
01976   return mutex->try_lock();
01977 }
01978 
01979 /** Unlock the config.
01980  * Modifications and queries are possible again.
01981  */
01982 void
01983 SQLiteConfiguration::unlock()
01984 {
01985   mutex->unlock();
01986 }
01987 
01988 
01989 Configuration::ValueIterator *
01990 SQLiteConfiguration::iterator()
01991 {
01992   sqlite3_stmt *stmt;
01993   const char *tail;
01994 
01995   if ( sqlite3_prepare(db, SQL_SELECT_ALL, -1, &stmt, &tail) != SQLITE_OK ) {
01996     throw ConfigurationException("iterator: Preparation SQL failed");
01997   }
01998 
01999   return new SQLiteValueIterator(stmt);
02000 }
02001 
02002 
02003 Configuration::ValueIterator *
02004 SQLiteConfiguration::iterator_default()
02005 {
02006   sqlite3_stmt *stmt;
02007   const char *tail;
02008 
02009   if ( sqlite3_prepare(db, SQL_SELECT_ALL_DEFAULT, -1, &stmt, &tail) != SQLITE_OK ) {
02010     throw ConfigurationException("iterator_default: Preparation SQL failed");
02011   }
02012 
02013   return new SQLiteValueIterator(stmt);
02014 }
02015 
02016 Configuration::ValueIterator *
02017 SQLiteConfiguration::iterator_hostspecific()
02018 {
02019   sqlite3_stmt *stmt;
02020   const char *tail;
02021 
02022   if ( sqlite3_prepare(db, SQL_SELECT_ALL_HOSTSPECIFIC, -1, &stmt, &tail) != SQLITE_OK ) {
02023     throw ConfigurationException("iterator_hostspecific: Preparation SQL failed");
02024   }
02025 
02026   return new SQLiteValueIterator(stmt);
02027 }
02028 
02029 /** Iterator for modified values.
02030  * Returns an iterator that can be used to iterate over all values that have been
02031  * modified in the default database in the last load (added, erased or changed).
02032  * @return iterator over all values
02033  */
02034 SQLiteConfiguration::SQLiteValueIterator *
02035 SQLiteConfiguration::modified_iterator()
02036 {
02037   sqlite3_stmt *stmt;
02038   const char *tail;
02039 
02040   if ( sqlite3_prepare(db, SQL_SELECT_MODIFIED_ALL, -1, &stmt, &tail) != SQLITE_OK ) {
02041     throw ConfigurationException("modified_iterator: Preparation SQL failed");
02042   }
02043 
02044   return new SQLiteValueIterator(stmt);
02045 }
02046 
02047 
02048 /** Iterator with search results.
02049  * Returns an iterator that can be used to iterate over the search results. All values
02050  * whose component and path start with the given strings are returned.
02051  * A call like
02052  * @code
02053  *   config->search("");
02054  * @endcode
02055  * is effectively the same as a call to iterator().
02056  * @param path start of path
02057  * @return iterator to search results
02058  */
02059 Configuration::ValueIterator *
02060 SQLiteConfiguration::search(const char *path)
02061 {
02062   sqlite3_stmt *stmt;
02063   const char *tail;
02064 
02065   char *p;
02066   if ( asprintf(&p, "%s%%", path) == -1 ) {
02067     throw ConfigurationException("search: could not allocate component string");
02068   }
02069 
02070   if ( sqlite3_prepare(db, SQL_SELECT_COMPLETE, -1, &stmt, &tail) != SQLITE_OK ) {
02071     free(p);
02072     throw ConfigurationException("begin: Preparation SQL failed");
02073   }
02074   if ( sqlite3_bind_text(stmt, 1, p, -1, NULL) != SQLITE_OK ) {
02075     free(p);
02076     throw ConfigurationException("begin: Binding text for path failed (1)");
02077   }
02078   if ( sqlite3_bind_text(stmt, 2, p, -1, NULL) != SQLITE_OK ) {
02079     free(p);
02080     throw ConfigurationException("begin: Binding text for path failed (2)");
02081   }
02082 
02083   return new SQLiteValueIterator(stmt, p);
02084 }
02085 
02086 /** @class SQLiteConfiguration::SQLiteValueIterator config/sqlite.h
02087  * SQLite configuration value iterator.
02088  */
02089 
02090 
02091 /** Constructor.
02092  * @param stmt compiled SQLite statement
02093  * @param p pointer to arbitrary data that is freed (not deleted!) when the iterator
02094  * is deleted.
02095  */
02096 SQLiteConfiguration::SQLiteValueIterator::SQLiteValueIterator(::sqlite3_stmt *stmt, void *p)
02097 {
02098   __stmt = stmt;
02099   __p = p;
02100 }
02101 
02102 
02103 /** Destructor. */
02104 SQLiteConfiguration::SQLiteValueIterator::~SQLiteValueIterator()
02105 {
02106   if ( __stmt != NULL ) {
02107     sqlite3_finalize(__stmt);
02108     __stmt = NULL;
02109   }
02110   if ( __p != NULL ) {
02111     free(__p);
02112   }
02113 }
02114 
02115 
02116 /* Check if there is another element and advance to this if possible.
02117  * This advances to the next element, if there is one.
02118  * @return true, if another element has been reached, false otherwise
02119  */
02120 bool
02121 SQLiteConfiguration::SQLiteValueIterator::next()
02122 {
02123   if ( __stmt == NULL) return false;
02124 
02125   if (sqlite3_step(__stmt) == SQLITE_ROW ) {
02126     return true;
02127   } else {
02128     sqlite3_finalize(__stmt);
02129     __stmt = NULL;
02130     return false;
02131   }
02132 }
02133 
02134 /** Check if the current element is valid.
02135  * This is much like the classic end element for iterators. If the iterator is
02136  * invalid there all subsequent calls to next() shall fail.
02137  * @return true, if the iterator is still valid, false otherwise
02138  */
02139 bool
02140 SQLiteConfiguration::SQLiteValueIterator::valid()
02141 {
02142   return ( __stmt != NULL);
02143 }
02144 
02145 
02146 /** Path of value.
02147  * @return path of value
02148  */
02149 const char *
02150 SQLiteConfiguration::SQLiteValueIterator::path()
02151 {
02152   return (const char *)sqlite3_column_text(__stmt, 0);
02153 }
02154 
02155 
02156 /** Type of value.
02157  * @return string representation of value type.
02158  */
02159 const char *
02160 SQLiteConfiguration::SQLiteValueIterator::type()
02161 {
02162   return (const char *)sqlite3_column_text(__stmt, 1);
02163 }
02164 
02165 
02166 /** Check if current value is a float.
02167  * @return true, if value is a float, false otherwise
02168  */
02169 bool
02170 SQLiteConfiguration::SQLiteValueIterator::is_float()
02171 {
02172   return (strcmp("float", (const char *)sqlite3_column_text(__stmt, 1)) == 0);
02173 }
02174 
02175 
02176 /** Check if current value is a unsigned int.
02177  * @return true, if value is a unsigned int, false otherwise
02178  */
02179 bool
02180 SQLiteConfiguration::SQLiteValueIterator::is_uint()
02181 {
02182   return (strcmp("unsigned int", (const char *)sqlite3_column_text(__stmt, 1)) == 0);
02183 }
02184 
02185 /** Check if current value is a int.
02186  * @return true, if value is a int, false otherwise
02187  */
02188 bool
02189 SQLiteConfiguration::SQLiteValueIterator::is_int()
02190 {
02191   return (strcmp("int", (const char *)sqlite3_column_text(__stmt, 1)) == 0);
02192 }
02193 
02194 
02195 /** Check if current value is a bool.
02196  * @return true, if value is a bool, false otherwise
02197  */
02198 bool
02199 SQLiteConfiguration::SQLiteValueIterator::is_bool()
02200 {
02201   return (strcmp("bool", (const char *)sqlite3_column_text(__stmt, 1)) == 0);
02202 }
02203 
02204 
02205 /** Check if current value is a string.
02206  * @return true, if value is a string, false otherwise
02207  */
02208 bool
02209 SQLiteConfiguration::SQLiteValueIterator::is_string()
02210 {
02211   return (strcmp("string", (const char *)sqlite3_column_text(__stmt, 1)) == 0);
02212 }
02213 
02214 bool
02215 SQLiteConfiguration::SQLiteValueIterator::is_default()
02216 {
02217   return (sqlite3_column_int(__stmt, 4) == 1);
02218 }
02219 
02220 
02221 /** Get float value.
02222  * @return value
02223  */
02224 float
02225 SQLiteConfiguration::SQLiteValueIterator::get_float()
02226 {
02227   return (float)sqlite3_column_double(__stmt, 2);
02228 }
02229 
02230 
02231 /** Get unsigned int value.
02232  * @return value
02233  */
02234 unsigned int
02235 SQLiteConfiguration::SQLiteValueIterator::get_uint()
02236 {
02237   int i = sqlite3_column_int(__stmt, 2);
02238   if( i < 0 ) {
02239     return 0;
02240   } else {
02241     return i;
02242   }
02243 }
02244 
02245 
02246 /** Get int value.
02247  * @return value
02248  */
02249 int
02250 SQLiteConfiguration::SQLiteValueIterator::get_int()
02251 {
02252   return sqlite3_column_int(__stmt, 2);
02253 }
02254 
02255 /** Get bool value.
02256  * @return value
02257  */
02258 bool
02259 SQLiteConfiguration::SQLiteValueIterator::get_bool()
02260 {
02261   return (sqlite3_column_int(__stmt, 2) != 0);
02262 }
02263 
02264 /** Get string value.
02265  * @return value
02266  */
02267 std::string
02268 SQLiteConfiguration::SQLiteValueIterator::get_string()
02269 {
02270   return (const char *)sqlite3_column_text(__stmt, 2);
02271 }
02272 
02273 
02274 /** Get value as string.
02275  * @return value
02276  */
02277 std::string
02278 SQLiteConfiguration::SQLiteValueIterator::get_as_string()
02279 {
02280   return (const char *)sqlite3_column_text(__stmt, 2);
02281 }
02282 
02283 /** Get comment.
02284  * @return string comment value
02285  */
02286 std::string
02287 SQLiteConfiguration::SQLiteValueIterator::get_comment()
02288 {
02289   const char *c = (const char *)sqlite3_column_text(__stmt, 3);
02290   return c ? c : "";
02291 }
02292 
02293 /** Get modification type.
02294  * This can only be called if the iterator has been retrieved via
02295  * SQLiteConfiguration::modified_iterator(). Otherwise the return value is
02296  * always and empty string.
02297  * @return string modification type
02298  */
02299 std::string
02300 SQLiteConfiguration::SQLiteValueIterator::get_modtype()
02301 {
02302   const char *c = (const char *)sqlite3_column_text(__stmt, 4);
02303   return c ? c : "";
02304 }
02305 
02306 
02307 
02308 /** Get old value (as string).
02309  * This can only be called if the iterator has been retrieved via
02310  * SQLiteConfiguration::modified_iterator(). The value is always returned
02311  * as string, as it is meant for debugging purposes only. Otherwise the
02312  * return value is always and empty string.
02313  * @return string modification type
02314  */
02315 std::string
02316 SQLiteConfiguration::SQLiteValueIterator::get_oldvalue()
02317 {
02318   const char *c = (const char *)sqlite3_column_text(__stmt, 5);
02319   return c ? c : "";
02320 }
02321 
02322 
02323 } // end namespace fawkes
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends