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