2014-07-20 21:13:56 +00:00
|
|
|
|
#include <gio/gio.h>
|
|
|
|
|
#include <gobject/gobject.h>
|
|
|
|
|
#include <libgda/libgda.h>
|
|
|
|
|
#include <sql-parser/gda-sql-parser.h>
|
|
|
|
|
#include <gobject/gvaluecollector.h>
|
|
|
|
|
|
|
|
|
|
#include "config.h"
|
2014-07-21 21:33:28 +00:00
|
|
|
|
#include "ag-app.h"
|
2014-07-20 21:13:56 +00:00
|
|
|
|
#include "ag-db.h"
|
|
|
|
|
|
|
|
|
|
#define SCHEMA_VERSION 1
|
|
|
|
|
|
|
|
|
|
static AgDb *singleton = NULL;
|
|
|
|
|
|
|
|
|
|
typedef struct _AgDbPrivate {
|
|
|
|
|
gchar *dsn;
|
|
|
|
|
GdaConnection *conn;
|
|
|
|
|
} AgDbPrivate;
|
|
|
|
|
|
2014-07-30 22:19:09 +00:00
|
|
|
|
G_DEFINE_QUARK(ag_db_error_quark, ag_db_error);
|
|
|
|
|
|
2014-07-20 21:13:56 +00:00
|
|
|
|
G_DEFINE_TYPE_WITH_PRIVATE(AgDb, ag_db, G_TYPE_OBJECT);
|
|
|
|
|
|
2014-07-30 22:33:54 +00:00
|
|
|
|
typedef enum {
|
|
|
|
|
COLUMN_ID,
|
|
|
|
|
COLUMN_NAME,
|
|
|
|
|
COLUMN_COUNTRY,
|
|
|
|
|
COLUMN_CITY,
|
|
|
|
|
COLUMN_LONGITUDE,
|
|
|
|
|
COLUMN_LATITUDE,
|
|
|
|
|
COLUMN_ALTITUDE,
|
|
|
|
|
COLUMN_YEAR,
|
|
|
|
|
COLUMN_MONTH,
|
|
|
|
|
COLUMN_DAY,
|
|
|
|
|
COLUMN_HOUR,
|
|
|
|
|
COLUMN_MINUTE,
|
|
|
|
|
COLUMN_SECOND,
|
|
|
|
|
COLUMN_TIMEZONE,
|
|
|
|
|
COLUMN_HOUSE_SYSTEM,
|
|
|
|
|
COLUMN_NOTE,
|
|
|
|
|
|
|
|
|
|
/* Leave this as the last element */
|
|
|
|
|
COLUMN_COUNT
|
|
|
|
|
} ChartTableColumn;
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
|
ChartTableColumn id;
|
|
|
|
|
gchar *name;
|
|
|
|
|
} ChartTableColumnDef;
|
|
|
|
|
|
|
|
|
|
static ChartTableColumnDef chart_table_column[] = {
|
|
|
|
|
{ COLUMN_ID, "id" },
|
|
|
|
|
{ COLUMN_NAME, "name" },
|
|
|
|
|
{ COLUMN_COUNTRY, "country_name" },
|
|
|
|
|
{ COLUMN_CITY, "city_name" },
|
|
|
|
|
{ COLUMN_LONGITUDE, "longitude" },
|
|
|
|
|
{ COLUMN_LATITUDE, "latitude" },
|
|
|
|
|
{ COLUMN_ALTITUDE, "altitude" },
|
|
|
|
|
{ COLUMN_YEAR, "year" },
|
|
|
|
|
{ COLUMN_MONTH, "month" },
|
|
|
|
|
{ COLUMN_DAY, "day" },
|
|
|
|
|
{ COLUMN_HOUR, "hour" },
|
|
|
|
|
{ COLUMN_MINUTE, "minute" },
|
|
|
|
|
{ COLUMN_SECOND, "second" },
|
|
|
|
|
{ COLUMN_TIMEZONE, "timezone" },
|
|
|
|
|
{ COLUMN_HOUSE_SYSTEM, "house_system" },
|
|
|
|
|
{ COLUMN_NOTE, "note" },
|
|
|
|
|
};
|
|
|
|
|
|
2014-07-20 21:13:56 +00:00
|
|
|
|
static void
|
|
|
|
|
ag_db_non_select(AgDb *db, const gchar *sql)
|
|
|
|
|
{
|
|
|
|
|
GdaStatement *sth;
|
|
|
|
|
gint nrows;
|
|
|
|
|
const gchar *remain;
|
|
|
|
|
GdaSqlParser *parser;
|
|
|
|
|
AgDbPrivate *priv = ag_db_get_instance_private(db);
|
|
|
|
|
GError *err = NULL;
|
|
|
|
|
|
|
|
|
|
parser = g_object_get_data(G_OBJECT(priv->conn), "parser");
|
|
|
|
|
g_assert(GDA_IS_SQL_PARSER(parser));
|
|
|
|
|
|
|
|
|
|
if ((sth = gda_sql_parser_parse_string(
|
|
|
|
|
parser,
|
|
|
|
|
sql,
|
|
|
|
|
&remain,
|
|
|
|
|
&err
|
|
|
|
|
)) == NULL) {
|
|
|
|
|
g_error(
|
|
|
|
|
"SQL error: %s",
|
|
|
|
|
(err && err->message)
|
|
|
|
|
? err->message
|
|
|
|
|
: "no reason"
|
|
|
|
|
);
|
2014-07-20 21:13:56 +00:00
|
|
|
|
}
|
2014-07-20 21:13:56 +00:00
|
|
|
|
|
|
|
|
|
if ((nrows = gda_connection_statement_execute_non_select(
|
|
|
|
|
priv->conn,
|
|
|
|
|
sth,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
&err
|
|
|
|
|
)) == -1) {
|
|
|
|
|
g_error(
|
|
|
|
|
"SQL error: %s",
|
|
|
|
|
(err && err->message)
|
|
|
|
|
? err->message
|
|
|
|
|
: "no details"
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_object_unref(sth);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
ag_db_table_exists(AgDb *db, const gchar *table)
|
|
|
|
|
{
|
|
|
|
|
GdaSqlParser *parser;
|
|
|
|
|
GdaStatement *sth;
|
|
|
|
|
GdaDataModel *result;
|
|
|
|
|
GdaSet *params;
|
|
|
|
|
GdaHolder *holder;
|
|
|
|
|
const gchar *remain;
|
|
|
|
|
gboolean ret;
|
|
|
|
|
GValue table_value = G_VALUE_INIT;
|
|
|
|
|
AgDbPrivate *priv = ag_db_get_instance_private(db);
|
|
|
|
|
GError *err = NULL;
|
|
|
|
|
|
|
|
|
|
parser = g_object_get_data(G_OBJECT(priv->conn), "parser");
|
|
|
|
|
|
|
|
|
|
if ((sth = gda_sql_parser_parse_string(
|
|
|
|
|
parser,
|
|
|
|
|
"SELECT type \n" \
|
|
|
|
|
" FROM sqlite_master \n" \
|
|
|
|
|
" WHERE type = 'table' \n" \
|
|
|
|
|
" AND name = ##name::string",
|
|
|
|
|
&remain,
|
|
|
|
|
&err
|
|
|
|
|
)) == NULL) {
|
|
|
|
|
g_error(
|
|
|
|
|
"SQL error: %s",
|
|
|
|
|
(err && err->message)
|
|
|
|
|
? err->message
|
|
|
|
|
: "no reason"
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (gda_statement_get_parameters(sth, ¶ms, &err) == FALSE) {
|
|
|
|
|
g_error(
|
|
|
|
|
"Params error: %s",
|
|
|
|
|
(err && err->message)
|
|
|
|
|
? err->message
|
|
|
|
|
: "no reason"
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
holder = gda_set_get_holder(params, "name");
|
|
|
|
|
g_value_init(&table_value, G_TYPE_STRING);
|
|
|
|
|
g_value_set_string(&table_value, table);
|
|
|
|
|
gda_holder_set_value(holder, &table_value, &err);
|
|
|
|
|
g_value_unset(&table_value);
|
|
|
|
|
|
|
|
|
|
result = gda_connection_statement_execute_select(
|
|
|
|
|
priv->conn,
|
|
|
|
|
sth,
|
|
|
|
|
params,
|
|
|
|
|
&err
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (gda_data_model_get_n_rows(result) > 0) {
|
|
|
|
|
ret = TRUE;
|
|
|
|
|
} else {
|
|
|
|
|
ret = FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_object_unref(result);
|
|
|
|
|
g_object_unref(sth);
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* ag_db_select:
|
|
|
|
|
* @db: the database object to work on
|
|
|
|
|
* @err: a #GError or NULL
|
|
|
|
|
* @sql: the query to execute
|
|
|
|
|
* @...: a NULL terminated list of key-value pairs of the query parameters
|
|
|
|
|
*
|
|
|
|
|
* Returns: (transfer full): the #GdaDataModel as the result of the query
|
|
|
|
|
*/
|
|
|
|
|
static GdaDataModel *
|
|
|
|
|
ag_db_select(AgDb *db, GError **err, const gchar *sql, ...)
|
|
|
|
|
{
|
|
|
|
|
GdaSqlParser *parser;
|
|
|
|
|
const gchar *remain;
|
|
|
|
|
GdaSet *params;
|
|
|
|
|
GdaStatement *sth;
|
|
|
|
|
GdaDataModel *ret;
|
2014-07-30 22:34:51 +00:00
|
|
|
|
gchar *error = NULL;
|
|
|
|
|
GError *local_err = NULL;
|
|
|
|
|
AgDbPrivate *priv = ag_db_get_instance_private(db);
|
2014-07-20 21:13:56 +00:00
|
|
|
|
|
|
|
|
|
parser = g_object_get_data(G_OBJECT(priv->conn), "parser");
|
|
|
|
|
|
|
|
|
|
if ((sth = gda_sql_parser_parse_string(
|
|
|
|
|
parser,
|
|
|
|
|
sql,
|
|
|
|
|
&remain,
|
2014-07-30 22:34:51 +00:00
|
|
|
|
&local_err
|
2014-07-20 21:13:56 +00:00
|
|
|
|
)) == NULL) {
|
|
|
|
|
g_error(
|
|
|
|
|
"SQL error: %s",
|
2014-07-30 22:34:51 +00:00
|
|
|
|
(local_err && local_err->message)
|
|
|
|
|
? local_err->message
|
2014-07-20 21:13:56 +00:00
|
|
|
|
: "no reason"
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-30 22:34:51 +00:00
|
|
|
|
if (!gda_statement_get_parameters(sth, ¶ms, &local_err)) {
|
2014-07-20 21:13:56 +00:00
|
|
|
|
g_error(
|
|
|
|
|
"SQL error: %s",
|
2014-07-30 22:34:51 +00:00
|
|
|
|
(local_err && local_err->message)
|
|
|
|
|
? local_err->message
|
2014-07-20 21:13:56 +00:00
|
|
|
|
: "no reason"
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (params) {
|
|
|
|
|
va_list ap;
|
|
|
|
|
|
|
|
|
|
va_start(ap, sql);
|
|
|
|
|
while (TRUE) {
|
|
|
|
|
gchar *key;
|
|
|
|
|
GdaHolder *holder;
|
|
|
|
|
GType type;
|
|
|
|
|
GValue value = G_VALUE_INIT;
|
|
|
|
|
|
|
|
|
|
if ((key = va_arg(ap, gchar *)) == NULL) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((holder = gda_set_get_holder(
|
|
|
|
|
params,
|
|
|
|
|
(const gchar *)key
|
|
|
|
|
)) == NULL) {
|
|
|
|
|
g_error("Error: holder %s is not defined in query.", key);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type = gda_holder_get_g_type(holder);
|
|
|
|
|
g_value_init(&value, type);
|
|
|
|
|
G_VALUE_COLLECT_INIT(&value, type, ap, 0, &error);
|
|
|
|
|
|
|
|
|
|
if (error) {
|
|
|
|
|
g_error("SQL GValue error: %s", error);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!gda_holder_set_value(holder, (const GValue *)&value, err)) {
|
|
|
|
|
g_error(
|
|
|
|
|
"SQL GdaHolder error: %s",
|
|
|
|
|
(*err && (*err)->message)
|
|
|
|
|
? (*err)->message
|
|
|
|
|
: "no reason"
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ret = gda_connection_statement_execute_select(priv->conn, sth, params, err);
|
|
|
|
|
g_object_unref(sth);
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
ag_db_check_version_table(AgDb *db)
|
|
|
|
|
{
|
|
|
|
|
if (ag_db_table_exists(db, "version")) {
|
|
|
|
|
GdaDataModel *result;
|
|
|
|
|
gint ret;
|
|
|
|
|
|
|
|
|
|
g_debug(
|
|
|
|
|
"Version table exists. " \
|
|
|
|
|
"Checking if db_version is %d and app_version is %s",
|
|
|
|
|
SCHEMA_VERSION,
|
|
|
|
|
PACKAGE_VERSION
|
|
|
|
|
);
|
|
|
|
|
result = ag_db_select(
|
|
|
|
|
db,
|
|
|
|
|
NULL,
|
|
|
|
|
"SELECT db_version, app_version FROM version",
|
|
|
|
|
NULL
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
ret = gda_data_model_get_n_rows(result);
|
|
|
|
|
|
|
|
|
|
if (ret < 0) {
|
|
|
|
|
g_error("No number of rows?");
|
|
|
|
|
} else if (ret > 1) {
|
|
|
|
|
g_error("Error in database. Version table has more than one rows!");
|
|
|
|
|
} else if (ret == 0) {
|
|
|
|
|
// TODO: Check schema against current one maybe? If it’s fine, we
|
|
|
|
|
// may just add a row here.
|
|
|
|
|
g_error("Error in database. Version table has no rows!");
|
|
|
|
|
} else {
|
|
|
|
|
// Version table has one row
|
|
|
|
|
const GValue *value;
|
|
|
|
|
GdaDataModelIter *iter = gda_data_model_create_iter(result);
|
|
|
|
|
gint version;
|
|
|
|
|
|
|
|
|
|
gda_data_model_iter_move_next(iter);
|
|
|
|
|
value = gda_data_model_iter_get_value_at(iter, 0);
|
|
|
|
|
|
|
|
|
|
if (!G_VALUE_HOLDS_INT(value)) {
|
|
|
|
|
g_error(
|
|
|
|
|
"Database is invalid. " \
|
|
|
|
|
"version.db_version should be an integer."
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
version = g_value_get_int(value);
|
|
|
|
|
|
|
|
|
|
if (version < SCHEMA_VERSION) {
|
|
|
|
|
// TODO
|
|
|
|
|
g_error("Update required!");
|
|
|
|
|
} else if (version > SCHEMA_VERSION) {
|
|
|
|
|
const GValue *app_version_value;
|
|
|
|
|
const gchar *app_version;
|
|
|
|
|
|
|
|
|
|
app_version_value = gda_data_model_iter_get_value_at(
|
|
|
|
|
iter,
|
|
|
|
|
1
|
|
|
|
|
);
|
|
|
|
|
app_version = g_value_get_string(
|
|
|
|
|
app_version_value
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
g_error(
|
|
|
|
|
"The version of your database is from the future. " \
|
|
|
|
|
"It seems it was created by Astrognome v%s.",
|
|
|
|
|
app_version
|
|
|
|
|
);
|
|
|
|
|
} else {
|
|
|
|
|
g_object_unref(result);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
GValue db_version = G_VALUE_INIT,
|
|
|
|
|
app_version = G_VALUE_INIT;
|
|
|
|
|
AgDbPrivate *priv = ag_db_get_instance_private(db);
|
|
|
|
|
|
|
|
|
|
g_value_init(&db_version, G_TYPE_INT);
|
|
|
|
|
g_value_init(&app_version, G_TYPE_STRING);
|
|
|
|
|
|
|
|
|
|
g_value_set_int(&db_version, SCHEMA_VERSION);
|
|
|
|
|
g_value_set_static_string(&app_version, PACKAGE_VERSION);
|
|
|
|
|
|
|
|
|
|
ag_db_non_select(
|
|
|
|
|
db,
|
|
|
|
|
"CREATE TABLE version (" \
|
|
|
|
|
"id INTEGER PRIMARY KEY, " \
|
|
|
|
|
"db_version INTEGER UNIQUE NOT NULL, " \
|
|
|
|
|
"app_version TEXT UNIQUE NOT NULL" \
|
|
|
|
|
")"
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
gda_connection_insert_row_into_table(
|
|
|
|
|
priv->conn,
|
|
|
|
|
"version",
|
|
|
|
|
NULL,
|
|
|
|
|
"db_version", &db_version,
|
|
|
|
|
"app_version", &app_version,
|
|
|
|
|
NULL
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
ag_db_check_chart_table(AgDb *db)
|
|
|
|
|
{
|
|
|
|
|
ag_db_non_select(
|
|
|
|
|
db,
|
|
|
|
|
"CREATE TABLE IF NOT EXISTS chart (" \
|
|
|
|
|
"id INTEGER PRIMARY KEY, " \
|
|
|
|
|
"name TEXT NOT NULL, " \
|
|
|
|
|
"country_name TEXT, " \
|
|
|
|
|
"city_name TEXT, " \
|
|
|
|
|
"longitude DOUBLE NOT NULL, " \
|
|
|
|
|
"latitude DOUBLE NOT NULL, " \
|
|
|
|
|
"altitude DOUBLE, " \
|
|
|
|
|
"year INTEGER NOT NULL, " \
|
|
|
|
|
"month UNSIGNED INTEGER NOT NULL, " \
|
|
|
|
|
"day UNSIGNED INTEGER NOT NULL, " \
|
|
|
|
|
"hour UNSIGNED INTEGER NOT NULL, " \
|
|
|
|
|
"minute UNSIGNED INTEGER NOT NULL, " \
|
|
|
|
|
"second UNSIGNED INTEGER NOT NULL, " \
|
|
|
|
|
"timezone DOUBLE NOT NULL, " \
|
|
|
|
|
"house_system TEXT NOT NULL, " \
|
|
|
|
|
"note TEXT" \
|
|
|
|
|
")"
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gint
|
|
|
|
|
ag_db_verify(AgDb *db)
|
|
|
|
|
{
|
|
|
|
|
ag_db_check_version_table(db);
|
|
|
|
|
ag_db_check_chart_table(db);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
ag_db_init(AgDb *db)
|
|
|
|
|
{
|
|
|
|
|
GdaSqlParser *parser;
|
|
|
|
|
GFile *user_data_dir = g_file_new_for_path(g_get_user_data_dir()),
|
|
|
|
|
*ag_data_dir = g_file_get_child(user_data_dir, "astrognome");
|
|
|
|
|
AgDbPrivate *priv = ag_db_get_instance_private(db);
|
|
|
|
|
gchar *path = g_file_get_path(ag_data_dir);
|
|
|
|
|
GError *err = NULL;
|
|
|
|
|
|
|
|
|
|
gda_init();
|
|
|
|
|
|
|
|
|
|
if (!g_file_query_exists(ag_data_dir, NULL)) {
|
|
|
|
|
gchar *path = g_file_get_path(ag_data_dir);
|
|
|
|
|
|
|
|
|
|
if (g_mkdir_with_parents(path, 0700) != 0) {
|
|
|
|
|
g_error(
|
|
|
|
|
"Data directory %s does not exist and can not be created.",
|
|
|
|
|
path
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
priv->dsn = g_strdup_printf("SQLite://DB_DIR=%s;DB_NAME=charts", path);
|
|
|
|
|
|
|
|
|
|
g_free(path);
|
|
|
|
|
g_object_unref(user_data_dir);
|
|
|
|
|
g_object_unref(ag_data_dir);
|
|
|
|
|
|
|
|
|
|
priv->conn = gda_connection_open_from_string(
|
|
|
|
|
NULL,
|
|
|
|
|
priv->dsn,
|
|
|
|
|
NULL,
|
|
|
|
|
GDA_CONNECTION_OPTIONS_NONE,
|
|
|
|
|
&err
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (priv->conn == NULL) {
|
|
|
|
|
g_error(
|
|
|
|
|
"Unable to initialize database: %s",
|
|
|
|
|
(err && err->message)
|
|
|
|
|
? err->message
|
|
|
|
|
: "no reason"
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((parser = gda_connection_create_parser(priv->conn)) == NULL) {
|
|
|
|
|
parser = gda_sql_parser_new();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_object_set_data_full(
|
|
|
|
|
G_OBJECT(priv->conn),
|
|
|
|
|
"parser",
|
|
|
|
|
parser,
|
|
|
|
|
g_object_unref
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
ag_db_verify(db);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
ag_db_dispose(GObject *gobject)
|
|
|
|
|
{
|
|
|
|
|
AgDbPrivate *priv = ag_db_get_instance_private(AG_DB(gobject));
|
|
|
|
|
|
|
|
|
|
g_object_unref(priv->conn);
|
|
|
|
|
g_free(priv->dsn);
|
|
|
|
|
G_OBJECT_CLASS(ag_db_parent_class)->dispose(gobject);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
ag_db_finalize(GObject *gobject)
|
|
|
|
|
{
|
|
|
|
|
singleton = NULL;
|
|
|
|
|
|
|
|
|
|
G_OBJECT_CLASS(ag_db_parent_class)->finalize(gobject);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
ag_db_class_init(AgDbClass *klass)
|
|
|
|
|
{
|
|
|
|
|
GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
|
|
|
|
|
|
|
|
|
|
gobject_class->dispose = ag_db_dispose;
|
|
|
|
|
gobject_class->finalize = ag_db_finalize;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AgDb *
|
|
|
|
|
ag_db_get(void)
|
|
|
|
|
{
|
|
|
|
|
if (!singleton) {
|
|
|
|
|
singleton = AG_DB(g_object_new(AG_TYPE_DB, NULL));
|
|
|
|
|
} else {
|
|
|
|
|
g_object_ref(singleton);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_assert(singleton);
|
|
|
|
|
|
|
|
|
|
return singleton;
|
|
|
|
|
}
|
2014-07-21 21:18:18 +00:00
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ag_db_save_data_free(AgDbSave *save_data)
|
|
|
|
|
{
|
|
|
|
|
if (!save_data) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (save_data->name) {
|
|
|
|
|
g_free(save_data->name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (save_data->country) {
|
|
|
|
|
g_free(save_data->country);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (save_data->city) {
|
|
|
|
|
g_free(save_data->city);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (save_data->house_system) {
|
|
|
|
|
g_free(save_data->house_system);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (save_data->note) {
|
|
|
|
|
g_free(save_data->note);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_free(save_data);
|
|
|
|
|
}
|
2014-07-21 21:33:28 +00:00
|
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
|
ag_db_save_chart(AgDb *db, AgDbSave *save_data, GtkWidget *window, GError **err)
|
|
|
|
|
{
|
|
|
|
|
GValue db_id = G_VALUE_INIT,
|
|
|
|
|
name = G_VALUE_INIT,
|
|
|
|
|
country = G_VALUE_INIT,
|
|
|
|
|
city = G_VALUE_INIT,
|
|
|
|
|
longitude = G_VALUE_INIT,
|
|
|
|
|
latitude = G_VALUE_INIT,
|
|
|
|
|
altitude = G_VALUE_INIT,
|
|
|
|
|
year = G_VALUE_INIT,
|
|
|
|
|
month = G_VALUE_INIT,
|
|
|
|
|
day = G_VALUE_INIT,
|
|
|
|
|
hour = G_VALUE_INIT,
|
|
|
|
|
minute = G_VALUE_INIT,
|
|
|
|
|
second = G_VALUE_INIT,
|
|
|
|
|
timezone = G_VALUE_INIT,
|
|
|
|
|
house_system = G_VALUE_INIT,
|
|
|
|
|
note = G_VALUE_INIT;
|
|
|
|
|
AgDbPrivate *priv = ag_db_get_instance_private(db);
|
|
|
|
|
|
|
|
|
|
g_value_init(&name, G_TYPE_STRING);
|
|
|
|
|
g_value_set_string(&name, save_data->name);
|
|
|
|
|
|
|
|
|
|
g_value_init(&country, G_TYPE_STRING);
|
|
|
|
|
g_value_set_string(&country, save_data->country);
|
|
|
|
|
|
|
|
|
|
g_value_init(&city, G_TYPE_STRING);
|
|
|
|
|
g_value_set_string(&city, save_data->city);
|
|
|
|
|
|
|
|
|
|
g_value_init(&longitude, G_TYPE_DOUBLE);
|
|
|
|
|
g_value_set_double(&longitude, save_data->longitude);
|
|
|
|
|
|
|
|
|
|
g_value_init(&latitude, G_TYPE_DOUBLE);
|
|
|
|
|
g_value_set_double(&latitude, save_data->latitude);
|
|
|
|
|
|
|
|
|
|
g_value_init(&altitude, G_TYPE_DOUBLE);
|
|
|
|
|
g_value_set_double(&altitude, save_data->altitude);
|
|
|
|
|
|
|
|
|
|
g_value_init(&year, G_TYPE_INT);
|
|
|
|
|
g_value_set_int(&year, save_data->year);
|
|
|
|
|
|
|
|
|
|
g_value_init(&month, G_TYPE_UINT);
|
|
|
|
|
g_value_set_uint(&month, save_data->month);
|
|
|
|
|
|
|
|
|
|
g_value_init(&day, G_TYPE_UINT);
|
|
|
|
|
g_value_set_uint(&day, save_data->day);
|
|
|
|
|
|
|
|
|
|
g_value_init(&hour, G_TYPE_UINT);
|
|
|
|
|
g_value_set_uint(&hour, save_data->hour);
|
|
|
|
|
|
|
|
|
|
g_value_init(&minute, G_TYPE_UINT);
|
|
|
|
|
g_value_set_uint(&minute, save_data->minute);
|
|
|
|
|
|
|
|
|
|
g_value_init(&second, G_TYPE_UINT);
|
|
|
|
|
g_value_set_uint(&second, save_data->second);
|
|
|
|
|
|
|
|
|
|
g_value_init(&timezone, G_TYPE_DOUBLE);
|
|
|
|
|
g_value_set_double(&timezone, save_data->timezone);
|
|
|
|
|
|
|
|
|
|
g_value_init(&house_system, G_TYPE_STRING);
|
|
|
|
|
g_value_set_string(&house_system, save_data->house_system);
|
|
|
|
|
|
|
|
|
|
g_value_init(¬e, G_TYPE_STRING);
|
|
|
|
|
g_value_set_string(¬e, save_data->note);
|
|
|
|
|
|
|
|
|
|
if (save_data->db_id == -1) {
|
|
|
|
|
if (!gda_connection_insert_row_into_table(
|
|
|
|
|
priv->conn,
|
|
|
|
|
"chart",
|
|
|
|
|
err,
|
|
|
|
|
"name", &name,
|
|
|
|
|
"country_name", &country,
|
|
|
|
|
"city_name", &city,
|
|
|
|
|
"longitude", &longitude,
|
|
|
|
|
"latitude", &latitude,
|
|
|
|
|
"altitude", &altitude,
|
|
|
|
|
"year", &year,
|
|
|
|
|
"month", &month,
|
|
|
|
|
"day", &day,
|
|
|
|
|
"hour", &hour,
|
|
|
|
|
"minute", &minute,
|
|
|
|
|
"second", &second,
|
|
|
|
|
"timezone", &timezone,
|
|
|
|
|
"house_system", &house_system,
|
|
|
|
|
"note", ¬e,
|
|
|
|
|
NULL
|
|
|
|
|
)) {
|
|
|
|
|
|
|
|
|
|
ag_app_message_dialog(
|
|
|
|
|
window,
|
|
|
|
|
GTK_MESSAGE_ERROR,
|
|
|
|
|
"Unable to save: %s",
|
|
|
|
|
(*err && (*err)->message)
|
|
|
|
|
? (*err)->message
|
|
|
|
|
: "no reason"
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
g_value_init(&db_id, G_TYPE_INT);
|
|
|
|
|
g_value_set_int(&db_id, save_data->db_id);
|
|
|
|
|
|
|
|
|
|
if (!gda_connection_update_row_in_table(
|
|
|
|
|
priv->conn,
|
|
|
|
|
"chart",
|
|
|
|
|
"id",
|
|
|
|
|
&db_id,
|
|
|
|
|
err,
|
|
|
|
|
"name", &name,
|
|
|
|
|
"country_name", &country,
|
|
|
|
|
"city_name", &city,
|
|
|
|
|
"longitude", &longitude,
|
|
|
|
|
"latitude", &latitude,
|
|
|
|
|
"altitude", &altitude,
|
|
|
|
|
"year", &year,
|
|
|
|
|
"month", &month,
|
|
|
|
|
"day", &day,
|
|
|
|
|
"hour", &hour,
|
|
|
|
|
"minute", &minute,
|
|
|
|
|
"second", &second,
|
|
|
|
|
"timezone", &timezone,
|
|
|
|
|
"house_system", &house_system,
|
|
|
|
|
"note", ¬e,
|
|
|
|
|
NULL
|
|
|
|
|
)) {
|
|
|
|
|
|
|
|
|
|
ag_app_message_dialog(
|
|
|
|
|
window,
|
|
|
|
|
GTK_MESSAGE_ERROR,
|
|
|
|
|
"Unable to save: %s",
|
|
|
|
|
(*err && (*err)->message)
|
|
|
|
|
? (*err)->message
|
|
|
|
|
: "no reason"
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_value_unset(&db_id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_value_unset(¬e);
|
|
|
|
|
g_value_unset(&house_system);
|
|
|
|
|
g_value_unset(&timezone);
|
|
|
|
|
g_value_unset(&second);
|
|
|
|
|
g_value_unset(&minute);
|
|
|
|
|
g_value_unset(&hour);
|
|
|
|
|
g_value_unset(&day);
|
|
|
|
|
g_value_unset(&month);
|
|
|
|
|
g_value_unset(&year);
|
|
|
|
|
g_value_unset(&altitude);
|
|
|
|
|
g_value_unset(&latitude);
|
|
|
|
|
g_value_unset(&longitude);
|
|
|
|
|
g_value_unset(&city);
|
|
|
|
|
g_value_unset(&country);
|
|
|
|
|
g_value_unset(&name);
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
2014-07-22 10:25:00 +00:00
|
|
|
|
|
|
|
|
|
GList *
|
|
|
|
|
ag_db_get_chart_list(AgDb *db, GError **err)
|
|
|
|
|
{
|
|
|
|
|
GdaDataModelIter *iter;
|
|
|
|
|
GList *ret = NULL;
|
|
|
|
|
GdaDataModel *result = ag_db_select(
|
|
|
|
|
db,
|
|
|
|
|
err,
|
|
|
|
|
"SELECT id, name FROM chart ORDER BY name",
|
|
|
|
|
NULL
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (result == NULL) {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
iter = gda_data_model_create_iter(result);
|
|
|
|
|
|
|
|
|
|
while (gda_data_model_iter_move_next(iter)) {
|
|
|
|
|
const GValue *value;
|
|
|
|
|
AgDbSave *save_data = g_new0(AgDbSave, 1);
|
|
|
|
|
|
|
|
|
|
value = gda_data_model_iter_get_value_at(iter, 0);
|
|
|
|
|
save_data->db_id = g_value_get_int(value);
|
|
|
|
|
|
|
|
|
|
value = gda_data_model_iter_get_value_at(iter, 1);
|
|
|
|
|
save_data->name = g_strdup(g_value_get_string(value));
|
|
|
|
|
|
|
|
|
|
ret = g_list_prepend(ret, save_data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return g_list_reverse(ret);
|
|
|
|
|
}
|
2014-07-30 22:33:54 +00:00
|
|
|
|
|
|
|
|
|
AgDbSave *
|
|
|
|
|
ag_db_get_chart_data_by_id(AgDb *db, guint row_id, GError **err)
|
|
|
|
|
{
|
|
|
|
|
AgDbSave *save_data;
|
|
|
|
|
const GValue *value;
|
|
|
|
|
GdaValueAttribute attributes;
|
|
|
|
|
gchar *query,
|
|
|
|
|
*columns;
|
|
|
|
|
guint i;
|
|
|
|
|
GdaDataModel *result;
|
|
|
|
|
GError *local_err = NULL;
|
|
|
|
|
|
|
|
|
|
columns = NULL;
|
|
|
|
|
|
|
|
|
|
for (i = 1; i < COLUMN_COUNT; i++) {
|
|
|
|
|
gchar *tmp;
|
|
|
|
|
|
|
|
|
|
if (i == 1) {
|
|
|
|
|
columns = g_strjoin(
|
|
|
|
|
", ",
|
|
|
|
|
chart_table_column[0].name,
|
|
|
|
|
chart_table_column[1].name,
|
|
|
|
|
NULL
|
|
|
|
|
);
|
|
|
|
|
} else {
|
|
|
|
|
tmp = g_strjoin(", ", columns, chart_table_column[i].name, NULL);
|
|
|
|
|
g_free(columns);
|
|
|
|
|
columns = tmp;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
query = g_strdup_printf(
|
|
|
|
|
"SELECT %s FROM chart WHERE id = ##id::gint",
|
|
|
|
|
columns
|
|
|
|
|
);
|
|
|
|
|
g_free(columns);
|
|
|
|
|
|
|
|
|
|
result = ag_db_select(db, &local_err, query, "id", row_id, NULL);
|
|
|
|
|
g_free(query);
|
|
|
|
|
|
|
|
|
|
if (local_err && (local_err->message)) {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (gda_data_model_get_n_rows(result) < 1) {
|
|
|
|
|
g_set_error(
|
|
|
|
|
err,
|
|
|
|
|
AG_DB_ERROR, AG_DB_ERROR_NO_CHART,
|
|
|
|
|
"Chart does not exist"
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
save_data = g_new0(AgDbSave, 1);
|
|
|
|
|
|
|
|
|
|
/* id */
|
|
|
|
|
value = gda_data_model_get_value_at(result, COLUMN_ID, 0, NULL);
|
|
|
|
|
save_data->db_id = g_value_get_int(value);
|
|
|
|
|
|
|
|
|
|
/* name */
|
|
|
|
|
value = gda_data_model_get_value_at(result, COLUMN_NAME, 0, NULL);
|
|
|
|
|
save_data->name = g_strdup(g_value_get_string(value));
|
|
|
|
|
|
|
|
|
|
/* country */
|
|
|
|
|
value = gda_data_model_get_value_at(result, COLUMN_COUNTRY, 0, NULL);
|
|
|
|
|
attributes = gda_data_model_get_attributes_at(result, COLUMN_COUNTRY, 0);
|
|
|
|
|
|
|
|
|
|
if (attributes | GDA_VALUE_ATTR_IS_NULL) {
|
|
|
|
|
save_data->country = NULL;
|
|
|
|
|
} else {
|
|
|
|
|
save_data->country = g_strdup(g_value_get_string(value));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
value = gda_data_model_get_value_at(result, COLUMN_CITY, 0, NULL);
|
|
|
|
|
attributes = gda_data_model_get_attributes_at(result, COLUMN_CITY, 0);
|
|
|
|
|
|
|
|
|
|
if (attributes | GDA_VALUE_ATTR_IS_NULL) {
|
|
|
|
|
save_data->city = NULL;
|
|
|
|
|
} else {
|
|
|
|
|
save_data->city = g_strdup(g_value_get_string(value));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
value = gda_data_model_get_value_at(
|
|
|
|
|
result,
|
|
|
|
|
COLUMN_LONGITUDE,
|
|
|
|
|
0,
|
|
|
|
|
NULL
|
|
|
|
|
);
|
|
|
|
|
save_data->longitude = g_value_get_double(value);
|
|
|
|
|
|
|
|
|
|
value = gda_data_model_get_value_at(
|
|
|
|
|
result,
|
|
|
|
|
COLUMN_LATITUDE,
|
|
|
|
|
0,
|
|
|
|
|
NULL
|
|
|
|
|
);
|
|
|
|
|
save_data->latitude = g_value_get_double(value);
|
|
|
|
|
|
|
|
|
|
value = gda_data_model_get_value_at(result, COLUMN_ALTITUDE, 0, NULL);
|
|
|
|
|
attributes = gda_data_model_get_attributes_at(result, COLUMN_ALTITUDE, 0);
|
|
|
|
|
|
|
|
|
|
if (attributes | GDA_VALUE_ATTR_IS_NULL) {
|
|
|
|
|
/* TODO: this value should be macroified */
|
|
|
|
|
save_data->altitude = 280.0;
|
|
|
|
|
} else {
|
|
|
|
|
save_data->altitude = g_value_get_double(value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
value = gda_data_model_get_value_at(result, COLUMN_YEAR, 0, NULL);
|
|
|
|
|
save_data->year = g_value_get_int(value);
|
|
|
|
|
|
|
|
|
|
value = gda_data_model_get_value_at(
|
|
|
|
|
result,
|
|
|
|
|
COLUMN_MONTH,
|
|
|
|
|
0,
|
|
|
|
|
NULL
|
|
|
|
|
);
|
|
|
|
|
save_data->month = g_value_get_uint(value);
|
|
|
|
|
|
|
|
|
|
value = gda_data_model_get_value_at(result, COLUMN_DAY, 0, NULL);
|
|
|
|
|
save_data->day = g_value_get_uint(value);
|
|
|
|
|
|
|
|
|
|
value = gda_data_model_get_value_at(result, COLUMN_HOUR, 0, NULL);
|
|
|
|
|
save_data->hour = g_value_get_uint(value);
|
|
|
|
|
|
|
|
|
|
value = gda_data_model_get_value_at(
|
|
|
|
|
result,
|
|
|
|
|
COLUMN_MINUTE,
|
|
|
|
|
0,
|
|
|
|
|
NULL
|
|
|
|
|
);
|
|
|
|
|
save_data->minute = g_value_get_uint(value);
|
|
|
|
|
|
|
|
|
|
value = gda_data_model_get_value_at(
|
|
|
|
|
result,
|
|
|
|
|
COLUMN_SECOND,
|
|
|
|
|
0,
|
|
|
|
|
NULL
|
|
|
|
|
);
|
|
|
|
|
save_data->second = g_value_get_uint(value);
|
|
|
|
|
|
|
|
|
|
value = gda_data_model_get_value_at(
|
|
|
|
|
result,
|
|
|
|
|
COLUMN_TIMEZONE,
|
|
|
|
|
0,
|
|
|
|
|
NULL
|
|
|
|
|
);
|
|
|
|
|
save_data->timezone = g_value_get_double(value);
|
|
|
|
|
|
|
|
|
|
value = gda_data_model_get_value_at(
|
|
|
|
|
result,
|
|
|
|
|
COLUMN_HOUSE_SYSTEM,
|
|
|
|
|
0,
|
|
|
|
|
NULL
|
|
|
|
|
);
|
|
|
|
|
save_data->house_system = g_strdup(g_value_get_string(value));
|
|
|
|
|
|
|
|
|
|
value = gda_data_model_get_value_at(result, COLUMN_NOTE, 0, NULL);
|
|
|
|
|
attributes = gda_data_model_get_attributes_at(result, 15, 0);
|
|
|
|
|
|
|
|
|
|
if (attributes | GDA_VALUE_ATTR_IS_NULL) {
|
|
|
|
|
save_data->note = NULL;
|
|
|
|
|
} else {
|
|
|
|
|
save_data->note = g_strdup(g_value_get_string(value));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_object_unref(result);
|
|
|
|
|
|
|
|
|
|
return save_data;
|
|
|
|
|
}
|
2014-07-31 16:11:32 +00:00
|
|
|
|
|
|
|
|
|
static gint
|
|
|
|
|
string_collate(const gchar *str1, const gchar *str2)
|
|
|
|
|
{
|
|
|
|
|
if (((str1 == NULL) || (str2 == NULL)) && (str1 != str2)) {
|
|
|
|
|
return (str1 == NULL) ? -1 : 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (str1 == str2) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return g_utf8_collate(str1, str2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
|
ag_db_save_identical(const AgDbSave *a, const AgDbSave *b)
|
|
|
|
|
{
|
|
|
|
|
if (a == b) {
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((a == NULL) || (b == NULL)) {
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (string_collate(a->name, b->name) != 0) {
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (string_collate(a->country, b->country) != 0) {
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (string_collate(a->city, b->city) != 0) {
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (a->longitude != b->longitude) {
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (a->latitude != b->latitude) {
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (a->altitude != b->altitude) {
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (a->year != b->year) {
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (a->month != b->month) {
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (a->day != b->day) {
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (a->hour != b->hour) {
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (a->minute != b->minute) {
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (a->second != b->second) {
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (a->timezone != b->timezone) {
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (string_collate(a->house_system, b->house_system) != 0) {
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (string_collate(a->note, b->note) != 0) {
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|