qof-gda.c

Go to the documentation of this file.
00001 /********************************************************************
00002  *            qof-gda.c
00003  *
00004  *  Sat Sep  9 13:11:17 2006
00005  *  Copyright  2006-2008  Neil Williams
00006  *  linux@codehelp.co.uk
00007  ********************************************************************/
00008 /*
00009  *  This program is free software; you can redistribute it and/or modify
00010  *  it under the terms of the GNU General Public License as published by
00011  *  the Free Software Foundation; either version 2 of the License, or
00012  *  (at your option) any later version.
00013  *
00014  *  This program is distributed in the hope that it will be useful,
00015  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  *  GNU General Public License for more details.
00018  *
00019  *  You should have received a copy of the GNU General Public License
00020  *  along with this program; if not, write to the Free Software
00021  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00022  */
00023 
00024 #include "config.h"
00025 #include <glib.h>
00026 #include <glib/gstdio.h>
00027 #include <libintl.h>
00028 #include <libgda/libgda.h>
00029 #include "qof.h"
00030 #include "qof-gda.h"
00031 
00032 #define _(String) dgettext (GETTEXT_PACKAGE, String)
00033 #define ACCESS_METHOD  "gda"
00034 #define LIBGDA_DIR     ".qofgda"
00035 #define GDA_DBNAME     "gda-database-name"
00036 #define GDA_USERNAME   "gda-username"
00037 #define GDA_PASSWORD   "gda-password"
00038 #define GDA_DATASOURCE "qof-gda-source"
00039 
00045 static QofLogModule log_module = QOF_MOD_GDA;
00046 
00047 typedef struct
00048 {
00049     QofBackend be;
00050     GdaClient * client_pool;
00051     GdaConnection * connection;
00052     GdaCommand * command;
00053     GdaDataModel * dm;
00054     GValue * gda_value;
00055     /* GdaTransaction is now just a string label */
00056     gchar * undo_trans, * commit_trans;
00057     GError * gda_err;
00058     const GdaColumn *gda_param;
00059     GList * entities;
00060     gint dbversion;
00061     gint create_handler;
00062     gint delete_handler;
00063     const gchar *fullpath;
00064     const gchar * table_name;   /* revised each iteration. */
00065     GSList * field_list;
00066     /* QofBackendOption settings: */
00067     gchar * data_source_name;
00068     gchar * provider_name;
00069     gchar * database_name;
00070     gchar * source_description;
00071     gchar * username;
00072     gchar * password;
00073     /* end QofBackendOption */
00074     gchar *err;
00075     gchar *sql_str;
00076     gboolean error;
00077     QofIdType e_type;
00078     QofBook * book;
00079 } QGdaBackend;
00080 
00081 static gboolean
00082 qgda_determine_file_type (const gchar * path)
00083 {
00084     if (!path)
00085         return FALSE;
00086     /* accept all requests for the gda: access_method */
00087     return TRUE;
00088 }
00089 
00090 static void
00091 qgda_modify (QofBackend *be, QofInstance *inst)
00092 {
00093 
00094 }
00095 
00096 static GdaColumn *
00097 qoftype_to_gdafield (QofIdTypeConst qoftype)
00098 {
00099     GdaColumn *p;
00100 
00101     p = gda_column_new();
00102     gda_column_set_allow_null (p, TRUE);
00103     gda_column_set_g_type (p, G_TYPE_NONE);
00104     if (0 == safe_strcasecmp (qoftype, QOF_TYPE_STRING))
00105         gda_column_set_g_type (p, G_TYPE_STRING);
00106     if (0 == safe_strcasecmp (qoftype, QOF_TYPE_GUID))
00107     {
00108         gda_column_set_g_type (p, G_TYPE_STRING);
00109         gda_column_set_allow_null (p, FALSE);
00110         gda_column_set_primary_key (p, TRUE);
00111     }
00112     if (0 == safe_strcasecmp (qoftype, QOF_TYPE_CHAR))
00113         gda_column_set_g_type (p, G_TYPE_STRING);
00114     if ((0 == safe_strcasecmp (qoftype, QOF_TYPE_DOUBLE)) ||
00115         (0 == safe_strcasecmp (qoftype, QOF_TYPE_NUMERIC)) ||
00116         (0 == safe_strcasecmp (qoftype, QOF_TYPE_DEBCRED)))
00117         gda_column_set_g_type (p, G_TYPE_DOUBLE);
00118     if (0 == safe_strcasecmp (qoftype, QOF_TYPE_TIME))
00119         gda_column_set_g_type (p, G_TYPE_DATE);
00120     if (0 == safe_strcasecmp (qoftype, QOF_TYPE_BOOLEAN))
00121         gda_column_set_g_type (p, G_TYPE_BOOLEAN);
00122     if (0 == safe_strcasecmp (qoftype, QOF_TYPE_INT32))
00123         gda_column_set_g_type (p, G_TYPE_INT);
00124     if (0 == safe_strcasecmp (qoftype, QOF_TYPE_INT64))
00125         gda_column_set_g_type (p, G_TYPE_INT64);
00126 /*  if (0 == safe_strcasecmp (qoftype, QOF_TYPE_KVP))
00127         gda_column_set_g_type (p, G_TYPE_); ??
00128 */
00129     if (gda_column_get_g_type (p) == G_TYPE_NONE)
00130     {
00131         g_free (p);
00132         return NULL;
00133     }
00134     return p;
00135 }
00136 
00137 static void
00138 convert_params (QofParam * param, gpointer user_data)
00139 {
00140     GdaColumn * p;
00141     QGdaBackend * qgda_be;
00142 
00143     qgda_be = (QGdaBackend*)user_data;
00144     if (!param)
00145         return;
00146     if (0 == safe_strcasecmp (param->param_type, QOF_ID_BOOK))
00147         return;
00148     p = qoftype_to_gdafield (param->param_type);
00149     if (!p)
00150     {
00151         DEBUG (" unsupported QofParam: %s %s",
00152             param->param_name, param->param_type);
00153         return;
00154     }
00155     gda_column_set_name (p, param->param_name);
00156     gda_column_set_table (p, qgda_be->table_name);
00157     qgda_be->field_list = g_slist_append (qgda_be->field_list, p);
00158     PINFO (" name=%s table=%s type=%s", param->param_name,
00159         qgda_be->table_name, param->param_type);
00160 }
00161 
00162 static void
00163 build_table (gpointer value, gpointer user_data)
00164 {
00165     QGdaBackend * qgda_be;
00166     GdaParameterList * plist;
00167     GError * qgda_err;
00168     gint c;
00169 
00170     qgda_err = NULL;
00171     qgda_be = (QGdaBackend*)user_data;
00172     if (!gda_connection_is_opened (qgda_be->connection))
00173     {
00174         /* this probably needs to be a user error/ */
00175         PERR (" no connection to gda available");
00176         return;
00177     }
00178     PINFO (" length=%d", g_slist_length(qgda_be->field_list));
00179     c = g_slist_length(qgda_be->field_list);
00180     if (c > 0)
00181     {
00182         gchar * text;
00183 
00184         /* need a plain text SQL statement for the table. 
00185         (meaning that this will end up looking a lot like
00186         QSQLiteBackend).
00187         */
00188         text = g_strdup ("create table ... ");
00189         plist = NULL;
00190         qgda_be->command = gda_command_new (text, GDA_COMMAND_TYPE_SQL, 
00191             GDA_COMMAND_OPTION_STOP_ON_ERRORS);
00192         gda_connection_execute_non_select_command (qgda_be->connection, 
00193             qgda_be->command, plist, &qgda_err);
00194         /* plist contains a GdaParameterList of results - probably ignore. */
00195         if (qgda_err)
00196         {
00197             /* handle the error here */
00198             g_clear_error (&qgda_err);
00199         }
00200         gda_command_free (qgda_be->command);
00201     }
00202 }
00203 
00204 static void
00205 create_tables (QofObject * obj, gpointer user_data)
00206 {
00207     QGdaBackend * qgda_be;
00208 
00209     qgda_be = (QGdaBackend*)user_data;
00210     if (qgda_be->field_list)
00211         g_slist_free (qgda_be->field_list);
00212     qgda_be->field_list = NULL;
00213     qgda_be->table_name = obj->e_type;
00214     qof_class_param_foreach (obj->e_type, convert_params,
00215         qgda_be);
00216     g_slist_foreach (qgda_be->field_list, build_table, qgda_be);
00217 }
00218 
00219 static gboolean
00220 create_data_source (QGdaBackend * qgda_be)
00221 {
00222     gchar * cnc_string;
00223     QofBackend * be;
00224     GdaProviderInfo * prov;
00225 
00226     ENTER (" ");
00227     be = (QofBackend*)qgda_be;
00228     if (!qgda_be->data_source_name)
00229     {
00230         qof_error_set_be (be, qof_error_register
00231             (_("GDA: Missing data source name."), FALSE));
00232         LEAVE (" empty data source name");
00233         return FALSE;
00234     }
00235     prov = gda_config_get_provider_by_name (qgda_be->provider_name);
00236     if (!prov)
00237     {
00238         gchar * msg;
00239 
00240         msg = g_strdup_printf (_("GDA Provider '%s' could not be found"),
00241             qgda_be->provider_name);
00242         qof_error_set_be (be, qof_error_register(msg, FALSE));
00243         g_free (msg);
00244         LEAVE (" provider '%s' not found", qgda_be->provider_name);
00245         return FALSE;
00246     }
00247 /*  cnc_string = g_strconcat ("DATABASE=", qgda_be->database_name,
00248         NULL);*/
00249     cnc_string = g_strdup ("URI=/home/neil/gda-test.db");
00250     /* creates db within source if db does not exist */
00251     gda_config_save_data_source (qgda_be->data_source_name,
00252         qgda_be->provider_name, cnc_string,
00253         qgda_be->source_description, qgda_be->username,
00254         qgda_be->password, TRUE);
00255     /* create tables per QofObject */
00256     qof_object_foreach_type (create_tables, qgda_be);
00257     /* gda_connection_create_table (don't log password) */
00258     LEAVE (" created data source for %s, %s, %s, %s",
00259         qgda_be->data_source_name,
00260         qgda_be->provider_name, cnc_string,
00261         qgda_be->username);
00262     return TRUE;
00263 }
00264 
00265 static void
00266 qgda_session_begin(QofBackend *be, QofSession *session, const
00267                    gchar *book_path, gboolean ignore_lock,
00268                    gboolean create_if_nonexistent)
00269 {
00270     QGdaBackend *qgda_be;
00271     GError * qgda_err;
00272 //  GList * connection_errors, *node;
00273 
00274     qgda_err = NULL;
00275     /* cannot use ignore_lock */
00276     PINFO (" gda session start");
00277     qgda_be = (QGdaBackend*)be;
00278     be->fullpath = g_strdup (book_path);
00279     if(book_path == NULL)
00280     {
00281         qof_error_set_be (be, qof_error_register
00282             (_("GDA: No data source path specified."), FALSE));
00283         qgda_be->error = TRUE;
00284         LEAVE (" bad URL");
00285         return;
00286     }
00287     /* check/create the ~/.libgda location. */
00288     {
00289         gchar * gdahome;
00290         struct stat lg;
00291         gint ret;
00292 
00293         ret = g_stat (g_get_home_dir(), &lg);
00294         if (ret)
00295         {
00296             qof_error_set_be (be, qof_error_register
00297                 (_("GDA: Unable to locate your home directory."),
00298                 FALSE));
00299             qgda_be->error = TRUE;
00300             LEAVE (" unable to use stat on home_dir.");
00301             return;
00302         }
00303         gdahome = g_strconcat (g_get_home_dir(),
00304             "/", LIBGDA_DIR, NULL);
00305         if (!S_ISDIR (lg.st_mode) || lg.st_size == 0)
00306             ret = g_mkdir_with_parents (gdahome, 0700);
00307         if (ret)
00308         {
00309             qof_error_set_be (be, qof_error_register
00310                 (_("GDA: Unable to create a .libgda directory "
00311                 "within your home directory."), FALSE));
00312             qgda_be->error = TRUE;
00313             LEAVE (" unable to create '%s' 0700", gdahome);
00314             return;
00315         }
00316         g_free (gdahome);
00317     }
00318     {
00319         /* check data source */
00320         GdaDataSourceInfo * source;
00321         gboolean created;
00322 
00323         created = FALSE;
00324         source = gda_config_find_data_source
00325             (qgda_be->data_source_name);
00326         if (!source && create_if_nonexistent)
00327         {
00328             DEBUG (" no source, creating . . .");
00329             created = create_data_source (qgda_be);
00330         }
00331         if (!source && !created)
00332         {
00333             qof_error_set_be (be, qof_error_register
00334                 (_("GDA: No data source found at '%s' - "
00335                 "Try loading data from another file "
00336                 "and write to gda: again to create the "
00337                 "GDA data source."), TRUE));
00338             DEBUG (" no source but set not to create.");
00339             qgda_be->error = TRUE;
00340             return;
00341         }
00342     }
00343     PINFO (" trying for a connection");
00344     /* use the username and password that created the source */
00345     qgda_be->connection = gda_client_open_connection
00346         (qgda_be->client_pool, qgda_be->data_source_name,
00347         NULL, NULL, GDA_CONNECTION_OPTIONS_DONT_SHARE, &qgda_err);
00348     if (qgda_be->connection)
00349     {
00350         PINFO (" appear to be connected.");
00351         /* create tables per QofObject */
00352         qof_object_foreach_type (create_tables, qgda_be);
00353     }
00354     else
00355     {
00356         gchar * msg;
00357 
00358         msg = g_strdup_printf (
00359             _("GDA encountered an error '%s' using data source '%s'."),
00360                 qgda_err->message, qgda_be->data_source_name);
00361         qof_error_set_be (be, qof_error_register (msg, FALSE));
00362         PERR (" failed to connect to GDA: '%s'", msg);
00363         qgda_be->error = TRUE;
00364         g_free (msg);
00365     }
00366 }
00367 
00368 static void
00369 load_entities (gpointer value, gpointer user_data)
00370 {
00371     gint column_id, row_id;
00372     GdaDataModel * dm;
00373     QGdaBackend * qgda_be;
00374 
00375     qgda_be = (QGdaBackend*)user_data;
00376     dm = (GdaDataModel*)value;
00377     if (!dm)
00378     {
00379         qgda_be->error = TRUE;
00380         DEBUG (" empty data model on load");
00381         return;
00382     }
00383     for (column_id = 0; column_id < gda_data_model_get_n_columns (dm);
00384         column_id++)
00385         g_print("%s\t", gda_data_model_get_column_title (dm, column_id));
00386     g_print("\n");
00387     for (row_id = 0; row_id < gda_data_model_get_n_rows (dm); row_id++) {
00388         for (column_id = 0; column_id < gda_data_model_get_n_columns (dm);
00389              column_id++)
00390         {
00391             gchar *str;
00392 
00393             qgda_be->gda_value = (GValue*)gda_data_model_get_value_at
00394                 (dm, column_id, row_id);
00395             str = gda_value_stringify (qgda_be->gda_value);
00396             g_print ("%s\t", str);
00397             g_free (str);
00398         }
00399         g_print("\n");
00400     }
00401     g_object_unref(dm);
00402 }
00403 
00404 static void
00405 qgda_class_foreach (QofObject * obj, gpointer data)
00406 {
00407     QGdaBackend *qgda_be;
00408     GError * qgda_err;
00409 
00410     qgda_err = NULL;
00411     qgda_be = (QGdaBackend*)data;
00412     qgda_be->sql_str = g_strdup_printf(
00413         "SELECT * FROM %s;", obj->e_type);
00414     PINFO (" sql=%s", qgda_be->sql_str);
00415     qgda_be->command = gda_command_new (qgda_be->sql_str,
00416         GDA_COMMAND_TYPE_SQL, GDA_COMMAND_OPTION_STOP_ON_ERRORS);
00417     qgda_be->entities = gda_connection_execute_command (qgda_be->connection,
00418         qgda_be->command, NULL, &qgda_err);
00419     g_list_foreach (qgda_be->entities, load_entities, qgda_be);
00420     gda_command_free (qgda_be->command);
00421 }
00422 
00423 static void
00424 qgda_db_load (QofBackend *be, QofBook *book)
00425 {
00426     QGdaBackend *qgda_be;
00427 
00428     qgda_be = (QGdaBackend*)be;
00429     if (qgda_be->error)
00430         return;
00431     /* select all */
00432     qgda_be->book = book;
00433     qof_object_foreach_type(qgda_class_foreach, qgda_be);
00434 }
00435 
00436 static void
00437 qgda_write_db (QofBackend *be, QofBook *book)
00438 {
00439 
00440 }
00441 
00442 static void
00443 qgda_session_end (QofBackend *be)
00444 {
00445     QGdaBackend *qgda_be;
00446 
00447     qgda_be = (QGdaBackend*)be;
00448     if (qgda_be->dm)
00449         g_object_unref(G_OBJECT(qgda_be->dm));
00450     gda_client_close_all_connections (qgda_be->client_pool);
00451 }
00452 
00453 static void
00454 qgda_destroy_backend (QofBackend *be)
00455 {
00456     QGdaBackend *qgda_be;
00457 
00458     qgda_be = (QGdaBackend*)be;
00459     if (qgda_be)
00460         g_object_unref(G_OBJECT(qgda_be->client_pool));
00461     qof_event_unregister_handler (qgda_be->create_handler);
00462     qof_event_unregister_handler (qgda_be->delete_handler);
00463     g_free (be);
00464     g_free (qgda_be);
00465 }
00466 
00467 static void
00468 option_cb (QofBackendOption * option, gpointer data)
00469 {
00470     QGdaBackend * qgda_be;
00471 
00472     qgda_be = (QGdaBackend *) data;
00473     g_return_if_fail (qgda_be);
00474     if (0 == safe_strcmp (GDA_DBNAME, option->option_name))
00475     {
00476         qgda_be->database_name = g_strdup (option->value);
00477         PINFO (" database name = %s", qgda_be->database_name);
00478     }
00479     if (0 == safe_strcmp (GDA_USERNAME, option->option_name))
00480     {
00481         qgda_be->username = g_strdup (option->value);
00482         PINFO (" username=%s", qgda_be->username);
00483     }
00484     if (0 == safe_strcmp (GDA_PASSWORD, option->option_name))
00485     {
00486         /* don't log the password! :-) */
00487         qgda_be->password = g_strdup (option->value);
00488     }
00489     if (0 == safe_strcmp (GDA_DATASOURCE, option->option_name))
00490     {
00491         qgda_be->data_source_name = g_strdup (option->value);
00492     }
00493 }
00494 
00495 static void
00496 load_config (QofBackend * be, KvpFrame * config)
00497 {
00498     QGdaBackend *qgda_be;
00499 
00500     ENTER (" ");
00501     qgda_be = (QGdaBackend *) be;
00502     g_return_if_fail (qgda_be);
00503     qof_backend_option_foreach (config, option_cb, qgda_be);
00504     LEAVE (" ");
00505 }
00506 
00507 static KvpFrame *
00508 get_config (QofBackend * be)
00509 {
00510     QofBackendOption *option;
00511     QGdaBackend *qgda_be;
00512 
00513     if (!be)
00514     {
00515         return NULL;
00516     }
00517     ENTER (" ");
00518     qgda_be = (QGdaBackend *) be;
00519     g_return_val_if_fail (qgda_be, NULL);
00520     qof_backend_prepare_frame (be);
00521     option = g_new0 (QofBackendOption, 1);
00522     option->option_name = GDA_DBNAME;
00523     option->description =
00524         _("Name of the database to use.");
00525     option->tooltip =
00526         _("Override the default database name with "
00527         "a name of your own choice.");
00528     option->type = KVP_TYPE_STRING;
00529     option->value = (gpointer) qgda_be->database_name;
00530     qof_backend_prepare_option (be, option);
00531     g_free (option);
00532     option = g_new0 (QofBackendOption, 1);
00533     option->option_name = GDA_USERNAME;
00534     option->description =
00535         _("The username to use to access this data source.");
00536     option->tooltip =
00537         _("The username specified in the configuration of this "
00538         "data source that provides write access to the data.");
00539     option->type = KVP_TYPE_STRING;
00540     option->value = (gpointer) qgda_be->username;
00541     qof_backend_prepare_option (be, option);
00542     g_free (option);
00543     option = g_new0 (QofBackendOption, 1);
00544     option->option_name = GDA_PASSWORD;
00545     option->description =
00546         _("Password to use with the username.");
00547     option->tooltip =
00548         _("The password that is to be used with the specified "
00549         "username.");
00550     option->type = KVP_TYPE_STRING;
00551     option->value = (gpointer) qgda_be->password;
00552     qof_backend_prepare_option (be, option);
00553     g_free (option);
00554     option = g_new0 (QofBackendOption, 1);
00555     option->option_name = GDA_DATASOURCE;
00556     option->description =
00557         _("Name of this data source.");
00558     option->tooltip =
00559         _("The name of this data source as specified "
00560         "in the GDA configuration.");
00561     option->type = KVP_TYPE_STRING;
00562     option->value = (gpointer) qgda_be->password;
00563     qof_backend_prepare_option (be, option);
00564     g_free (option);
00565     LEAVE (" ");
00566     return qof_backend_complete_frame (be);
00567 }
00568 
00569 static QofBackend *
00570 qgda_backend_new (void)
00571 {
00572     QGdaBackend *qgda_be;
00573     QofBackend *be;
00574 
00575     ENTER (" ");
00576     qgda_be = g_new0(QGdaBackend, 1);
00577     be = (QofBackend*) qgda_be;
00578     qof_backend_init(be);
00579     gda_init (PACKAGE, "0.1", 0, NULL);
00580     qgda_be->client_pool = gda_client_new ();
00581     qgda_be->dbversion = QOF_OBJECT_VERSION;
00582     be->session_begin = qgda_session_begin;
00583 
00584     be->session_end = qgda_session_end;
00585     be->destroy_backend = qgda_destroy_backend;
00586     be->load = qgda_db_load;
00587     be->save_may_clobber_data = NULL;
00588     be->begin = NULL;
00589     /* commit: write to gda, commit undo record. */
00590     be->commit = qgda_modify;
00591     be->rollback = NULL;
00592     /* would need a QofQuery back to QofSqlQuery conversion. */
00593     be->compile_query = NULL;
00594     /* unused */
00595     be->free_query = NULL;
00596     be->run_query = NULL;
00597     be->counter = NULL;
00598     /* The QOF GDA backend might be multi-user */
00599     be->events_pending = NULL;
00600     be->process_events = NULL;
00601 
00602     be->sync = qgda_write_db;
00603     be->load_config = load_config;
00604     be->get_config = get_config;
00605     LEAVE (" ");
00606 
00607 /* DEBUG */
00608     qgda_be->data_source_name = "QOF_DEBUG";
00609     qgda_be->database_name = "URI=/home/neil/test.gda";
00610     qgda_be->provider_name = "XML";
00611     qgda_be->source_description = "QOF GDA debug data";
00612 /* end debug */
00613     return be;
00614 }
00615 
00616 static void
00617 qgda_provider_free (QofBackendProvider *prov)
00618 {
00619     prov->provider_name = NULL;
00620     prov->access_method = NULL;
00621     g_free (prov);
00622 }
00623 
00624 void qof_gda_provider_init(void)
00625 {
00626     QofBackendProvider *prov;
00627 
00628     bindtextdomain (PACKAGE, LOCALE_DIR);
00629     prov = g_new0 (QofBackendProvider, 1);
00630     prov->provider_name = "QOF GDA Backend Version 0.1";
00631     prov->access_method = ACCESS_METHOD;
00632     prov->partial_book_supported = TRUE;
00633     prov->backend_new = qgda_backend_new;
00634     prov->check_data_type = qgda_determine_file_type;
00635     prov->provider_free = qgda_provider_free;
00636     qof_backend_register_provider (prov);
00637 }

Generated on Thu Jan 31 22:50:25 2008 for QOF by  doxygen 1.5.4