00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
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
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;
00067
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
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
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
00108
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
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
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
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
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
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
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
00238
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
00255 qof_object_foreach_type (create_tables, qgda_be);
00256
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
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
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
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
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
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
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
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
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
00458
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
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
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
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
00643 be->commit = qgda_modify;
00644 be->rollback = NULL;
00645
00646 be->compile_query = NULL;
00647
00648 be->free_query = NULL;
00649 be->run_query = NULL;
00650 be->counter = NULL;
00651
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 }