diff --git a/plugin/sqlite/Makefile.am b/plugin/sqlite/Makefile.am new file mode 100644 index 0000000..8d3851c --- /dev/null +++ b/plugin/sqlite/Makefile.am @@ -0,0 +1,21 @@ +include $(top_srcdir)/Makefile.decl + +sqlite_lib_LTLIBRARIES = libdbsqlite.la + +AM_CPPFLAGS = \ + -I$(top_srcdir) \ + $(glib_CFLAGS) +libdbsqlite_la_LIBADD = \ + $(glib_LIBS) \ + $(top_builddir)/db/libdb.la \ + $(sqlite_LIBS) +libdbsqlite_la_LDFLAGS = -avoid-version +libdbsqlite_la_SOURCES = \ + db-sqlite.h \ + db-sqlite.c + +sqlite_libdir = $(plugin_libdir)/sqlite + +install-data-hook: + rm -f $(DESTDIR)$(sqlite_libdir)/libdbsqlite.la + rm -f $(DESTDIR)$(sqlite_libdir)/libdbsqlite.a diff --git a/plugin/sqlite/db-sqlite.c b/plugin/sqlite/db-sqlite.c new file mode 100644 index 0000000..4c0def7 --- /dev/null +++ b/plugin/sqlite/db-sqlite.c @@ -0,0 +1,256 @@ +/* + * Copyright (C) 2012 - Juan Ferrer Toribio + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "db-sqlite.h" +#include + +/** + * SECTION: db-sqlite + * @Short_description: manages a connection to a SQLite database. + * @Title: DbSqlite + * @See_also: #DbConn + * + * This class manages a connection to a SQLite database internally. This + * is accessed through the #DbConn class to internally connect, query and + * disconnect the database. + **/ +G_DEFINE_TYPE (DbSqlite, db_sqlite, DB_TYPE_PLUGIN); + +//+++++++++++++++++++++++++++++++++++++++++++++++++++ Private + +static void db_sqlite_close (DbSqlite * self) +{ + if (self->sqlite) + { + sqlite3_close (self->sqlite); + self->sqlite = NULL; + } +} + +static gboolean db_sqlite_open (DbSqlite * self, const gchar * host, + const gchar * schema, const gchar * user, const gchar * pass, GError ** err) +{ + db_sqlite_close (self); + sqlite3_open (schema, &self->sqlite); + + if (!self->sqlite) + { + g_set_error (err + ,DB_CONN_LOG_DOMAIN + ,DB_CONN_ERROR_OPENING + ,sqlite3_errmsg (self->sqlite) + ); + return FALSE; + } + + return TRUE; +} + +static void db_sqlite_set_ssl (DbSqlite * self, const gchar * ca) +{ + g_warning ("DbSqlite: SSL not supported by this plugin"); +} + +static DbResultSet * db_sqlite_query (DbSqlite * self, const gchar * sql, GError ** err) +{ + gint i, j; + gint status; + sqlite3_stmt * stmt; + GValue def = G_VALUE_INIT; + DbResult * result; + DbResultSet * set = db_result_set_new (); + + while (sql) + { + status = sqlite3_prepare_v2 (self->sqlite, sql, -1, &stmt, &sql); + + if (status != SQLITE_OK) + break; + + status = sqlite3_step (stmt); + + if (status != SQLITE_DONE && status != SQLITE_ROW) + { + sqlite3_finalize (stmt); + break; + } + + result = g_new (DbResult, 1); + result->ncols = sqlite3_column_count (stmt); + set->results = g_slist_append (set->results, result); + + // INSERT, DELETE or UPDATE + + if (result->ncols == 0) + { + result->nrows = sqlite3_changes (self->sqlite); + result->column = NULL; + result->data = NULL; + sqlite3_finalize (stmt); + continue; + } + + // SELECT + + result->nrows = 0; + result->column = g_new (DbColumn, result->ncols); + result->data = g_ptr_array_new_full (2, + (GDestroyNotify) db_row_free); + + GType gtypes[result->ncols]; + + for (i = 0; i < result->ncols; i++) + { + DbColumn * column = &result->column[i]; + column->info = 0; + column->name = g_strdup (sqlite3_column_origin_name (stmt, i)); + column->alias = g_strdup (sqlite3_column_name (stmt, i)); + column->table = g_strdup (sqlite3_column_table_name (stmt, i)); + column->table_alias = g_strdup (column->table); + column->schema = g_strdup (sqlite3_column_database_name (stmt, i)); + + if (!column->alias) + column->alias = g_strdup (column->name); + + switch (sqlite3_column_type (stmt, i)) + { + case SQLITE_INTEGER: + gtypes[i] = G_TYPE_INT; + break; + case SQLITE_FLOAT: + gtypes[i] = G_TYPE_DOUBLE; + break; + case SQLITE_BLOB: + gtypes[i] = G_TYPE_BYTES; + break; + case SQLITE_TEXT: + case SQLITE_NULL: // TODO + default: + gtypes[i] = G_TYPE_STRING; + break; + } + + if (!g_strcmp0 (column->name, "rowid")) + { + SqlObject * func = sql_function_new ("last_insert_rowid", NULL); + + g_value_init (&def, SQL_TYPE_FUNCTION); + g_value_take_object (&def, g_object_ref_sink (func)); + + column->info |= DB_COLUMN_PRI_KEY; + } + else + g_value_init (&def, GVN_TYPE_NULL); + + column->spec = gvn_param_spec_new_with_attrs (gtypes[i], FALSE, TRUE, &def); + g_value_unset (&def); + } + + for (i = 0; status == SQLITE_ROW; i++) + { + DbRow * row = db_row_new (result->ncols, i); + g_ptr_array_add (result->data, row); + + for (j = 0; j < result->ncols; j++) + if (sqlite3_column_type (stmt, j) != SQLITE_NULL) + { + GValue * value = &row->value[j]; + g_value_init (value, gtypes[j]); + + switch (gtypes[j]) + { + case G_TYPE_INT: + g_value_set_int (value, sqlite3_column_int (stmt, j)); + break; + case G_TYPE_DOUBLE: + g_value_set_double (value, sqlite3_column_double (stmt, j)); + break; + case G_TYPE_STRING: + g_value_set_string (value, (gchar *) sqlite3_column_text (stmt, j)); + break; + default: + if (gtypes[i] == G_TYPE_BYTES) + { + int len = sqlite3_column_bytes (stmt, j); + const void * blob = sqlite3_column_blob (stmt, j); + g_value_take_boxed (value, g_bytes_new (blob, len)); + } + } + } + else + g_value_init (&row->value[j], GVN_TYPE_NULL); + + status = sqlite3_step (stmt); + } + + result->nrows = i; + sqlite3_finalize (stmt); + } + + if (sqlite3_errcode (self->sqlite) != SQLITE_OK) + { + db_result_set_free (set); + set = NULL; + + g_set_error (err + ,DB_CONN_LOG_DOMAIN + ,DB_CONN_ERROR_UNKNOW + ,sqlite3_errmsg (self->sqlite) + ); + } + + return set; +} + +static void db_sqlite_kill_query (DbSqlite * self) +{ + g_warning ("DbSqlite: Kill doesn't supported by this plugin"); +} + +static void db_sqlite_value_render (SqlValue * self, SqlRender * render, SqlBatch * batch) +{ + if (G_VALUE_TYPE (self->value) == G_TYPE_BYTES) + { + // TODO: Render binary data + g_warning ("DbSqlite: Can't render binary data"); + sql_render_set_error (render); + } + else + sql_object_render (SQL_OBJECT (self), render, batch); +} + +//+++++++++++++++++++++++++++++++++++++++++++++++++++ Class + +static void db_sqlite_init (DbSqlite * self) +{ + SqlRender * render = sql_render_new ('`'); + sql_render_register_function (render, SQL_TYPE_VALUE, + (SqlRenderFunc) db_sqlite_value_render); + + DB_PLUGIN (self)->render = render; + self->sqlite = NULL; +} + +static void db_sqlite_class_init (DbSqliteClass * k) +{ + DbPluginClass * klass = DB_PLUGIN_CLASS (k); + klass->open = (DbPluginOpenFunc) db_sqlite_open; + klass->close = (DbPluginCloseFunc) db_sqlite_close; + klass->set_ssl = (DbPluginSetSSL) db_sqlite_set_ssl; + klass->query = (DbPluginQueryFunc) db_sqlite_query; + klass->kill_query = (DbPluginKillQueryFunc) db_sqlite_kill_query; +} diff --git a/plugin/sqlite/db-sqlite.h b/plugin/sqlite/db-sqlite.h new file mode 100644 index 0000000..2d42bd1 --- /dev/null +++ b/plugin/sqlite/db-sqlite.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2012 - Juan Ferrer Toribio + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef DB_SQLITE_H +#define DB_SQLITE_H + +#include +#include + +#define DB_TYPE_SQLITE (db_sqlite_get_type ()) +#define DB_SQLITE(self) (G_TYPE_CHECK_INSTANCE_CAST ((self), DB_TYPE_SQLITE, DbSqlite)) +#define DB_IS_SQLITE(self) (G_TYPE_CHECK_INSTANCE_TYPE ((self), DB_TYPE_SQLITE)) +#define DB_SQLITE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), DB_TYPE_SQLITE, DbSqliteClass)) +#define DB_IS_SQLITE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), DB_TYPE_SQLITE)) +#define DB_SQLITE_GET_CLASS(self) (G_TYPE_INSTANCE_GET_CLASS ((self), DB_TYPE_SQLITE, DbSqliteClass)) + +typedef struct _DbSqlite DbSqlite; +typedef struct _DbSqliteClass DbSqliteClass; + +struct _DbSqlite +{ + DbPlugin parent; + sqlite3 * sqlite; +}; + +struct _DbSqliteClass +{ + DbPluginClass parent; +}; + +GType db_sqlite_get_type (); +DbConn * db_sqlite_new (); + +#endif \ No newline at end of file diff --git a/vn/schema/config.db b/vn/schema/config.db new file mode 100644 index 0000000..30ff4e6 Binary files /dev/null and b/vn/schema/config.db differ