QOF 0.8.4
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 #include "qofsql-p.h"
00032 
00033 #define _(String) dgettext (GETTEXT_PACKAGE, String)
00034 #define ACCESS_METHOD  "gda"
00035 #define LIBGDA_DIR     ".qofgda"
00036 #define GDA_DBNAME     "gda-database-name"
00037 #define GDA_USERNAME   "gda-username"
00038 #define GDA_PASSWORD   "gda-password"
00039 #define GDA_DATASOURCE "qof-gda-source"
00040 
00042 #define ONLY_DEBUG 1
00043 
00049 static QofLogModule log_module = QOF_MOD_GDA;
00050 
00051 typedef struct
00052 {
00053     QofBackend be;
00054     GdaClient * client_pool;
00055     GdaConnection * connection;
00056     GdaCommand * command;
00057     GValue * gda_value;
00058     /* GdaTransaction is now just a string label */
00059     gchar * undo_trans, * commit_trans;
00060     GError * gda_err;
00061     GList * entities;
00062     gint dbversion;
00063     gint create_handler;
00064     gint delete_handler;
00065     const gchar *fullpath;
00066     const gchar * table_name;   /* revised each iteration. */
00067     /* QofBackendOption settings: */
00068     gchar * data_source_name;
00069     gchar * provider_name;
00070     gchar * database_name;
00071     gchar * source_description;
00072     gchar * username;
00073     gchar * password;
00074     gchar * gdahome;
00075     /* end QofBackendOption */
00076     gchar *err;
00077     gchar *sql_str;
00079     GList *dirty_list;
00081     gboolean exists;
00082     gboolean error;
00083     QofIdType e_type;
00084     QofBook * book;
00085     QofErrorId err_delete, err_insert, err_update, err_create;
00086 } QGdaBackend;
00087 
00088 static gboolean
00089 qgda_determine_file_type (const gchar * path)
00090 {
00091     if (!path)
00092         return FALSE;
00093     /* accept all requests for the gda: access_method */
00094     return TRUE;
00095 }
00096 
00097 static void
00098 qgda_modify (QofBackend *be, QofInstance *inst)
00099 {
00100     QGdaBackend *qgda_be;
00101 
00102     qgda_be = (QGdaBackend *) be;
00103     if (!inst)
00104         return;
00105     if (!inst->param)
00106         return;
00107 //  if (loading)
00108 //      return;
00109     if (!inst->param->param_setfcn)
00110         return;
00111     qgda_be->gda_err = NULL;
00112     ENTER (" modified %s param:%s", ((QofEntity *) inst)->e_type, inst->param->param_name);
00113     qgda_be->sql_str = qof_sql_entity_update ((QofEntity*)inst);
00114     if (!qgda_be->sql_str)
00115     {
00116         LEAVE (" null string");
00117         return;
00118     }
00119     DEBUG (" sql_str=%s", qgda_be->sql_str);
00120     qgda_be->command = gda_command_new (qgda_be->sql_str, GDA_COMMAND_TYPE_SQL, 
00121         GDA_COMMAND_OPTION_STOP_ON_ERRORS);
00122     gda_connection_execute_non_select_command (qgda_be->connection, 
00123         qgda_be->command, NULL, &qgda_be->gda_err);
00124     if (qgda_be->gda_err)
00125     {
00126         qof_error_set_be (be, qgda_be->err_update);
00127         qgda_be->error = TRUE;
00128         PERR (" error on modify:%s", qgda_be->err);
00129         LEAVE (" ");
00130         g_error_free (qgda_be->gda_err);
00131         qgda_be->gda_err = NULL;
00132         return;
00133     }
00134     inst->dirty = FALSE;
00135     g_free (qgda_be->sql_str);
00136     qgda_be->error = FALSE;
00137     LEAVE (" ");
00138 }
00139 
00140 static void
00141 create_tables (QofObject * obj, gpointer user_data)
00142 {
00143     QGdaBackend * qgda_be;
00144     QofBackend * be;
00145 //  GdaParameterList * plist;
00146     gchar * str;
00147 
00148     qgda_be = (QGdaBackend*)user_data;
00149     be = (QofBackend*)qgda_be;
00150     if (!gda_connection_is_opened (qgda_be->connection))
00151     {
00152         qof_error_set_be (be, qof_error_register
00153             (_("GDA: No connection available."), FALSE));
00154         qgda_be->error = TRUE;
00155         PERR (" no connection to gda available");
00156         return;
00157     }
00158     qgda_be->gda_err = NULL;
00159     str = qof_sql_object_create_table (obj);
00160     qgda_be->command = gda_command_new (str, GDA_COMMAND_TYPE_SQL, 
00161         GDA_COMMAND_OPTION_STOP_ON_ERRORS);
00162     gda_connection_execute_non_select_command (qgda_be->connection, 
00163         qgda_be->command, NULL, &qgda_be->gda_err);
00164     if (qgda_be->gda_err)
00165     {
00166         gchar * msg;
00167 
00168         /* Translators: the string is the error message from GDA */
00169         msg = g_strdup_printf (_("GDA: Error: %s"), qgda_be->gda_err->message);
00170         qof_error_set_be (be, qof_error_register (msg, FALSE));
00171         qgda_be->error = TRUE;
00172         g_error_free (qgda_be->gda_err);
00173         g_free (msg);
00174     }
00175     qof_sql_entity_set_kvp_exists (TRUE);
00176 //  g_free (plist);
00177     gda_command_free (qgda_be->command);
00178 }
00179 
00180 static gboolean
00181 create_data_source (QGdaBackend * qgda_be)
00182 {
00183     gchar * cnc_string, * msg;
00184     QofBackend * be;
00185     GdaProviderInfo * prov;
00186 
00187     ENTER (" ");
00188     be = (QofBackend*)qgda_be;
00189     if (!qgda_be->data_source_name)
00190     {
00191         qof_error_set_be (be, qof_error_register
00192             (_("GDA: Missing data source name."), FALSE));
00193         LEAVE (" empty data source name");
00194         return FALSE;
00195     }
00196     qgda_be->gda_err = NULL;
00197     prov = gda_config_get_provider_by_name (qgda_be->provider_name);
00198     if (!prov)
00199     {
00200         /* Translators: The string is the GDA provider name. */
00201         msg = g_strdup_printf (_("GDA Provider '%s' could not be found"),
00202             qgda_be->provider_name);
00203         qof_error_set_be (be, qof_error_register(msg, FALSE));
00204         g_free (msg);
00205         LEAVE (" provider '%s' not found", qgda_be->provider_name);
00206         return FALSE;
00207     }
00208     cnc_string = g_strconcat ("DB_DIR=", qgda_be->gdahome, ";DB_NAME=", 
00209         qgda_be->database_name, NULL);
00210     /* creates db within source if db does not exist */
00211     {
00212         GdaServerOperation * prepare;
00213         gboolean modify_global_config, save_data_source, test;
00214         prepare = gda_client_prepare_create_database (qgda_be->client_pool, 
00215             qgda_be->data_source_name, qgda_be->provider_name);
00216         test = gda_client_perform_create_database (qgda_be->client_pool, prepare, NULL);
00217         if (test)
00218             PINFO ("performed creation of new database ok");
00219         else
00220             PERR ("creation of new database failed");
00221         modify_global_config = gda_config_can_modify_global_config ();
00222         /* only the root user can modify global config in GDA - find out */
00223         gda_config_has_section ("/apps/libgda/Datasources/QOF_DEBUG");
00224         modify_global_config = gda_config_can_modify_global_config ();
00225         save_data_source = gda_config_save_data_source (qgda_be->data_source_name,
00226             qgda_be->provider_name, cnc_string,
00227             qgda_be->source_description, qgda_be->username,
00228             qgda_be->password, modify_global_config);
00229         g_return_val_if_fail (save_data_source, FALSE);
00230     }
00231     qgda_be->connection = gda_client_open_connection
00232         (qgda_be->client_pool, qgda_be->data_source_name,
00233         NULL, NULL, GDA_CONNECTION_OPTIONS_NONE, &qgda_be->gda_err);
00234     if (!qgda_be->connection)
00235     {
00236         gchar * msg;
00237         /* Translators: First string is the data source name,
00238         second string is the message from GDA. */
00239         msg = g_strdup_printf 
00240             (_("GDA: Failed to connect to the data source '%s'. "
00241             "The GDA error was '%s'."), qgda_be->data_source_name, 
00242             qgda_be->gda_err->message);
00243         qof_error_set_be (be, qof_error_register (msg, FALSE));
00244         g_free (msg);
00245         qgda_be->error = TRUE;
00246 #ifdef ONLY_DEBUG
00247         PERR ("connect request failed, removing %s", qgda_be->data_source_name);
00248         g_message ("connect request failed, removing %s", qgda_be->data_source_name);
00249         gda_config_remove_data_source (qgda_be->data_source_name);
00250 #endif
00251         g_error_free (qgda_be->gda_err);
00252         return FALSE;
00253     }
00254     /* create tables per QofObject */
00255     qof_object_foreach_type (create_tables, qgda_be);
00256     /* gda_connection_create_table (don't log password) */
00257     LEAVE (" created data source for %s, %s, %s, %s",
00258         qgda_be->data_source_name,
00259         qgda_be->provider_name, cnc_string,
00260         qgda_be->username);
00261     return TRUE;
00262 }
00263 
00264 static void
00265 qgda_session_begin(QofBackend *be, QofSession *session, const
00266                    gchar *book_path, gboolean ignore_lock,
00267                    gboolean create_if_nonexistent)
00268 {
00269     QGdaBackend *qgda_be;
00270     GdaDataSourceInfo * source;
00271     gboolean created;
00272 
00273     /* cannot use ignore_lock */
00274     PINFO (" gda session start");
00275     qgda_be = (QGdaBackend*)be;
00276     be->fullpath = g_strdup (book_path);
00277     qgda_be->gda_err = NULL;
00278     if(book_path == NULL)
00279     {
00280         qof_error_set_be (be, qof_error_register
00281             (_("GDA: No data source path specified."), FALSE));
00282         qgda_be->error = TRUE;
00283         LEAVE (" bad URL");
00284         return;
00285     }
00286     /* check/create the ~/.libgda location. */
00287     {
00288         struct stat lg;
00289         gint ret;
00290 
00291         ret = g_stat (g_get_home_dir(), &lg);
00292         if (ret)
00293         {
00294             qof_error_set_be (be, qof_error_register
00295                 (_("GDA: Unable to locate your home directory."),
00296                 FALSE));
00297             qgda_be->error = TRUE;
00298             LEAVE (" unable to use stat on home_dir.");
00299             return;
00300         }
00301         qgda_be->gdahome = g_strconcat (g_get_home_dir(), "/", LIBGDA_DIR, NULL);
00302         if (!S_ISDIR (lg.st_mode) || lg.st_size == 0)
00303             ret = g_mkdir_with_parents (qgda_be->gdahome, 0700);
00304         if (ret)
00305         {
00306             qof_error_set_be (be, qof_error_register
00307                 (_("GDA: Unable to create a .libgda directory "
00308                 "within your home directory."), FALSE));
00309             qgda_be->error = TRUE;
00310             LEAVE (" unable to create '%s' 0700", qgda_be->gdahome);
00311             return;
00312         }
00313     }
00314     if (qgda_be->data_source_name)
00315     {
00316         /* check data source */
00317         qgda_be->book = qof_session_get_book (session);
00318         PINFO ("name=%s", qgda_be->data_source_name);
00319         PINFO ("provider=%s", qgda_be->provider_name);
00320         created = FALSE;
00321         source = gda_config_find_data_source
00322             (qgda_be->data_source_name);
00323         if (!source && create_if_nonexistent)
00324         {
00325             DEBUG (" no source, creating . . .");
00326             created = create_data_source (qgda_be);
00327         }
00328         if (!source && !created)
00329         {
00330             qof_error_set_be (be, qof_error_register
00331                 (_("GDA: No data source found at '%s' - Try loading data "
00332                 "from another file and write to gda: again to create the "
00333                 "GDA data source."), TRUE));
00334             DEBUG (" no source but set not to create.");
00335             qgda_be->error = TRUE;
00336             return;
00337         }
00338     }
00339     PINFO (" trying for a connection");
00340     /* use the username and password that created the source */
00341     qgda_be->connection = gda_client_open_connection
00342         (qgda_be->client_pool, qgda_be->data_source_name,
00343         NULL, NULL, GDA_CONNECTION_OPTIONS_DONT_SHARE, &qgda_be->gda_err);
00344     if (qgda_be->connection)
00345     {
00346         PINFO (" appear to be connected.");
00347         /* create tables per QofObject */
00348         qof_object_foreach_type (create_tables, qgda_be);
00349     }
00350     else
00351     {
00352         gchar * msg;
00353 
00354         msg = g_strdup_printf (
00355             _("GDA encountered an error '%s' using data source '%s'."),
00356                 qgda_be->gda_err->message, qgda_be->data_source_name);
00357         qof_error_set_be (be, qof_error_register (msg, FALSE));
00358         PERR (" failed to connect to GDA: '%s'", msg);
00359         qgda_be->error = TRUE;
00360         g_message (msg);
00361         g_free (msg);
00362         g_error_free (qgda_be->gda_err);
00363 #ifdef ONLY_DEBUG
00364 
00365         PERR ("connect request failed, removing %s", qgda_be->data_source_name);
00366         g_message ("connect request failed, removing %s", qgda_be->data_source_name);
00367         gda_config_remove_data_source (qgda_be->data_source_name);
00368 #endif
00369     }
00370 }
00371 
00372 static void
00373 load_entities (gpointer value, gpointer user_data)
00374 {
00375     gint column_id, row_id;
00376     GdaDataModel * dm;
00377     QGdaBackend * qgda_be;
00378 
00379     qgda_be = (QGdaBackend*)user_data;
00380     dm = (GdaDataModel*)value;
00381     if (!dm)
00382     {
00383         qgda_be->error = TRUE;
00384         DEBUG (" empty data model on load");
00385         return;
00386     }
00387     for (column_id = 0; column_id < gda_data_model_get_n_columns (dm);
00388         column_id++)
00389         g_print("%s\t", gda_data_model_get_column_title (dm, column_id));
00390     g_print("\n");
00391     for (row_id = 0; row_id < gda_data_model_get_n_rows (dm); row_id++) {
00392         for (column_id = 0; column_id < gda_data_model_get_n_columns (dm);
00393              column_id++)
00394         {
00395             gchar *str;
00396 
00397             qgda_be->gda_value = (GValue*)gda_data_model_get_value_at
00398                 (dm, column_id, row_id);
00399             str = gda_value_stringify (qgda_be->gda_value);
00400             g_print ("%s\t", str);
00401             g_free (str);
00402         }
00403         g_print("\n");
00404     }
00405     g_object_unref(dm);
00406 }
00407 
00408 static void
00409 qgda_class_foreach (QofObject * obj, gpointer data)
00410 {
00411     QGdaBackend *qgda_be;
00412 
00413     qgda_be = (QGdaBackend*)data;
00414     qgda_be->gda_err = NULL;
00415     qgda_be->sql_str = g_strdup_printf("SELECT * FROM %s;", obj->e_type);
00416     PINFO (" sql=%s", qgda_be->sql_str);
00417     qgda_be->command = gda_command_new (qgda_be->sql_str,
00418         GDA_COMMAND_TYPE_SQL, GDA_COMMAND_OPTION_STOP_ON_ERRORS);
00419     qgda_be->entities = gda_connection_execute_command (qgda_be->connection,
00420         qgda_be->command, NULL, &qgda_be->gda_err);
00421     if (qgda_be->gda_err)
00422         g_error_free (qgda_be->gda_err);
00423     g_list_foreach (qgda_be->entities, load_entities, qgda_be);
00424     gda_command_free (qgda_be->command);
00425 }
00426 
00427 static void
00428 qgda_db_load (QofBackend *be, QofBook *book)
00429 {
00430     QGdaBackend *qgda_be;
00431 
00432     qgda_be = (QGdaBackend*)be;
00433     if (qgda_be->error)
00434         return;
00435     /* select all */
00436     qgda_be->book = book;
00437     qof_object_foreach_type(qgda_class_foreach, qgda_be);
00438 }
00439 
00440 static void
00441 qgda_check_entity (QofEntity * ent, gpointer data)
00442 {
00443     QofInstance *inst;
00444     QGdaBackend * qgda_be;
00445     gchar * gstr;
00446 
00447     qgda_be = (QGdaBackend*) data;
00448     inst = (QofInstance *) ent;
00449     if (!inst->dirty)
00450         return;
00451     /* check if this entity already exists */
00452     gstr = g_strnfill (GUID_ENCODING_LENGTH + 1, ' ');
00453     guid_to_string_buff (qof_entity_get_guid (ent), gstr);
00454     qgda_be->sql_str = g_strdup_printf 
00455         ("SELECT * FROM %s where guid = \"%s\";", ent->e_type, gstr);
00456     qgda_be->dirty_list = NULL;
00457     /* assume entity does not yet exist in backend,
00458        e.g. being copied from another session. */
00459     qgda_be->exists = FALSE;
00460 }
00461 
00462 static void
00463 qgda_write_foreach (QofObject * obj, gpointer data)
00464 {
00465     QGdaBackend *qgda_be;
00466 
00467     qgda_be = (QGdaBackend*)data;
00468     qgda_be->gda_err = NULL;
00469     if (!qof_book_not_saved (qgda_be->book))
00470         return;
00471     qof_object_foreach (obj->e_type, qgda_be->book, qgda_check_entity, &qgda_be);
00472 }
00473 
00474 static void
00475 qgda_write_db (QofBackend *be, QofBook *book)
00476 {
00477     QGdaBackend *qgda_be;
00478 
00479     g_return_if_fail (be);
00480     qgda_be = (QGdaBackend *) be;
00481     qgda_be->book = book;
00482     /* update each record with current state */
00483     qof_object_foreach_type (qgda_write_foreach, qgda_be);
00484 }
00485 
00486 static void
00487 qgda_session_end (QofBackend *be)
00488 {
00489     QGdaBackend *qgda_be;
00490 
00491     qgda_be = (QGdaBackend*)be;
00492     if (qgda_be)
00493     {
00494         /* only remove data_source whilst debugging! */
00495         PINFO ("removing %s", qgda_be->data_source_name);
00496         gda_config_remove_data_source (qgda_be->data_source_name);
00497         gda_client_close_all_connections (qgda_be->client_pool);
00498         g_object_unref(G_OBJECT(qgda_be->client_pool));
00499     }
00500 }
00501 
00502 static void
00503 qgda_destroy_backend (QofBackend *be)
00504 {
00505     QGdaBackend *qgda_be;
00506 
00507     qgda_be = (QGdaBackend*)be;
00508     qof_event_unregister_handler (qgda_be->create_handler);
00509     qof_event_unregister_handler (qgda_be->delete_handler);
00510     g_free (be);
00511     g_free (qgda_be);
00512 }
00513 
00514 static void
00515 option_cb (QofBackendOption * option, gpointer data)
00516 {
00517     QGdaBackend * qgda_be;
00518 
00519     qgda_be = (QGdaBackend *) data;
00520     g_return_if_fail (qgda_be);
00521     if (0 == safe_strcmp (GDA_DBNAME, option->option_name))
00522     {
00523         qgda_be->database_name = g_strdup (option->value);
00524         PINFO (" database name = %s", qgda_be->database_name);
00525     }
00526     if (0 == safe_strcmp (GDA_USERNAME, option->option_name))
00527     {
00528         qgda_be->username = g_strdup (option->value);
00529         PINFO (" username=%s", qgda_be->username);
00530     }
00531     if (0 == safe_strcmp (GDA_PASSWORD, option->option_name))
00532     {
00533         /* don't log the password! :-) */
00534         qgda_be->password = g_strdup (option->value);
00535     }
00536     if (0 == safe_strcmp (GDA_DATASOURCE, option->option_name))
00537     {
00538         qgda_be->data_source_name = g_strdup (option->value);
00539     }
00540 }
00541 
00542 static void
00543 load_config (QofBackend * be, KvpFrame * config)
00544 {
00545     QGdaBackend *qgda_be;
00546 
00547     ENTER (" ");
00548     qgda_be = (QGdaBackend *) be;
00549     g_return_if_fail (qgda_be);
00550     qof_backend_option_foreach (config, option_cb, qgda_be);
00551     LEAVE (" ");
00552 }
00553 
00554 static KvpFrame *
00555 get_config (QofBackend * be)
00556 {
00557     QofBackendOption *option;
00558     QGdaBackend *qgda_be;
00559 
00560     if (!be)
00561         return NULL;
00562     ENTER (" ");
00563     qgda_be = (QGdaBackend *) be;
00564     g_return_val_if_fail (qgda_be, NULL);
00565     qof_backend_prepare_frame (be);
00566     option = g_new0 (QofBackendOption, 1);
00567     option->option_name = GDA_DBNAME;
00568     option->description =
00569         _("Name of the database to use.");
00570     option->tooltip =
00571         _("Override the default database name with "
00572         "a name of your own choice.");
00573     option->type = KVP_TYPE_STRING;
00574     option->value = (gpointer) qgda_be->database_name;
00575     qof_backend_prepare_option (be, option);
00576     g_free (option);
00577     option = g_new0 (QofBackendOption, 1);
00578     option->option_name = GDA_USERNAME;
00579     option->description =
00580         _("The username to use to access this data source.");
00581     option->tooltip =
00582         _("The username specified in the configuration of this "
00583         "data source that provides write access to the data.");
00584     option->type = KVP_TYPE_STRING;
00585     option->value = (gpointer) qgda_be->username;
00586     qof_backend_prepare_option (be, option);
00587     g_free (option);
00588     option = g_new0 (QofBackendOption, 1);
00589     option->option_name = GDA_PASSWORD;
00590     option->description =
00591         _("Password to use with the username.");
00592     option->tooltip =
00593         _("The password that is to be used with the specified "
00594         "username.");
00595     option->type = KVP_TYPE_STRING;
00596     option->value = (gpointer) qgda_be->password;
00597     qof_backend_prepare_option (be, option);
00598     g_free (option);
00599     option = g_new0 (QofBackendOption, 1);
00600     option->option_name = GDA_DATASOURCE;
00601     option->description =
00602         _("Name of this data source.");
00603     option->tooltip =
00604         _("The name of this data source as specified "
00605         "in the GDA configuration.");
00606     option->type = KVP_TYPE_STRING;
00607     option->value = (gpointer) qgda_be->password;
00608     qof_backend_prepare_option (be, option);
00609     g_free (option);
00610     LEAVE (" ");
00611     return qof_backend_complete_frame (be);
00612 }
00613 
00614 static QofBackend *
00615 qgda_backend_new (void)
00616 {
00617     QGdaBackend *qgda_be;
00618     QofBackend *be;
00619 
00620     ENTER (" ");
00621     qgda_be = g_new0(QGdaBackend, 1);
00622     be = (QofBackend*) qgda_be;
00623     qof_backend_init(be);
00624     gda_init (PACKAGE, "0.1", 0, NULL);
00625     qgda_be->client_pool = gda_client_new ();
00626     qgda_be->dbversion = QOF_OBJECT_VERSION;
00627     qgda_be->err_delete =
00628         qof_error_register (_("Unable to delete record."), FALSE);
00629     qgda_be->err_create =
00630         qof_error_register (_("Unable to create record."), FALSE);
00631     qgda_be->err_insert =
00632         qof_error_register (_("Unable to insert a new record."), FALSE);
00633     qgda_be->err_update =
00634         qof_error_register (_("Unable to update existing record."), FALSE);
00635     be->session_begin = qgda_session_begin;
00636 
00637     be->session_end = qgda_session_end;
00638     be->destroy_backend = qgda_destroy_backend;
00639     be->load = qgda_db_load;
00640     be->save_may_clobber_data = NULL;
00641     be->begin = NULL;
00642     /* commit: write to gda, commit undo record. */
00643     be->commit = qgda_modify;
00644     be->rollback = NULL;
00645     /* would need a QofQuery back to QofSqlQuery conversion. */
00646     be->compile_query = NULL;
00647     /* unused */
00648     be->free_query = NULL;
00649     be->run_query = NULL;
00650     be->counter = NULL;
00651     /* The QOF GDA backend might be multi-user */
00652     be->events_pending = NULL;
00653     be->process_events = NULL;
00654 
00655     be->sync = qgda_write_db;
00656     be->load_config = load_config;
00657     be->get_config = get_config;
00658     LEAVE (" ");
00659 
00660 #ifdef ONLY_DEBUG
00661     qgda_be->data_source_name = "QOF_DEBUG";
00662     qgda_be->database_name = "DB_DIR=/home/neil/";
00663     qgda_be->provider_name = "SQLite";
00664     qgda_be->source_description = "QOF GDA debug data";
00665 #endif
00666     return be;
00667 }
00668 
00669 static void
00670 qgda_provider_free (QofBackendProvider *prov)
00671 {
00672     prov->provider_name = NULL;
00673     prov->access_method = NULL;
00674     g_free (prov);
00675 }
00676 
00677 void qof_gda_provider_init(void)
00678 {
00679     QofBackendProvider *prov;
00680 
00681     bindtextdomain (PACKAGE, LOCALE_DIR);
00682     prov = g_new0 (QofBackendProvider, 1);
00683     prov->provider_name = "QOF GDA Backend Version 0.1";
00684     prov->access_method = ACCESS_METHOD;
00685     prov->partial_book_supported = TRUE;
00686     prov->backend_new = qgda_backend_new;
00687     prov->check_data_type = qgda_determine_file_type;
00688     prov->provider_free = qgda_provider_free;
00689     qof_backend_register_provider (prov);
00690 }