00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00029 #include "config.h"
00030
00031 #include <errno.h>
00032 #include <glib.h>
00033 #include <glib/gstdio.h>
00034 #if !HAVE_GMTIME_R
00035 #include "gmtime_r.h"
00036 #endif
00037
00038 #include "gnc-backend-dbi-priv.h"
00039
00040 #include "qof.h"
00041 #include "qofquery-p.h"
00042 #include "qofquerycore-p.h"
00043 #include "Account.h"
00044 #include "TransLog.h"
00045 #include "gnc-engine.h"
00046 #include "SX-book.h"
00047 #include "Recurrence.h"
00048
00049 #include "gnc-gconf-utils.h"
00050 #include "gnc-uri-utils.h"
00051 #include "gnc-filepath-utils.h"
00052 #include "gnc-locale-utils.h"
00053
00054 #include "gnc-backend-dbi.h"
00055
00056 #ifdef S_SPLINT_S
00057 #include "splint-defs.h"
00058 #endif
00059
00060 #ifdef G_OS_WIN32
00061 #include <winsock2.h>
00062 #define GETPID() GetCurrentProcessId()
00063 #else
00064 #include <limits.h>
00065 #include <unistd.h>
00066 #define GETPID() getpid()
00067 #endif
00068
00069 #define GNC_HOST_NAME_MAX 255
00070 #define TRANSACTION_NAME "trans"
00071
00072 static QofLogModule log_module = G_LOG_DOMAIN;
00073
00074 static gchar lock_table[] = "gnclock";
00075
00076 #define FILE_URI_TYPE "file"
00077 #define FILE_URI_PREFIX (FILE_URI_TYPE "://")
00078 #define SQLITE3_URI_TYPE "sqlite3"
00079 #define SQLITE3_URI_PREFIX (SQLITE3_URI_TYPE "://")
00080 #define PGSQL_DEFAULT_PORT 5432
00081
00082 static gchar* conn_create_table_ddl_sqlite3( GncSqlConnection* conn,
00083 const gchar* table_name,
00084 const GList* col_info_list );
00085 static GSList* conn_get_table_list( dbi_conn conn, const gchar* dbname );
00086 static GSList* conn_get_table_list_sqlite3( dbi_conn conn, const gchar* dbname );
00087 static void append_sqlite3_col_def( GString* ddl, GncSqlColumnInfo* info );
00088 static GSList *conn_get_index_list_sqlite3( dbi_conn conn );
00089 static provider_functions_t provider_sqlite3 =
00090 {
00091 conn_create_table_ddl_sqlite3,
00092 conn_get_table_list_sqlite3,
00093 append_sqlite3_col_def,
00094 conn_get_index_list_sqlite3
00095 };
00096 #define SQLITE3_TIMESPEC_STR_FORMAT "%04d%02d%02d%02d%02d%02d"
00097
00098 static gchar* conn_create_table_ddl_mysql( GncSqlConnection* conn,
00099 const gchar* table_name,
00100 const GList* col_info_list );
00101 static void append_mysql_col_def( GString* ddl, GncSqlColumnInfo* info );
00102 static GSList *conn_get_index_list_mysql( dbi_conn conn );
00103 static provider_functions_t provider_mysql =
00104 {
00105 conn_create_table_ddl_mysql,
00106 conn_get_table_list,
00107 append_mysql_col_def,
00108 conn_get_index_list_mysql
00109 };
00110 #define MYSQL_TIMESPEC_STR_FORMAT "%04d%02d%02d%02d%02d%02d"
00111
00112 static gchar* conn_create_table_ddl_pgsql( GncSqlConnection* conn,
00113 const gchar* table_name,
00114 const GList* col_info_list );
00115 static GSList* conn_get_table_list_pgsql( dbi_conn conn, const gchar* dbname );
00116 static void append_pgsql_col_def( GString* ddl, GncSqlColumnInfo* info );
00117 static GSList *conn_get_index_list_pgsql( dbi_conn conn );
00118
00119 static provider_functions_t provider_pgsql =
00120 {
00121 conn_create_table_ddl_pgsql,
00122 conn_get_table_list_pgsql,
00123 append_pgsql_col_def,
00124 conn_get_index_list_pgsql
00125 };
00126 #define PGSQL_TIMESPEC_STR_FORMAT "%04d%02d%02d %02d%02d%02d"
00127
00128 static gboolean gnc_dbi_lock_database( QofBackend *qbe, gboolean ignore_lock );
00129 static void gnc_dbi_unlock( QofBackend *qbe );
00130 static gboolean save_may_clobber_data( QofBackend* qbe );
00131
00132 static gchar* create_index_ddl( GncSqlConnection* conn,
00133 const gchar* index_name,
00134 const gchar* table_name,
00135 const GncSqlColumnTableEntry* col_table );
00136 static gchar* add_columns_ddl( GncSqlConnection* conn,
00137 const gchar* table_name,
00138 GList* col_info_list );
00139 static GncSqlConnection* create_dbi_connection( provider_functions_t* provider, QofBackend* qbe, dbi_conn conn );
00140 static gboolean conn_test_dbi_library( dbi_conn conn );
00141 #define GNC_DBI_PROVIDER_SQLITE (&provider_sqlite3)
00142 #define GNC_DBI_PROVIDER_MYSQL (&provider_mysql)
00143 #define GNC_DBI_PROVIDER_PGSQL (&provider_pgsql)
00144
00145
00146 #define DBI_MAX_CONN_ATTEMPTS 5
00147
00148
00149
00150
00151
00152 static void
00153 gnc_table_slist_free( GSList *table_list )
00154 {
00155 GSList *list;
00156 for ( list = table_list; list != NULL; list = g_slist_next( list ))
00157 {
00158 g_free( list->data );
00159 }
00160 g_slist_free( table_list );
00161 }
00162
00163 static void
00164 gnc_dbi_set_error( GncDbiSqlConnection* dbi_conn, gint last_error,
00165 gint error_repeat, gboolean retry )
00166 {
00167 g_return_if_fail( dbi_conn != NULL );
00168
00169 dbi_conn->last_error = last_error;
00170 if ( error_repeat > 0 )
00171 dbi_conn->error_repeat = dbi_conn->error_repeat + error_repeat;
00172 else
00173 dbi_conn->error_repeat = 0;
00174 dbi_conn->retry = retry;
00175 }
00176
00177 static void
00178 gnc_dbi_init_error( GncDbiSqlConnection* dbi_conn )
00179 {
00180 gnc_dbi_set_error( dbi_conn, ERR_BACKEND_NO_ERR, 0, FALSE );
00181 }
00182
00183
00184
00185
00186 static gboolean
00187 gnc_dbi_verify_conn( GncDbiSqlConnection* dbi_conn )
00188 {
00189 if ( dbi_conn->conn_ok )
00190 return TRUE;
00191
00192
00193
00194
00195
00196
00197 gnc_dbi_init_error( dbi_conn );
00198 dbi_conn->conn_ok = TRUE;
00199 (void)dbi_conn_connect( dbi_conn->conn );
00200
00201 return dbi_conn->conn_ok;
00202 }
00203
00204
00205
00206 static void
00207 create_tables_cb( const gchar* type, gpointer data_p, gpointer be_p )
00208 {
00209 GncSqlObjectBackend* pData = data_p;
00210 GncDbiBackend* be = be_p;
00211
00212 g_return_if_fail( type != NULL && data_p != NULL && be_p != NULL );
00213 g_return_if_fail( pData->version == GNC_SQL_BACKEND_VERSION );
00214
00215 if ( pData->create_tables != NULL )
00216 {
00217 (pData->create_tables)( &be->sql_be );
00218 }
00219 }
00220
00221 static void
00222 sqlite3_error_fn( dbi_conn conn, void* user_data )
00223 {
00224 GncDbiBackend *be = (GncDbiBackend*)user_data;
00225 GncDbiSqlConnection *dbi_conn = (GncDbiSqlConnection*)be->sql_be.conn;
00226 const gchar* msg;
00227
00228 (void)dbi_conn_error( conn, &msg );
00229 PERR( "DBI error: %s\n", msg );
00230 gnc_dbi_set_error( conn, ERR_BACKEND_MISC, 0, FALSE );
00231 }
00232
00233 static void
00234 gnc_dbi_sqlite3_session_begin( QofBackend *qbe, QofSession *session,
00235 const gchar *book_id, gboolean ignore_lock,
00236 gboolean create, gboolean force )
00237 {
00238 GncDbiBackend *be = (GncDbiBackend*)qbe;
00239 gint result;
00240 gchar* dirname = NULL;
00241 gchar* basename = NULL;
00242 gchar *filepath = NULL;
00243 gchar *msg = " ";
00244 gboolean file_exists;
00245
00246 g_return_if_fail( qbe != NULL );
00247 g_return_if_fail( session != NULL );
00248 g_return_if_fail( book_id != NULL );
00249
00250 ENTER (" ");
00251
00252
00253 filepath = gnc_uri_get_path ( book_id );
00254 file_exists = g_file_test( filepath,
00255 G_FILE_TEST_IS_REGULAR | G_FILE_TEST_EXISTS );
00256 if ( !create && !file_exists )
00257 {
00258 qof_backend_set_error( qbe, ERR_FILEIO_FILE_NOT_FOUND );
00259 qof_backend_set_message(qbe, "Sqlite3 file %s not found", filepath);
00260 goto exit;
00261 }
00262
00263 if ( create && !force && file_exists )
00264 {
00265 qof_backend_set_error (qbe, ERR_BACKEND_STORE_EXISTS);
00266 msg = "Might clobber, no force";
00267 goto exit;
00268 }
00269
00270
00271 if ( be->conn != NULL )
00272 {
00273 dbi_conn_close( be->conn );
00274 }
00275 be->conn = dbi_conn_new( "sqlite3" );
00276 if ( be->conn == NULL )
00277 {
00278 PERR( "Unable to create sqlite3 dbi connection\n" );
00279 qof_backend_set_error( qbe, ERR_BACKEND_BAD_URL );
00280 goto exit;
00281 }
00282
00283 dirname = g_path_get_dirname( filepath );
00284 basename = g_path_get_basename( filepath );
00285 dbi_conn_error_handler( be->conn, sqlite3_error_fn, be );
00286
00287 result = dbi_conn_set_option( be->conn, "host", "localhost" );
00288 if ( result < 0 )
00289 {
00290 PERR( "Error setting 'host' option\n" );
00291 qof_backend_set_error( qbe, ERR_BACKEND_SERVER_ERR );
00292 goto exit;
00293 }
00294 result = dbi_conn_set_option( be->conn, "dbname", basename );
00295 if ( result < 0 )
00296 {
00297 PERR( "Error setting 'dbname' option\n" );
00298 qof_backend_set_error( qbe, ERR_BACKEND_SERVER_ERR );
00299 goto exit;
00300 }
00301 result = dbi_conn_set_option( be->conn, "sqlite3_dbdir", dirname );
00302 if ( result < 0 )
00303 {
00304 PERR( "Error setting 'sqlite3_dbdir' option\n" );
00305 qof_backend_set_error( qbe, ERR_BACKEND_SERVER_ERR );
00306 goto exit;
00307 }
00308 result = dbi_conn_connect( be->conn );
00309
00310 if ( result < 0 )
00311 {
00312 PERR( "Unable to connect to %s: %d\n", book_id, result );
00313 qof_backend_set_error( qbe, ERR_BACKEND_BAD_URL );
00314 goto exit;
00315 }
00316
00317 if ( !conn_test_dbi_library( be->conn ) )
00318 {
00319 qof_backend_set_error( qbe, ERR_SQL_BAD_DBI );
00320 qof_backend_set_message( qbe, "DBI library fails large number test" );
00321 if ( create && !file_exists )
00322 {
00323
00324 dbi_conn_close( be->conn );
00325 be->conn = NULL;
00326 g_unlink( filepath );
00327 }
00328 msg = "Bad DBI Library";
00329 goto exit;
00330 }
00331 if ( !gnc_dbi_lock_database( qbe, ignore_lock ) )
00332 {
00333 qof_backend_set_error( qbe, ERR_BACKEND_LOCKED );
00334 msg = "Locked";
00335 goto exit;
00336 }
00337
00338 if ( be->sql_be.conn != NULL )
00339 {
00340 gnc_sql_connection_dispose( be->sql_be.conn );
00341 }
00342 be->sql_be.conn = create_dbi_connection( GNC_DBI_PROVIDER_SQLITE, qbe, be->conn );
00343 be->sql_be.timespec_format = SQLITE3_TIMESPEC_STR_FORMAT;
00344
00345
00346
00347 xaccLogSetBaseName (filepath);
00348 PINFO ("logpath=%s", filepath ? filepath : "(null)");
00349
00350 exit:
00351 if ( filepath != NULL ) g_free ( filepath );
00352 if ( basename != NULL ) g_free( basename );
00353 if ( dirname != NULL ) g_free( dirname );
00354 LEAVE ( "%s", msg );
00355 }
00356
00357 static GSList*
00358 conn_get_index_list_sqlite3( dbi_conn conn )
00359 {
00360 GSList *list = NULL;
00361 const gchar *errmsg;
00362 dbi_result result = dbi_conn_query( conn, "SELECT name FROM sqlite_master WHERE type = 'index' AND name NOT LIKE 'sqlite_autoindex%'" );
00363 if ( dbi_conn_error( conn, &errmsg ) != DBI_ERROR_NONE )
00364 {
00365 g_print( "Index Table Retrieval Error: %s\n", errmsg );
00366 return NULL;
00367 }
00368 while ( dbi_result_next_row( result ) != 0 )
00369 {
00370 const gchar* index_name;
00371
00372 index_name = dbi_result_get_string_idx( result, 1 );
00373 list = g_slist_prepend( list, strdup( index_name ) );
00374 }
00375 dbi_result_free( result );
00376 return list;
00377 }
00378
00379 static void
00380 mysql_error_fn( dbi_conn conn, void* user_data )
00381 {
00382 GncDbiBackend *be = (GncDbiBackend*)user_data;
00383 GncDbiSqlConnection *dbi_conn = (GncDbiSqlConnection*)be->sql_be.conn;
00384 const gchar* msg;
00385 gint err_num;
00386
00387 err_num = dbi_conn_error( conn, &msg );
00388
00389
00390
00391
00392
00393
00394
00395
00396 if ( err_num == 1049 )
00397 {
00398 PINFO( "DBI error: %s\n", msg );
00399 be->exists = FALSE;
00400 return;
00401 }
00402
00403
00404
00405
00406
00407 if (!dbi_conn)
00408 {
00409 PINFO( "DBI error: %s\n", msg );
00410 PINFO( "Note: GbcDbiSqlConnection not yet initialized. Skipping further error processing." );
00411 return;
00412 }
00413
00414
00415 if ( err_num == 2006 )
00416 {
00417 PINFO( "DBI error: %s - Reconnecting...\n", msg );
00418 if (dbi_conn)
00419 gnc_dbi_set_error( dbi_conn, ERR_BACKEND_CONN_LOST, 1, TRUE );
00420 dbi_conn->conn_ok = TRUE;
00421 (void)dbi_conn_connect( conn );
00422 }
00423 else if ( err_num == 2003 )
00424 {
00425 if (dbi_conn->error_repeat >= DBI_MAX_CONN_ATTEMPTS )
00426 {
00427 PERR( "DBI error: %s - Giving up after %d consecutive attempts.\n", msg, DBI_MAX_CONN_ATTEMPTS );
00428 if (dbi_conn)
00429 gnc_dbi_set_error( dbi_conn, ERR_BACKEND_CANT_CONNECT, 0, FALSE );
00430 dbi_conn->conn_ok = FALSE;
00431 }
00432 else
00433 {
00434 PINFO( "DBI error: %s - Reconnecting...\n", msg );
00435 if (dbi_conn)
00436 gnc_dbi_set_error( dbi_conn, ERR_BACKEND_CANT_CONNECT, 1, TRUE );
00437 dbi_conn->conn_ok = TRUE;
00438 (void)dbi_conn_connect( conn );
00439 }
00440 }
00441 else
00442 {
00443 PERR( "DBI error: %s\n", msg );
00444 if (dbi_conn)
00445 gnc_dbi_set_error( dbi_conn, ERR_BACKEND_MISC, 0, FALSE );
00446 }
00447 }
00448
00461 static gboolean
00462 set_standard_connection_options( QofBackend* qbe, dbi_conn conn, const gchar* host, int port,
00463 const gchar* dbname, const gchar* username, const gchar* password )
00464 {
00465 gint result;
00466
00467 result = dbi_conn_set_option( conn, "host", host );
00468 if ( result < 0 )
00469 {
00470 PERR( "Error setting 'host' option\n" );
00471 qof_backend_set_error( qbe, ERR_BACKEND_SERVER_ERR );
00472 return FALSE;
00473 }
00474 result = dbi_conn_set_option_numeric( conn, "port", port );
00475 if ( result < 0 )
00476 {
00477 PERR( "Error setting 'port' option\n" );
00478 qof_backend_set_error( qbe, ERR_BACKEND_SERVER_ERR );
00479 return FALSE;
00480 }
00481 result = dbi_conn_set_option( conn, "dbname", dbname );
00482 if ( result < 0 )
00483 {
00484 PERR( "Error setting 'dbname' option\n" );
00485 qof_backend_set_error( qbe, ERR_BACKEND_SERVER_ERR );
00486 return FALSE;
00487 }
00488 result = dbi_conn_set_option( conn, "username", username );
00489 if ( result < 0 )
00490 {
00491 PERR( "Error setting 'username' option\n" );
00492 qof_backend_set_error( qbe, ERR_BACKEND_SERVER_ERR );
00493 return FALSE;
00494 }
00495 result = dbi_conn_set_option( conn, "password", password );
00496 if ( result < 0 )
00497 {
00498 PERR( "Error setting 'password' option\n" );
00499 qof_backend_set_error( qbe, ERR_BACKEND_SERVER_ERR );
00500 return FALSE;
00501 }
00502
00503 return TRUE;
00504 }
00505
00506
00507 static gboolean
00508 gnc_dbi_lock_database ( QofBackend* qbe, gboolean ignore_lock )
00509 {
00510
00511 GncDbiBackend *qe = (GncDbiBackend*)qbe;
00512 dbi_conn dcon = qe->conn;
00513 dbi_result result;
00514 const gchar *dbname = dbi_conn_get_option( dcon, "dbname" );
00515
00516 result = dbi_conn_get_table_list( dcon, dbname, lock_table);
00517 if (!( result && dbi_result_get_numrows( result ) ))
00518 {
00519 if ( result )
00520 {
00521 dbi_result_free( result );
00522 result = NULL;
00523 }
00524 result = dbi_conn_queryf( dcon, "CREATE TABLE %s ( Hostname varchar(%d), PID int )", lock_table, GNC_HOST_NAME_MAX );
00525 if ( dbi_conn_error( dcon, NULL ) )
00526 {
00527 const gchar *errstr;
00528 dbi_conn_error( dcon, &errstr );
00529 PERR( "Error %s creating lock table", errstr );
00530 qof_backend_set_error( qbe, ERR_BACKEND_SERVER_ERR );
00531 if ( result )
00532 {
00533 dbi_result_free( result );
00534 result = NULL;
00535 }
00536 return FALSE;
00537 }
00538 if ( result )
00539 {
00540 dbi_result_free( result );
00541 result = NULL;
00542 }
00543 }
00544 if (result)
00545 {
00546 dbi_result_free( result );
00547 result = NULL;
00548 }
00549
00550
00551 if ( (result = dbi_conn_query( dcon, "BEGIN" )) )
00552 {
00553
00554 gchar hostname[ GNC_HOST_NAME_MAX + 1 ];
00555 if (result)
00556 {
00557 dbi_result_free( result );
00558 result = NULL;
00559 }
00560 result = dbi_conn_queryf( dcon, "SELECT * FROM %s", lock_table );
00561 if ( result && dbi_result_get_numrows( result ) )
00562 {
00563 dbi_result_free( result );
00564 result = NULL;
00565 if ( !ignore_lock )
00566 {
00567 qof_backend_set_error( qbe, ERR_BACKEND_LOCKED );
00568
00569 dbi_conn_query( dcon, "ROLLBACK" );
00570 return FALSE;
00571 }
00572 result = dbi_conn_queryf( dcon, "DELETE FROM %s", lock_table );
00573 if ( !result)
00574 {
00575 qof_backend_set_error( qbe, ERR_BACKEND_SERVER_ERR );
00576 qof_backend_set_message( qbe, "Failed to delete lock record" );
00577 result = dbi_conn_query( dcon, "ROLLBACK" );
00578 if (result)
00579 {
00580 dbi_result_free( result );
00581 result = NULL;
00582 }
00583 return FALSE;
00584 }
00585 if (result)
00586 {
00587 dbi_result_free( result );
00588 result = NULL;
00589 }
00590 }
00591
00592 memset( hostname, 0, sizeof(hostname) );
00593 gethostname( hostname, GNC_HOST_NAME_MAX );
00594 result = dbi_conn_queryf( dcon,
00595 "INSERT INTO %s VALUES ('%s', '%d')",
00596 lock_table, hostname, (int)GETPID() );
00597 if ( !result)
00598 {
00599 qof_backend_set_error( qbe, ERR_BACKEND_SERVER_ERR );
00600 qof_backend_set_message( qbe, "Failed to create lock record" );
00601 result = dbi_conn_query( dcon, "ROLLBACK" );
00602 if (result)
00603 {
00604 dbi_result_free( result );
00605 result = NULL;
00606 }
00607 return FALSE;
00608 }
00609 if (result)
00610 {
00611 dbi_result_free( result );
00612 result = NULL;
00613 }
00614 result = dbi_conn_query( dcon, "COMMIT" );
00615 if (result)
00616 {
00617 dbi_result_free( result );
00618 result = NULL;
00619 }
00620 return TRUE;
00621 }
00622
00623 qof_backend_set_error( qbe, ERR_BACKEND_SERVER_ERR );
00624 qof_backend_set_message( qbe, "SQL Backend failed to obtain a transaction" );
00625 if (result)
00626 {
00627 dbi_result_free( result );
00628 result = NULL;
00629 }
00630 return FALSE;
00631 }static void
00632 gnc_dbi_unlock( QofBackend *qbe )
00633 {
00634 GncDbiBackend *qe = (GncDbiBackend*)qbe;
00635 dbi_conn dcon = qe->conn;
00636 dbi_result result;
00637 const gchar *dbname = NULL;
00638
00639 g_return_if_fail( dcon != NULL );
00640 g_return_if_fail( dbi_conn_error( dcon, NULL ) == 0 );
00641
00642 dbname = dbi_conn_get_option( dcon, "dbname" );
00643
00644 g_return_if_fail( dbname != NULL );
00645 result = dbi_conn_get_table_list( dcon, dbname, lock_table);
00646 if (!( result && dbi_result_get_numrows( result ) ))
00647 {
00648 if (result)
00649 {
00650 dbi_result_free( result );
00651 result = NULL;
00652 }
00653 PWARN("No lock table in database, so not unlocking it.");
00654 return;
00655 }
00656 dbi_result_free( result );
00657
00658 result = dbi_conn_query( dcon, "BEGIN" );
00659 if ( result )
00660 {
00661
00662 gchar hostname[ GNC_HOST_NAME_MAX + 1 ];
00663
00664 dbi_result_free( result );
00665 result = NULL;
00666 memset( hostname, 0, sizeof(hostname) );
00667 gethostname( hostname, GNC_HOST_NAME_MAX );
00668 result = dbi_conn_queryf( dcon, "SELECT * FROM %s WHERE Hostname = '%s' AND PID = '%d'", lock_table, hostname, (int)GETPID() );
00669 if ( result && dbi_result_get_numrows( result ) )
00670 {
00671 if (result)
00672 {
00673 dbi_result_free( result );
00674 result = NULL;
00675 }
00676 result = dbi_conn_queryf( dcon, "DELETE FROM %s", lock_table );
00677 if ( !result)
00678 {
00679 PERR("Failed to delete the lock entry");
00680 qof_backend_set_error( qbe, ERR_BACKEND_SERVER_ERR );
00681 result = dbi_conn_query( dcon, "ROLLBACK" );
00682 if (result)
00683 {
00684 dbi_result_free( result );
00685 result = NULL;
00686 }
00687 return;
00688 }
00689 else
00690 {
00691 dbi_result_free( result );
00692 result = NULL;
00693 }
00694 result = dbi_conn_query( dcon, "COMMIT" );
00695 if (result)
00696 {
00697 dbi_result_free( result );
00698 result = NULL;
00699 }
00700 return;
00701 }
00702 result = dbi_conn_query( dcon, "ROLLBACK" );
00703 if (result)
00704 {
00705 dbi_result_free( result );
00706 result = NULL;
00707 }
00708 PWARN("There was no lock entry in the Lock table");
00709 return;
00710 }
00711 if (result)
00712 {
00713 dbi_result_free( result );
00714 result = NULL;
00715 }
00716 PWARN("Unable to get a lock on LOCK, so failed to clear the lock entry.");
00717 qof_backend_set_error( qbe, ERR_BACKEND_SERVER_ERR );
00718 }
00719
00720 static void
00721 gnc_dbi_mysql_session_begin( QofBackend* qbe, QofSession *session,
00722 const gchar *book_id, gboolean ignore_lock,
00723 gboolean create, gboolean force )
00724 {
00725 GncDbiBackend *be = (GncDbiBackend*)qbe;
00726 gchar* protocol = NULL;
00727 gchar* host = NULL;
00728 gchar* dbname = NULL;
00729 gchar* username = NULL;
00730 gchar* password = NULL;
00731 gchar* basename = NULL;
00732 gchar* translog_path = NULL;
00733 gint portnum = 0;
00734 gint result;
00735 gboolean success = FALSE;
00736
00737 g_return_if_fail( qbe != NULL );
00738 g_return_if_fail( session != NULL );
00739 g_return_if_fail( book_id != NULL );
00740
00741 ENTER (" ");
00742
00743
00744
00745
00746 gnc_uri_get_components ( book_id, &protocol, &host, &portnum,
00747 &username, &password, &dbname );
00748
00749
00750
00751
00752 if ( be->conn != NULL )
00753 {
00754 dbi_conn_close( be->conn );
00755 }
00756 be->conn = dbi_conn_new( "mysql" );
00757 if ( be->conn == NULL )
00758 {
00759 PERR( "Unable to create mysql dbi connection\n" );
00760 qof_backend_set_error( qbe, ERR_BACKEND_BAD_URL );
00761 goto exit;
00762 }
00763 dbi_conn_error_handler( be->conn, mysql_error_fn, be );
00764 if ( !set_standard_connection_options( qbe, be->conn, host, portnum, dbname, username, password ) )
00765 {
00766 goto exit;
00767 }
00768 be->exists = TRUE;
00769 result = dbi_conn_connect( be->conn );
00770 if ( result == 0 )
00771 {
00772 if ( !conn_test_dbi_library( be->conn ) )
00773 {
00774 qof_backend_set_error( qbe, ERR_SQL_BAD_DBI );
00775 qof_backend_set_message( qbe,
00776 "DBI library fails large number test" );
00777 goto exit;
00778 }
00779 if (create && !force && save_may_clobber_data( qbe ) )
00780 {
00781 qof_backend_set_error ( qbe, ERR_BACKEND_STORE_EXISTS );
00782 PWARN("Databse already exists, Might clobber it.");
00783 goto exit;
00784 }
00785
00786 success = gnc_dbi_lock_database ( qbe, ignore_lock );
00787 }
00788 else
00789 {
00790
00791 if ( be->exists )
00792 {
00793 PERR( "Unable to connect to database '%s'\n", dbname );
00794 qof_backend_set_error( qbe, ERR_BACKEND_SERVER_ERR );
00795 goto exit;
00796 }
00797
00798
00799 if ( create )
00800 {
00801 dbi_result dresult;
00802 result = dbi_conn_set_option( be->conn, "dbname", "mysql" );
00803 if ( result < 0 )
00804 {
00805 PERR( "Error setting 'dbname' option\n" );
00806 qof_backend_set_error( qbe, ERR_BACKEND_SERVER_ERR );
00807 goto exit;
00808 }
00809 result = dbi_conn_connect( be->conn );
00810 if ( result < 0 )
00811 {
00812 PERR( "Unable to connect to 'mysql' database\n" );
00813 qof_backend_set_error( qbe, ERR_BACKEND_SERVER_ERR );
00814 goto exit;
00815 }
00816 dresult = dbi_conn_queryf( be->conn, "CREATE DATABASE %s CHARACTER SET utf8", dbname );
00817 if ( dresult == NULL )
00818 {
00819 PERR( "Unable to create database '%s'\n", dbname );
00820 qof_backend_set_error( qbe, ERR_BACKEND_SERVER_ERR );
00821 goto exit;
00822 }
00823 dbi_conn_close( be->conn );
00824
00825
00826 be->conn = dbi_conn_new( "mysql" );
00827 if ( be->conn == NULL )
00828 {
00829 PERR( "Unable to create mysql dbi connection\n" );
00830 qof_backend_set_error( qbe, ERR_BACKEND_BAD_URL );
00831 goto exit;
00832 }
00833 dbi_conn_error_handler( be->conn, mysql_error_fn, be );
00834 if ( !set_standard_connection_options( qbe, be->conn, host, 0, dbname, username, password ) )
00835 {
00836 goto exit;
00837 }
00838 result = dbi_conn_connect( be->conn );
00839 if ( result < 0 )
00840 {
00841 PERR( "Unable to create database '%s'\n", dbname );
00842 qof_backend_set_error( qbe, ERR_BACKEND_SERVER_ERR );
00843 goto exit;
00844 }
00845 if ( !conn_test_dbi_library( be->conn ) )
00846 {
00847 qof_backend_set_error( qbe, ERR_SQL_BAD_DBI );
00848 qof_backend_set_message( qbe,
00849 "DBI library fails large number test" );
00850 dbi_conn_queryf( be->conn, "DROP DATABASE %s", dbname );
00851 goto exit;
00852 }
00853 success = gnc_dbi_lock_database ( qbe, ignore_lock );
00854 }
00855 else
00856 {
00857 qof_backend_set_error( qbe, ERR_BACKEND_NO_SUCH_DB );
00858 qof_backend_set_message( qbe, "Database %s not found", dbname );
00859 }
00860 }
00861
00862 if ( success )
00863 {
00864 dbi_result dresult;
00865
00866
00867 dresult = dbi_conn_queryf( be->conn, "SET NAMES 'utf8'" );
00868 if ( dresult == NULL )
00869 {
00870 PERR( "Unable to set connection char set" );
00871 qof_backend_set_error( qbe, ERR_BACKEND_SERVER_ERR );
00872 goto exit;
00873 }
00874
00875 if ( be->sql_be.conn != NULL )
00876 {
00877 gnc_sql_connection_dispose( be->sql_be.conn );
00878 }
00879 be->sql_be.conn = create_dbi_connection( GNC_DBI_PROVIDER_MYSQL, qbe, be->conn );
00880 }
00881 be->sql_be.timespec_format = MYSQL_TIMESPEC_STR_FORMAT;
00882
00883
00884
00885 basename = g_strjoin("_", protocol, host, username, dbname, NULL);
00886 translog_path = gnc_build_translog_path (basename);
00887 xaccLogSetBaseName (translog_path);
00888 PINFO ("logpath=%s", translog_path ? translog_path : "(null)");
00889
00890 exit:
00891 g_free( protocol );
00892 g_free( host );
00893 g_free( username );
00894 g_free( password );
00895 g_free( basename );
00896 g_free( translog_path );
00897 g_free( dbname );
00898
00899 LEAVE (" ");
00900 }
00901
00902 static GSList*
00903 conn_get_index_list_mysql( dbi_conn conn )
00904 {
00905 GSList *index_list = NULL;
00906 dbi_result table_list;
00907 const char *errmsg;
00908 const gchar *dbname = dbi_conn_get_option( conn, "dbname" );
00909 g_return_val_if_fail( conn != NULL, NULL );
00910 table_list = dbi_conn_get_table_list( conn, dbname, NULL );
00911 if ( dbi_conn_error( conn, &errmsg ) != DBI_ERROR_NONE )
00912 {
00913 g_print( "Table Retrieval Error: %s\n", errmsg );
00914 return NULL;
00915 }
00916 while ( dbi_result_next_row( table_list ) != 0 )
00917 {
00918 dbi_result result;
00919 const gchar *table_name = dbi_result_get_string_idx( table_list, 1 );
00920 result = dbi_conn_queryf( conn,
00921 "SHOW INDEXES IN %s WHERE Key_name != 'PRIMARY'",
00922 table_name );
00923 if ( dbi_conn_error( conn, &errmsg ) != DBI_ERROR_NONE )
00924 {
00925 g_print( "Index Table Retrieval Error: %s\n", errmsg );
00926 continue;
00927 }
00928
00929 while ( dbi_result_next_row( result ) != 0 )
00930 {
00931 const gchar* index_name = dbi_result_get_string_idx( result, 3 );
00932 index_list = g_slist_prepend( index_list, strdup( index_name ) );
00933 }
00934 dbi_result_free( result );
00935 }
00936
00937 return index_list;
00938 }
00939
00940 static void
00941 pgsql_error_fn( dbi_conn conn, void* user_data )
00942 {
00943 GncDbiBackend *be = (GncDbiBackend*)user_data;
00944 GncDbiSqlConnection *dbi_conn = (GncDbiSqlConnection*)be->sql_be.conn;
00945 const gchar* msg;
00946
00947 (void)dbi_conn_error( conn, &msg );
00948 if ( g_str_has_prefix( msg, "FATAL: database" ) &&
00949 g_str_has_suffix( msg, "does not exist\n" ) )
00950 {
00951 PINFO( "DBI error: %s\n", msg );
00952 be->exists = FALSE;
00953 gnc_dbi_set_error( dbi_conn, ERR_BACKEND_NO_SUCH_DB, 0, FALSE );
00954 }
00955 else if ( g_strrstr( msg, "server closed the connection unexpectedly" ) )
00956 {
00957 if ( dbi_conn == NULL )
00958 {
00959 PWARN( "DBI Error: Connection lost, connection pointer invalid");
00960 return;
00961 }
00962 PINFO( "DBI error: %s - Reconnecting...\n", msg );
00963 gnc_dbi_set_error( dbi_conn, ERR_BACKEND_CONN_LOST, 1, TRUE );
00964 dbi_conn->conn_ok = TRUE;
00965 (void)dbi_conn_connect( conn );
00966 }
00967 else if ( dbi_conn &&
00968 ( g_str_has_prefix( msg, "connection pointer is NULL" ) ||
00969 g_str_has_prefix(msg, "could not connect to server" ) ) )
00970 {
00971 if (dbi_conn->error_repeat >= DBI_MAX_CONN_ATTEMPTS )
00972 {
00973 PERR( "DBI error: %s - Giving up after %d consecutive attempts.\n", msg, DBI_MAX_CONN_ATTEMPTS );
00974 gnc_dbi_set_error( dbi_conn, ERR_BACKEND_CANT_CONNECT, 0, FALSE );
00975 dbi_conn->conn_ok = FALSE;
00976 }
00977 else
00978 {
00979 PINFO( "DBI error: %s - Reconnecting...\n", msg );
00980 gnc_dbi_set_error( dbi_conn, ERR_BACKEND_CANT_CONNECT, 1, TRUE );
00981 dbi_conn->conn_ok = TRUE;
00982 (void)dbi_conn_connect( conn );
00983 }
00984 }
00985 else
00986 {
00987 PERR( "DBI error: %s\n", msg );
00988 gnc_dbi_set_error( dbi_conn, ERR_BACKEND_MISC, 0, FALSE );
00989 }
00990 }
00991
00992 static void
00993 gnc_dbi_postgres_session_begin( QofBackend *qbe, QofSession *session,
00994 const gchar *book_id, gboolean ignore_lock,
00995 gboolean create, gboolean force )
00996 {
00997 GncDbiBackend *be = (GncDbiBackend*)qbe;
00998 gint result = 0;
00999 gchar* protocol = NULL;
01000 gchar* host = NULL;
01001 gchar *dbname = NULL, *dbnamelc = NULL;
01002 gchar* username = NULL;
01003 gchar* password = NULL;
01004 gchar* basename = NULL;
01005 gchar* translog_path = NULL;
01006 gboolean success = FALSE;
01007 gint portnum = 0;
01008
01009 g_return_if_fail( qbe != NULL );
01010 g_return_if_fail( session != NULL );
01011 g_return_if_fail( book_id != NULL );
01012
01013 ENTER (" ");
01014
01015
01016
01017
01018 gnc_uri_get_components ( book_id, &protocol, &host, &portnum,
01019 &username, &password, &dbname );
01020 if ( portnum == 0 )
01021 portnum = PGSQL_DEFAULT_PORT;
01022
01023
01024
01025
01026 dbnamelc = g_utf8_strdown( dbname, -1 );
01027
01028
01029
01030
01031 if ( be->conn != NULL )
01032 {
01033 dbi_conn_close( be->conn );
01034 }
01035 be->conn = dbi_conn_new( "pgsql" );
01036 if ( be->conn == NULL )
01037 {
01038 PERR( "Unable to create pgsql dbi connection\n" );
01039 qof_backend_set_error( qbe, ERR_BACKEND_BAD_URL );
01040 goto exit;
01041 }
01042 dbi_conn_error_handler( be->conn, pgsql_error_fn, be );
01043 if ( !set_standard_connection_options( qbe, be->conn, host, portnum, dbnamelc, username, password ) )
01044 {
01045 goto exit;
01046 }
01047 be->exists = TRUE;
01048 result = dbi_conn_connect( be->conn );
01049 if ( result == 0 )
01050 {
01051 if ( !conn_test_dbi_library( be->conn ) )
01052 {
01053 qof_backend_set_error( qbe, ERR_SQL_BAD_DBI );
01054 qof_backend_set_message( qbe,
01055 "DBI library fails large number test" );
01056 goto exit;
01057 }
01058 if (create && !force && save_may_clobber_data( qbe ) )
01059 {
01060 qof_backend_set_error ( qbe, ERR_BACKEND_STORE_EXISTS );
01061 PWARN("Databse already exists, Might clobber it.");
01062 goto exit;
01063 }
01064
01065 success = gnc_dbi_lock_database ( qbe, ignore_lock );
01066 }
01067 else
01068 {
01069
01070 if ( be->exists )
01071 {
01072 PERR( "Unable to connect to database '%s'\n", dbname );
01073 qof_backend_set_error( qbe, ERR_BACKEND_SERVER_ERR );
01074 goto exit;
01075 }
01076
01077
01078 if ( create )
01079 {
01080 dbi_result dresult;
01081 result = dbi_conn_set_option( be->conn, "dbname", "postgres" );
01082 if ( result < 0 )
01083 {
01084 PERR( "Error setting 'dbname' option\n" );
01085 qof_backend_set_error( qbe, ERR_BACKEND_SERVER_ERR );
01086 goto exit;
01087 }
01088 result = dbi_conn_connect( be->conn );
01089 if ( result < 0 )
01090 {
01091 PERR( "Unable to connect to 'postgres' database\n" );
01092 qof_backend_set_error( qbe, ERR_BACKEND_SERVER_ERR );
01093 goto exit;
01094 }
01095 dresult = dbi_conn_queryf( be->conn, "CREATE DATABASE %s WITH TEMPLATE template0 ENCODING 'UTF8'", dbnamelc );
01096 if ( dresult == NULL )
01097 {
01098 PERR( "Unable to create database '%s'\n", dbname );
01099 qof_backend_set_error( qbe, ERR_BACKEND_SERVER_ERR );
01100 goto exit;
01101 }
01102 dbi_conn_queryf( be->conn, "ALTER DATABASE %s SET standard_conforming_strings TO on", dbnamelc );
01103 dbi_conn_close( be->conn );
01104
01105
01106 be->conn = dbi_conn_new( "pgsql" );
01107 if ( be->conn == NULL )
01108 {
01109 PERR( "Unable to create pgsql dbi connection\n" );
01110 qof_backend_set_error( qbe, ERR_BACKEND_BAD_URL );
01111 goto exit;
01112 }
01113 dbi_conn_error_handler( be->conn, pgsql_error_fn, be );
01114 if ( !set_standard_connection_options( qbe, be->conn, host, PGSQL_DEFAULT_PORT, dbnamelc, username, password ) )
01115 {
01116 goto exit;
01117 }
01118 result = dbi_conn_connect( be->conn );
01119 if ( result < 0 )
01120 {
01121 PERR( "Unable to create database '%s'\n", dbname );
01122 qof_backend_set_error( qbe, ERR_BACKEND_SERVER_ERR );
01123 goto exit;
01124 }
01125 if ( !conn_test_dbi_library( be->conn ) )
01126 {
01127 qof_backend_set_error( qbe, ERR_SQL_BAD_DBI );
01128 qof_backend_set_message( qbe,
01129 "DBI library fails large number test" );
01130 dbi_conn_select_db( be->conn, "template1" );
01131 dbi_conn_queryf( be->conn, "DROP DATABASE %s", dbnamelc );
01132 goto exit;
01133 }
01134 success = gnc_dbi_lock_database ( qbe, ignore_lock );
01135 }
01136 else
01137 {
01138 qof_backend_set_error( qbe, ERR_BACKEND_NO_SUCH_DB );
01139 qof_backend_set_message( qbe, "Database %s not found", dbname );
01140 }
01141 }
01142 if ( success )
01143 {
01144 if ( be->sql_be.conn != NULL )
01145 {
01146 gnc_sql_connection_dispose( be->sql_be.conn );
01147 }
01148 be->sql_be.conn = create_dbi_connection( GNC_DBI_PROVIDER_PGSQL, qbe, be->conn );
01149 }
01150 be->sql_be.timespec_format = PGSQL_TIMESPEC_STR_FORMAT;
01151
01152
01153
01154 basename = g_strjoin("_", protocol, host, username, dbname, NULL);
01155 translog_path = gnc_build_translog_path (basename);
01156 xaccLogSetBaseName (translog_path);
01157 PINFO ("logpath=%s", translog_path ? translog_path : "(null)");
01158
01159 exit:
01160 g_free( protocol );
01161 g_free( host );
01162 g_free( username );
01163 g_free( password );
01164 g_free( basename );
01165 g_free( translog_path );
01166 g_free( dbname );
01167 g_free( dbnamelc );
01168
01169 LEAVE (" ");
01170 }
01171
01172 static GSList*
01173 conn_get_index_list_pgsql( dbi_conn conn )
01174 {
01175 GSList *list = NULL;
01176 const gchar *errmsg;
01177 dbi_result result;
01178 g_print( "Retrieving postgres index list\n");
01179 result = dbi_conn_query( conn, "SELECT relname FROM pg_class AS a INNER JOIN pg_index AS b ON (b.indexrelid = a.oid) INNER JOIN pg_namespace AS c ON (a.relnamespace = c.oid) WHERE reltype = '0' AND indisprimary = 'f' AND nspname = 'public'" );
01180 if ( dbi_conn_error( conn, &errmsg ) != DBI_ERROR_NONE )
01181 {
01182 g_print( "Index Table Retrieval Error: %s\n", errmsg );
01183 return NULL;
01184 }
01185 while ( dbi_result_next_row( result ) != 0 )
01186 {
01187 const gchar* index_name;
01188
01189 index_name = dbi_result_get_string_idx( result, 1 );
01190 list = g_slist_prepend( list, strdup( index_name ) );
01191 }
01192 dbi_result_free( result );
01193 return list;
01194 }
01195
01196
01197
01198
01199 static void
01200 gnc_dbi_session_end( QofBackend *be_start )
01201 {
01202 GncDbiBackend *be = (GncDbiBackend*)be_start;
01203
01204 g_return_if_fail( be_start != NULL );
01205
01206 ENTER (" ");
01207
01208 if ( be->conn != NULL )
01209 {
01210 gnc_dbi_unlock( be_start );
01211 dbi_conn_close( be->conn );
01212 be->conn = NULL;
01213 }
01214 if ( be->sql_be.conn != NULL )
01215 {
01216 gnc_sql_connection_dispose( be->sql_be.conn );
01217 be->sql_be.conn = NULL;
01218 }
01219 gnc_sql_finalize_version_info( &be->sql_be );
01220
01221 LEAVE (" ");
01222 }
01223
01224 static void
01225 gnc_dbi_destroy_backend( QofBackend *be )
01226 {
01227 g_return_if_fail( be != NULL );
01228
01229
01230 xaccLogSetBaseName (NULL);
01231
01232 qof_backend_destroy( be );
01233
01234 g_free( be );
01235 }
01236
01237
01238
01239
01240
01241
01242
01243
01244
01245
01246
01247
01248 static void
01249 gnc_dbi_load( QofBackend* qbe, QofBook *book, QofBackendLoadType loadType )
01250 {
01251 GncDbiBackend *be = (GncDbiBackend*)qbe;
01252
01253 g_return_if_fail( qbe != NULL );
01254 g_return_if_fail( book != NULL );
01255
01256 ENTER( "be=%p, book=%p", be, book );
01257
01258 if ( loadType == LOAD_TYPE_INITIAL_LOAD )
01259 {
01260 g_assert( be->primary_book == NULL );
01261 be->primary_book = book;
01262
01263
01264 gnc_sql_init_version_info( &be->sql_be );
01265
01266
01267 qof_object_foreach_backend( GNC_SQL_BACKEND, create_tables_cb, be );
01268 }
01269
01270 gnc_sql_load( &be->sql_be, book, loadType );
01271
01272 if ( GNUCASH_RESAVE_VERSION > gnc_sql_get_table_version( &be->sql_be, "Gnucash" ) )
01273 {
01274
01275
01276
01277 qof_backend_set_error( qbe, ERR_SQL_DB_TOO_OLD );
01278 }
01279 else if ( GNUCASH_RESAVE_VERSION < gnc_sql_get_table_version( &be->sql_be,
01280 "Gnucash-Resave"))
01281 {
01282
01283
01284
01285
01286 qof_backend_set_error( qbe, ERR_SQL_DB_TOO_NEW );
01287 }
01288
01289
01290 LEAVE( "" );
01291 }
01292
01293
01294
01295 static gboolean
01296 save_may_clobber_data( QofBackend* qbe )
01297 {
01298 GncDbiBackend* be = (GncDbiBackend*)qbe;
01299 const gchar* dbname;
01300 dbi_result result;
01301 gboolean retval = FALSE;
01302
01303
01304 dbname = dbi_conn_get_option( be->conn, "dbname" );
01305 result = dbi_conn_get_table_list( be->conn, dbname, NULL );
01306 if ( result )
01307 {
01308 retval = dbi_result_get_numrows( result ) > 0;
01309 dbi_result_free( result );
01310 }
01311 return retval;
01312 }
01313
01314 static dbi_result
01315 conn_table_manage_backup (GncDbiSqlConnection *conn,
01316 gchar *table_name, TableOpType op )
01317 {
01318 gchar *new_name = g_strdup_printf( "%s_%s", table_name, "back" );
01319 dbi_result result = NULL;
01320 switch ( op )
01321 {
01322 case backup:
01323 result = dbi_conn_queryf( conn->conn, "ALTER TABLE %s RENAME TO %s",
01324 table_name, new_name );
01325 break;
01326 case rollback:
01327 result = dbi_conn_queryf( conn->conn,
01328 "ALTER TABLE %s RENAME TO %s",
01329 new_name, table_name );
01330 break;
01331 case drop_backup:
01332 result = dbi_conn_queryf( conn->conn, "DROP TABLE %s",
01333 new_name );
01334 default:
01335 break;
01336 }
01337 g_free( new_name );
01338 return result;
01339 }
01340
01366 static gboolean
01367 conn_table_operation( GncSqlConnection *sql_conn, GSList *table_name_list,
01368 TableOpType op )
01369 {
01370 GSList* node;
01371 gboolean result = TRUE;
01372 GncDbiSqlConnection *conn = (GncDbiSqlConnection*)(sql_conn);
01373 GSList *full_table_name_list = NULL;
01374 const gchar *dbname = dbi_conn_get_option( conn->conn, "dbname" );
01375
01376 g_return_val_if_fail( table_name_list != NULL, FALSE );
01377 if ( op == rollback )
01378 full_table_name_list =
01379 conn->provider->get_table_list( conn->conn, dbname );
01380
01381 for ( node = table_name_list; node != NULL && result; node = node->next )
01382 {
01383 gchar* table_name = (gchar*)node->data;
01384 dbi_result result;
01385
01386 if ( g_strcmp0(table_name, lock_table) == 0)
01387 {
01388 continue;
01389 }
01390 do
01391 {
01392 gnc_dbi_init_error( conn );
01393 switch ( op )
01394 {
01395 case rollback:
01396 if (g_slist_find(full_table_name_list, table_name))
01397 {
01398 result = dbi_conn_queryf( conn->conn, "DROP TABLE %s",
01399 table_name );
01400 if ( result )
01401 break;
01402 }
01403
01404 case backup:
01405 case drop_backup:
01406 result = conn_table_manage_backup( conn, table_name, op );
01407 break;
01408 case empty:
01409 result = dbi_conn_queryf( conn->conn, "DELETE FROM TABLE %s",
01410 table_name );
01411 break;
01412 case drop:
01413 default:
01414 result = dbi_conn_queryf( conn->conn, "DROP TABLE %s",
01415 table_name );
01416 break;
01417 }
01418 }
01419 while ( conn->retry );
01420 if ( result != NULL )
01421 {
01422 if ( dbi_result_free( result ) < 0 )
01423 {
01424 PERR( "Error in dbi_result_free() result\n" );
01425 result = FALSE;
01426 }
01427 }
01428 }
01429 gnc_table_slist_free( full_table_name_list );
01430 return result;
01431 }
01432
01440 static void
01441 gnc_dbi_sync_all( QofBackend* qbe, QofBook *book )
01442 {
01443 GncDbiBackend* be = (GncDbiBackend*)qbe;
01444 GncDbiSqlConnection *conn = (GncDbiSqlConnection*)(((GncSqlBackend*)be)->conn);
01445 GSList* table_name_list;
01446 const gchar* dbname;
01447 gint status;
01448
01449 g_return_if_fail( be != NULL );
01450 g_return_if_fail( book != NULL );
01451
01452 ENTER( "book=%p, primary=%p", book, be->primary_book );
01453
01454
01455 dbname = dbi_conn_get_option( be->conn, "dbname" );
01456 table_name_list = conn->provider->get_table_list( conn->conn, dbname );
01457 if ( !conn_table_operation( (GncSqlConnection*)conn, table_name_list,
01458 drop ) )
01459 {
01460 qof_backend_set_error( qbe, ERR_BACKEND_SERVER_ERR );
01461 return;
01462 }
01463 gnc_table_slist_free( table_name_list );
01464
01465 be->is_pristine_db = TRUE;
01466 be->primary_book = book;
01467 gnc_sql_sync_all( &be->sql_be, book );
01468
01469 LEAVE( "book=%p", book );
01470 }
01471
01481 static void
01482 gnc_dbi_safe_sync_all( QofBackend *qbe, QofBook *book )
01483 {
01484 GncDbiBackend *be = (GncDbiBackend*)qbe;
01485 GncDbiSqlConnection *conn = (GncDbiSqlConnection*)(((GncSqlBackend*)be)->conn);
01486 GSList *table_list, *index_list, *iter;
01487 const gchar* dbname = NULL;
01488 gint status;
01489
01490 g_return_if_fail( be != NULL );
01491 g_return_if_fail( book != NULL );
01492
01493 ENTER( "book=%p, primary=%p", book, be->primary_book );
01494 dbname = dbi_conn_get_option( be->conn, "dbname" );
01495 table_list = conn->provider->get_table_list( conn->conn, dbname );
01496 if ( !conn_table_operation( (GncSqlConnection*)conn, table_list,
01497 backup ) )
01498 {
01499 qof_backend_set_error( qbe, ERR_BACKEND_SERVER_ERR );
01500 conn_table_operation( (GncSqlConnection*)conn, table_list,
01501 rollback );
01502 LEAVE( "Failed to rename tables" );
01503 gnc_table_slist_free( table_list );
01504 return;
01505 }
01506 index_list = conn->provider->get_index_list( conn->conn );
01507 for ( iter = index_list; iter != NULL; iter = g_slist_next( iter) )
01508 {
01509 const char *errmsg;
01510 dbi_result result =
01511 dbi_conn_queryf( conn->conn, "DROP INDEX %s", iter->data );
01512 if ( result )
01513 dbi_result_free( result );
01514 if ( DBI_ERROR_NONE != dbi_conn_error( conn->conn, &errmsg ) )
01515 {
01516 qof_backend_set_error( qbe, ERR_BACKEND_SERVER_ERR );
01517 gnc_table_slist_free( index_list );
01518 conn_table_operation( (GncSqlConnection*)conn, table_list,
01519 rollback );
01520 gnc_table_slist_free( table_list );
01521 LEAVE( "Failed to drop indexes %s", errmsg );
01522 return;
01523 }
01524 }
01525 gnc_table_slist_free( index_list );
01526
01527 be->is_pristine_db = TRUE;
01528 be->primary_book = book;
01529
01530 gnc_sql_sync_all( &be->sql_be, book );
01531 if ( ERR_BACKEND_NO_ERR != qof_backend_get_error( qbe ) )
01532 {
01533 conn_table_operation( (GncSqlConnection*)conn, table_list,
01534 rollback );
01535 LEAVE( "Failed to create new database tables" );
01536 return;
01537 }
01538 conn_table_operation( (GncSqlConnection*)conn, table_list,
01539 drop_backup );
01540 gnc_table_slist_free( table_list );
01541 LEAVE("book=%p", book);
01542 }
01543
01544 static void
01545 gnc_dbi_begin_edit( QofBackend *qbe, QofInstance *inst )
01546 {
01547 GncDbiBackend* be = (GncDbiBackend*)qbe;
01548
01549 g_return_if_fail( be != NULL );
01550 g_return_if_fail( inst != NULL );
01551
01552 gnc_sql_begin_edit( &be->sql_be, inst );
01553 }
01554
01555 static void
01556 gnc_dbi_rollback_edit( QofBackend *qbe, QofInstance *inst )
01557 {
01558 GncDbiBackend* be = (GncDbiBackend*)qbe;
01559
01560 g_return_if_fail( be != NULL );
01561 g_return_if_fail( inst != NULL );
01562
01563 gnc_sql_rollback_edit( &be->sql_be, inst );
01564 }
01565
01566 static void
01567 gnc_dbi_commit_edit( QofBackend *qbe, QofInstance *inst )
01568 {
01569 GncDbiBackend* be = (GncDbiBackend*)qbe;
01570
01571 g_return_if_fail( be != NULL );
01572 g_return_if_fail( inst != NULL );
01573
01574 gnc_sql_commit_edit( &be->sql_be, inst );
01575 }
01576
01577
01578
01579 static void
01580 init_sql_backend( GncDbiBackend* dbi_be )
01581 {
01582 QofBackend* be;
01583
01584 be = (QofBackend*)dbi_be;
01585
01586 be->session_end = gnc_dbi_session_end;
01587 be->destroy_backend = gnc_dbi_destroy_backend;
01588
01589 be->load = gnc_dbi_load;
01590
01591
01592 be->begin = gnc_dbi_begin_edit;
01593 be->commit = gnc_dbi_commit_edit;
01594 be->rollback = gnc_dbi_rollback_edit;
01595
01596
01597 be->events_pending = NULL;
01598 be->process_events = NULL;
01599
01600 be->sync = gnc_dbi_sync_all;
01601 be->safe_sync = gnc_dbi_safe_sync_all;
01602 be->load_config = NULL;
01603 be->get_config = NULL;
01604
01605 be->compile_query = gnc_sql_compile_query;
01606 be->run_query = gnc_sql_run_query;
01607 be->free_query = gnc_sql_free_query;
01608
01609 be->export_fn = NULL;
01610
01611 gnc_sql_init( &dbi_be->sql_be );
01612
01613 dbi_be->sql_be.conn = NULL;
01614 dbi_be->sql_be.primary_book = NULL;
01615 }
01616
01617 static QofBackend*
01618 new_backend( void (*session_begin)( QofBackend *, QofSession *, const gchar *,
01619 gboolean,
01620 gboolean,
01621 gboolean ) )
01622 {
01623 GncDbiBackend *dbi_be;
01624 QofBackend *be;
01625
01626 dbi_be = g_new0( GncDbiBackend, 1 );
01627 g_assert( dbi_be != NULL );
01628
01629 be = (QofBackend*)dbi_be;
01630 qof_backend_init( be );
01631
01632 be->session_begin = session_begin;
01633 init_sql_backend( dbi_be );
01634
01635 return be;
01636 }
01637
01638 static QofBackend*
01639 gnc_dbi_backend_sqlite3_new( void )
01640 {
01641 return new_backend( gnc_dbi_sqlite3_session_begin );
01642 }
01643
01644 static QofBackend*
01645 gnc_dbi_backend_mysql_new( void )
01646 {
01647 return new_backend( gnc_dbi_mysql_session_begin );
01648 }
01649
01650 static QofBackend*
01651 gnc_dbi_backend_postgres_new( void )
01652 {
01653 return new_backend( gnc_dbi_postgres_session_begin );
01654 }
01655
01656 static void
01657 gnc_dbi_provider_free( QofBackendProvider *prov )
01658 {
01659 g_return_if_fail( prov != NULL );
01660
01661 g_free( prov );
01662 }
01663
01664
01665
01666
01667
01668 static gboolean
01669 gnc_dbi_check_sqlite3_file( const gchar *uri )
01670 {
01671 FILE* f;
01672 gchar buf[50];
01673 size_t chars_read;
01674 gint status;
01675 gchar *filename;
01676
01677
01678 g_return_val_if_fail( uri != NULL, FALSE );
01679
01680 filename = gnc_uri_get_path ( uri );
01681 f = g_fopen( filename, "r" );
01682 g_free ( filename );
01683
01684
01685 if ( f == NULL )
01686 {
01687 PINFO( "doesn't exist (errno=%d) -> DBI", errno );
01688 return TRUE;
01689 }
01690
01691
01692 chars_read = fread( buf, sizeof(buf), 1, f );
01693 status = fclose( f );
01694 if ( status < 0 )
01695 {
01696 PERR( "Error in fclose(): %d\n", errno );
01697 }
01698 if ( g_str_has_prefix( buf, "SQLite format 3" ) )
01699 {
01700 PINFO( "has SQLite format string -> DBI" );
01701 return TRUE;
01702 }
01703 PINFO( "exists, does not have SQLite format string -> not DBI" );
01704
01705
01706 return FALSE;
01707 }
01708
01709 void
01710 gnc_module_init_backend_dbi(void)
01711 {
01712 QofBackendProvider *prov;
01713 const gchar* driver_dir;
01714 int num_drivers;
01715 gboolean have_sqlite3_driver = FALSE;
01716 gboolean have_mysql_driver = FALSE;
01717 gboolean have_pgsql_driver = FALSE;
01718
01719
01720
01721 driver_dir = g_getenv( "GNC_DBD_DIR" );
01722 if ( driver_dir == NULL )
01723 {
01724 PINFO( "GNC_DBD_DIR not set: using libdbi built-in default\n");
01725 }
01726
01727
01728 num_drivers = dbi_initialize( driver_dir );
01729 if ( num_drivers <= 0 )
01730 {
01731 PWARN( "No DBD drivers found\n" );
01732 }
01733 else
01734 {
01735 dbi_driver driver = NULL;
01736 PINFO( "%d DBD drivers found\n", num_drivers );
01737
01738 do
01739 {
01740 driver = dbi_driver_list( driver );
01741 if ( driver != NULL )
01742 {
01743 const gchar* name = dbi_driver_get_name( driver );
01744
01745 PINFO( "Driver: %s\n", name );
01746 if ( strcmp( name, "sqlite3" ) == 0 )
01747 {
01748 have_sqlite3_driver = TRUE;
01749 }
01750 else if ( strcmp( name, "mysql" ) == 0 )
01751 {
01752 have_mysql_driver = TRUE;
01753 }
01754 else if ( strcmp( name, "pgsql" ) == 0 )
01755 {
01756 have_pgsql_driver = TRUE;
01757 }
01758 }
01759 }
01760 while ( driver != NULL );
01761 }
01762
01763 if ( have_sqlite3_driver )
01764 {
01765 prov = g_new0( QofBackendProvider, 1 );
01766 g_assert( prov != NULL );
01767
01768 prov->provider_name = "GnuCash Libdbi (SQLITE3) Backend";
01769 prov->access_method = FILE_URI_TYPE;
01770 prov->partial_book_supported = FALSE;
01771 prov->backend_new = gnc_dbi_backend_sqlite3_new;
01772 prov->provider_free = gnc_dbi_provider_free;
01773 prov->check_data_type = gnc_dbi_check_sqlite3_file;
01774 qof_backend_register_provider( prov );
01775
01776 prov = g_new0( QofBackendProvider, 1 );
01777 g_assert( prov != NULL );
01778
01779 prov->provider_name = "GnuCash Libdbi (SQLITE3) Backend";
01780 prov->access_method = SQLITE3_URI_TYPE;
01781 prov->partial_book_supported = FALSE;
01782 prov->backend_new = gnc_dbi_backend_sqlite3_new;
01783 prov->provider_free = gnc_dbi_provider_free;
01784 prov->check_data_type = gnc_dbi_check_sqlite3_file;
01785 qof_backend_register_provider( prov );
01786 }
01787
01788 if ( have_mysql_driver )
01789 {
01790 prov = g_new0( QofBackendProvider, 1 );
01791 g_assert( prov != NULL );
01792
01793 prov->provider_name = "GnuCash Libdbi (MYSQL) Backend";
01794 prov->access_method = "mysql";
01795 prov->partial_book_supported = FALSE;
01796 prov->backend_new = gnc_dbi_backend_mysql_new;
01797 prov->provider_free = gnc_dbi_provider_free;
01798 prov->check_data_type = NULL;
01799 qof_backend_register_provider( prov );
01800 }
01801
01802 if ( have_pgsql_driver )
01803 {
01804 prov = g_new0( QofBackendProvider, 1 );
01805 g_assert( prov != NULL );
01806
01807 prov->provider_name = "GnuCash Libdbi (POSTGRESQL) Backend";
01808 prov->access_method = "postgres";
01809 prov->partial_book_supported = FALSE;
01810 prov->backend_new = gnc_dbi_backend_postgres_new;
01811 prov->provider_free = gnc_dbi_provider_free;
01812 prov->check_data_type = NULL;
01813 qof_backend_register_provider( prov );
01814 }
01815
01816
01817
01818
01819 }
01820
01821 #ifndef GNC_NO_LOADABLE_MODULES
01822 G_MODULE_EXPORT void
01823 qof_backend_module_init( void )
01824 {
01825 gnc_module_init_backend_dbi();
01826 }
01827
01828 G_MODULE_EXPORT void
01829 qof_backend_module_finalize( void )
01830 {
01831 gnc_module_finalize_backend_dbi();
01832 }
01833 #endif
01834
01835 void
01836 gnc_module_finalize_backend_dbi( void )
01837 {
01838 dbi_shutdown();
01839 }
01840
01841
01842 typedef struct
01843 {
01844 GncSqlRow base;
01845
01846
01847 dbi_result result;
01848 GList* gvalue_list;
01849 } GncDbiSqlRow;
01850
01851 static void
01852 row_dispose( GncSqlRow* row )
01853 {
01854 GncDbiSqlRow* dbi_row = (GncDbiSqlRow*)row;
01855 GList* node;
01856
01857 if ( dbi_row->gvalue_list != NULL )
01858 {
01859 for ( node = dbi_row->gvalue_list; node != NULL; node = node->next )
01860 {
01861 GValue* value;
01862 if ( !G_IS_VALUE(node->data) )
01863 continue;
01864 value = (GValue*)node->data;
01865 if ( G_VALUE_HOLDS_STRING(value) )
01866 {
01867 g_free( (gpointer)g_value_get_string( value ) );
01868 }
01869 g_free( value );
01870 }
01871 g_list_free( dbi_row->gvalue_list );
01872 }
01873 g_free( dbi_row );
01874 }
01875
01876 static const GValue*
01877 row_get_value_at_col_name( GncSqlRow* row, const gchar* col_name )
01878 {
01879 GncDbiSqlRow* dbi_row = (GncDbiSqlRow*)row;
01880 gushort type;
01881 guint attrs;
01882 GValue* value;
01883 time_t time;
01884 struct tm tm_struct;
01885
01886 type = dbi_result_get_field_type( dbi_row->result, col_name );
01887 attrs = dbi_result_get_field_attribs( dbi_row->result, col_name );
01888 value = g_new0( GValue, 1 );
01889 g_assert( value != NULL );
01890
01891 switch ( type )
01892 {
01893 case DBI_TYPE_INTEGER:
01894 (void)g_value_init( value, G_TYPE_INT64 );
01895 g_value_set_int64( value, dbi_result_get_longlong( dbi_row->result, col_name ) );
01896 break;
01897 case DBI_TYPE_DECIMAL:
01898 gnc_push_locale( LC_NUMERIC, "C" );
01899 if ( (attrs & DBI_DECIMAL_SIZEMASK) == DBI_DECIMAL_SIZE4 )
01900 {
01901 (void)g_value_init( value, G_TYPE_FLOAT );
01902 g_value_set_float( value, dbi_result_get_float( dbi_row->result, col_name ) );
01903 }
01904 else if ( (attrs & DBI_DECIMAL_SIZEMASK) == DBI_DECIMAL_SIZE8 )
01905 {
01906 (void)g_value_init( value, G_TYPE_DOUBLE );
01907 g_value_set_double( value, dbi_result_get_double( dbi_row->result, col_name ) );
01908 }
01909 else
01910 {
01911 PERR( "Field %s: strange decimal length attrs=%d\n", col_name, attrs );
01912 }
01913 gnc_pop_locale( LC_NUMERIC );
01914 break;
01915 case DBI_TYPE_STRING:
01916 (void)g_value_init( value, G_TYPE_STRING );
01917 g_value_take_string( value, dbi_result_get_string_copy( dbi_row->result, col_name ) );
01918 break;
01919 case DBI_TYPE_DATETIME:
01920 if ( dbi_result_field_is_null( dbi_row->result, col_name ) )
01921 {
01922 return NULL;
01923 }
01924 else
01925 {
01926 time = dbi_result_get_datetime( dbi_row->result, col_name );
01927 (void)gmtime_r( &time, &tm_struct );
01928 (void)g_value_init( value, G_TYPE_STRING );
01929 g_value_take_string( value,
01930 g_strdup_printf( "%d%02d%02d%02d%02d%02d",
01931 1900 + tm_struct.tm_year, tm_struct.tm_mon + 1, tm_struct.tm_mday,
01932 tm_struct.tm_hour, tm_struct.tm_min, tm_struct.tm_sec ) );
01933 }
01934 break;
01935 default:
01936 PERR( "Field %s: unknown DBI_TYPE: %d\n", col_name, type );
01937 g_free( value );
01938 return NULL;
01939 }
01940
01941 dbi_row->gvalue_list = g_list_prepend( dbi_row->gvalue_list, value );
01942 return value;
01943 }
01944
01945 static GncSqlRow*
01946 create_dbi_row( dbi_result result )
01947 {
01948 GncDbiSqlRow* row;
01949
01950 row = g_new0( GncDbiSqlRow, 1 );
01951 g_assert( row != NULL );
01952
01953 row->base.getValueAtColName = row_get_value_at_col_name;
01954 row->base.dispose = row_dispose;
01955 row->result = result;
01956
01957 return (GncSqlRow*)row;
01958 }
01959
01960 typedef struct
01961 {
01962 GncSqlResult base;
01963
01964
01965 GncDbiSqlConnection* dbi_conn;
01966
01967 dbi_result result;
01968 guint num_rows;
01969 guint cur_row;
01970 GncSqlRow* row;
01971 } GncDbiSqlResult;
01972
01973 static void
01974 result_dispose( GncSqlResult* result )
01975 {
01976 GncDbiSqlResult* dbi_result = (GncDbiSqlResult*)result;
01977
01978 if ( dbi_result->row != NULL )
01979 {
01980 gnc_sql_row_dispose( dbi_result->row );
01981 }
01982 if ( dbi_result->result != NULL )
01983 {
01984 gint status;
01985
01986 status = dbi_result_free( dbi_result->result );
01987 if ( status < 0 )
01988 {
01989 PERR( "Error in dbi_result_free() result\n" );
01990 qof_backend_set_error( dbi_result->dbi_conn->qbe, ERR_BACKEND_SERVER_ERR );
01991 }
01992 }
01993 g_free( result );
01994 }
01995
01996 static guint
01997 result_get_num_rows( GncSqlResult* result )
01998 {
01999 GncDbiSqlResult* dbi_result = (GncDbiSqlResult*)result;
02000
02001 return dbi_result->num_rows;
02002 }
02003
02004 static GncSqlRow*
02005 result_get_first_row( GncSqlResult* result )
02006 {
02007 GncDbiSqlResult* dbi_result = (GncDbiSqlResult*)result;
02008
02009 if ( dbi_result->row != NULL )
02010 {
02011 gnc_sql_row_dispose( dbi_result->row );
02012 dbi_result->row = NULL;
02013 }
02014 if ( dbi_result->num_rows > 0 )
02015 {
02016 gint status = dbi_result_first_row( dbi_result->result );
02017 if ( status == 0 )
02018 {
02019 PERR( "Error in dbi_result_first_row()\n" );
02020 qof_backend_set_error( dbi_result->dbi_conn->qbe, ERR_BACKEND_SERVER_ERR );
02021 }
02022 dbi_result->cur_row = 1;
02023 dbi_result->row = create_dbi_row( dbi_result->result );
02024 return dbi_result->row;
02025 }
02026 else
02027 {
02028 return NULL;
02029 }
02030 }
02031
02032 static GncSqlRow*
02033 result_get_next_row( GncSqlResult* result )
02034 {
02035 GncDbiSqlResult* dbi_result = (GncDbiSqlResult*)result;
02036
02037 if ( dbi_result->row != NULL )
02038 {
02039 gnc_sql_row_dispose( dbi_result->row );
02040 dbi_result->row = NULL;
02041 }
02042 if ( dbi_result->cur_row < dbi_result->num_rows )
02043 {
02044 gint status = dbi_result_next_row( dbi_result->result );
02045 if ( status == 0 )
02046 {
02047 PERR( "Error in dbi_result_first_row()\n" );
02048 qof_backend_set_error( dbi_result->dbi_conn->qbe, ERR_BACKEND_SERVER_ERR );
02049 }
02050 dbi_result->cur_row++;
02051 dbi_result->row = create_dbi_row( dbi_result->result );
02052 return dbi_result->row;
02053 }
02054 else
02055 {
02056 return NULL;
02057 }
02058 }
02059
02060 static GncSqlResult*
02061 create_dbi_result( GncDbiSqlConnection* dbi_conn, dbi_result result )
02062 {
02063 GncDbiSqlResult* dbi_result;
02064
02065 dbi_result = g_new0( GncDbiSqlResult, 1 );
02066 g_assert( dbi_result != NULL );
02067
02068 dbi_result->base.dispose = result_dispose;
02069 dbi_result->base.getNumRows = result_get_num_rows;
02070 dbi_result->base.getFirstRow = result_get_first_row;
02071 dbi_result->base.getNextRow = result_get_next_row;
02072 dbi_result->result = result;
02073 dbi_result->num_rows = (guint)dbi_result_get_numrows( result );
02074 dbi_result->cur_row = 0;
02075 dbi_result->dbi_conn = dbi_conn;
02076
02077 return (GncSqlResult*)dbi_result;
02078 }
02079
02080 typedef struct
02081 {
02082 GncSqlStatement base;
02083
02084 GString* sql;
02085
02086 GncSqlConnection* conn;
02087 } GncDbiSqlStatement;
02088
02089 static void
02090 stmt_dispose( GncSqlStatement* stmt )
02091 {
02092 GncDbiSqlStatement* dbi_stmt = (GncDbiSqlStatement*)stmt;
02093
02094 if ( dbi_stmt->sql != NULL )
02095 {
02096 (void)g_string_free( dbi_stmt->sql, TRUE );
02097 }
02098 g_free( stmt );
02099 }
02100
02101 static gchar*
02102 stmt_to_sql( GncSqlStatement* stmt )
02103 {
02104 GncDbiSqlStatement* dbi_stmt = (GncDbiSqlStatement*)stmt;
02105
02106 return dbi_stmt->sql->str;
02107 }
02108
02109 static void
02110 stmt_add_where_cond( GncSqlStatement* stmt, QofIdTypeConst type_name,
02111 gpointer obj, const GncSqlColumnTableEntry* table_row, GValue* value )
02112 {
02113 GncDbiSqlStatement* dbi_stmt = (GncDbiSqlStatement*)stmt;
02114 gchar* buf;
02115 gchar* value_str;
02116
02117 value_str = gnc_sql_get_sql_value( dbi_stmt->conn, value );
02118 buf = g_strdup_printf( " WHERE %s = %s", table_row->col_name,
02119 value_str );
02120 g_free( value_str );
02121 (void)g_string_append( dbi_stmt->sql, buf );
02122 g_free( buf );
02123 }
02124
02125 static GncSqlStatement*
02126 create_dbi_statement( GncSqlConnection* conn, const gchar* sql )
02127 {
02128 GncDbiSqlStatement* stmt;
02129
02130 stmt = g_new0( GncDbiSqlStatement, 1 );
02131 g_assert( stmt != NULL );
02132
02133 stmt->base.dispose = stmt_dispose;
02134 stmt->base.toSql = stmt_to_sql;
02135 stmt->base.addWhereCond = stmt_add_where_cond;
02136 stmt->sql = g_string_new( sql );
02137 stmt->conn = conn;
02138
02139 return (GncSqlStatement*)stmt;
02140 }
02141
02142 static void
02143 conn_dispose( GncSqlConnection* conn )
02144 {
02145
02146
02147 g_free( conn );
02148 }
02149
02150 static GncSqlResult*
02151 conn_execute_select_statement( GncSqlConnection* conn, GncSqlStatement* stmt )
02152 {
02153 GncDbiSqlConnection* dbi_conn = (GncDbiSqlConnection*)conn;
02154 GncDbiSqlStatement* dbi_stmt = (GncDbiSqlStatement*)stmt;
02155 dbi_result result;
02156
02157 DEBUG( "SQL: %s\n", dbi_stmt->sql->str );
02158 gnc_push_locale( LC_NUMERIC, "C" );
02159 do
02160 {
02161 gnc_dbi_init_error( dbi_conn );
02162 result = dbi_conn_query( dbi_conn->conn, dbi_stmt->sql->str );
02163 }
02164 while ( dbi_conn->retry );
02165 if ( result == NULL )
02166 {
02167 PERR( "Error executing SQL %s\n", dbi_stmt->sql->str );
02168 return NULL;
02169 }
02170 gnc_pop_locale( LC_NUMERIC );
02171 return create_dbi_result( dbi_conn, result );
02172 }
02173
02174 static gint
02175 conn_execute_nonselect_statement( GncSqlConnection* conn, GncSqlStatement* stmt )
02176 {
02177 GncDbiSqlConnection* dbi_conn = (GncDbiSqlConnection*)conn;
02178 GncDbiSqlStatement* dbi_stmt = (GncDbiSqlStatement*)stmt;
02179 dbi_result result;
02180 gint num_rows;
02181 gint status;
02182
02183 DEBUG( "SQL: %s\n", dbi_stmt->sql->str );
02184 do
02185 {
02186 gnc_dbi_init_error( dbi_conn );
02187 result = dbi_conn_query( dbi_conn->conn, dbi_stmt->sql->str );
02188 }
02189 while ( dbi_conn->retry );
02190 if ( result == NULL )
02191 {
02192 PERR( "Error executing SQL %s\n", dbi_stmt->sql->str );
02193 return -1;
02194 }
02195 num_rows = (gint)dbi_result_get_numrows_affected( result );
02196 status = dbi_result_free( result );
02197 if ( status < 0 )
02198 {
02199 PERR( "Error in dbi_result_free() result\n" );
02200 qof_backend_set_error( dbi_conn->qbe, ERR_BACKEND_SERVER_ERR );
02201 }
02202 return num_rows;
02203 }
02204
02205 static GncSqlStatement*
02206 conn_create_statement_from_sql( GncSqlConnection* conn, const gchar* sql )
02207 {
02208
02209
02210 return create_dbi_statement( conn, sql );
02211 }
02212
02213 static GValue*
02214 create_gvalue_from_string( gchar* s )
02215 {
02216 GValue* s_gval;
02217
02218 s_gval = g_new0( GValue, 1 );
02219 g_assert( s_gval != NULL );
02220
02221 (void)g_value_init( s_gval, G_TYPE_STRING );
02222 g_value_take_string( s_gval, s );
02223
02224 return s_gval;
02225 }
02226
02227 static gboolean
02228 conn_does_table_exist( GncSqlConnection* conn, const gchar* table_name )
02229 {
02230 GncDbiSqlConnection* dbi_conn = (GncDbiSqlConnection*)conn;
02231 gint nTables;
02232 dbi_result tables;
02233 const gchar* dbname;
02234 gint status;
02235
02236 g_return_val_if_fail( conn != NULL, FALSE );
02237 g_return_val_if_fail( table_name != NULL, FALSE );
02238
02239 dbname = dbi_conn_get_option( dbi_conn->conn, "dbname" );
02240 tables = dbi_conn_get_table_list( dbi_conn->conn, dbname, table_name );
02241 nTables = (gint)dbi_result_get_numrows( tables );
02242 status = dbi_result_free( tables );
02243 if ( status < 0 )
02244 {
02245 PERR( "Error in dbi_result_free() result\n" );
02246 qof_backend_set_error( dbi_conn->qbe, ERR_BACKEND_SERVER_ERR );
02247 }
02248
02249 if ( nTables == 1 )
02250 {
02251 return TRUE;
02252 }
02253 else
02254 {
02255 return FALSE;
02256 }
02257 }
02258
02259 static gboolean
02260 conn_begin_transaction( GncSqlConnection* conn )
02261 {
02262 GncDbiSqlConnection* dbi_conn = (GncDbiSqlConnection*)conn;
02263 dbi_result result;
02264 gint status;
02265 gboolean success = FALSE;
02266
02267 DEBUG( "BEGIN\n" );
02268
02269 if ( !gnc_dbi_verify_conn (dbi_conn) )
02270 {
02271 PERR( "gnc_dbi_verify_conn() failed\n" );
02272 qof_backend_set_error( dbi_conn->qbe, ERR_BACKEND_SERVER_ERR );
02273 return FALSE;
02274 }
02275
02276 do
02277 {
02278 gnc_dbi_init_error( dbi_conn );
02279 result = dbi_conn_queryf( dbi_conn->conn, "BEGIN" );
02280 }
02281 while ( dbi_conn->retry );
02282
02283 success = ( result != NULL );
02284 status = dbi_result_free( result );
02285 if ( status < 0 )
02286 {
02287 PERR( "Error in dbi_result_free() result\n" );
02288 qof_backend_set_error( dbi_conn->qbe, ERR_BACKEND_SERVER_ERR );
02289 }
02290 if ( !success )
02291 {
02292 PERR( "BEGIN transaction failed()\n" );
02293 qof_backend_set_error( dbi_conn->qbe, ERR_BACKEND_SERVER_ERR );
02294 }
02295
02296 return success;
02297 }
02298
02299 static gboolean
02300 conn_rollback_transaction( GncSqlConnection* conn )
02301 {
02302 GncDbiSqlConnection* dbi_conn = (GncDbiSqlConnection*)conn;
02303 dbi_result result;
02304 gint status;
02305 gboolean success = FALSE;
02306
02307 DEBUG( "ROLLBACK\n" );
02308 result = dbi_conn_queryf( dbi_conn->conn, "ROLLBACK" );
02309 success = ( result != NULL );
02310
02311 status = dbi_result_free( result );
02312 if ( status < 0 )
02313 {
02314 PERR( "Error in dbi_result_free() result\n" );
02315 qof_backend_set_error( dbi_conn->qbe, ERR_BACKEND_SERVER_ERR );
02316 }
02317 if ( !success )
02318 {
02319 PERR( "Error in conn_rollback_transaction()\n" );
02320 qof_backend_set_error( dbi_conn->qbe, ERR_BACKEND_SERVER_ERR );
02321 }
02322
02323 return success;
02324 }
02325
02326 static gboolean
02327 conn_commit_transaction( GncSqlConnection* conn )
02328 {
02329 GncDbiSqlConnection* dbi_conn = (GncDbiSqlConnection*)conn;
02330 dbi_result result;
02331 gint status;
02332 gboolean success = FALSE;
02333
02334 DEBUG( "COMMIT\n" );
02335 result = dbi_conn_queryf( dbi_conn->conn, "COMMIT" );
02336 success = ( result != NULL );
02337
02338 status = dbi_result_free( result );
02339 if ( status < 0 )
02340 {
02341 PERR( "Error in dbi_result_free() result\n" );
02342 qof_backend_set_error( dbi_conn->qbe, ERR_BACKEND_SERVER_ERR );
02343 }
02344 if ( !success )
02345 {
02346 PERR( "Error in conn_commit_transaction()\n" );
02347 qof_backend_set_error( dbi_conn->qbe, ERR_BACKEND_SERVER_ERR );
02348 }
02349
02350 return success;
02351 }
02352
02353 static gchar*
02354 create_index_ddl( GncSqlConnection* conn,
02355 const gchar* index_name,
02356 const gchar* table_name,
02357 const GncSqlColumnTableEntry* col_table )
02358 {
02359 GString* ddl;
02360 const GncSqlColumnTableEntry* table_row;
02361
02362 g_return_val_if_fail( conn != NULL, NULL );
02363 g_return_val_if_fail( index_name != NULL, NULL );
02364 g_return_val_if_fail( table_name != NULL, NULL );
02365 g_return_val_if_fail( col_table != NULL, NULL );
02366
02367 ddl = g_string_new( "" );
02368 g_string_printf( ddl, "CREATE INDEX %s ON %s (", index_name, table_name );
02369 for ( table_row = col_table; table_row->col_name != NULL; ++table_row )
02370 {
02371 if ( table_row != col_table )
02372 {
02373 (void)g_string_append( ddl, ", " );
02374 }
02375 g_string_append_printf( ddl, "%s", table_row->col_name );
02376 }
02377 (void)g_string_append( ddl, ")" );
02378
02379 return g_string_free( ddl, FALSE );
02380 }
02381
02382 static gchar*
02383 add_columns_ddl( GncSqlConnection* conn,
02384 const gchar* table_name,
02385 GList* col_info_list )
02386 {
02387 GString* ddl;
02388 const GList* list_node;
02389 const GncSqlColumnTableEntry* table_row;
02390 guint col_num;
02391 GncDbiSqlConnection* dbi_conn = (GncDbiSqlConnection*)conn;
02392
02393 g_return_val_if_fail( conn != NULL, NULL );
02394 g_return_val_if_fail( table_name != NULL, NULL );
02395 g_return_val_if_fail( col_info_list != NULL, NULL );
02396
02397 ddl = g_string_new( "" );
02398 g_string_printf( ddl, "ALTER TABLE %s ", table_name );
02399 for ( list_node = col_info_list, col_num = 0; list_node != NULL;
02400 list_node = list_node->next, col_num++ )
02401 {
02402 GncSqlColumnInfo* info = (GncSqlColumnInfo*)(list_node->data);
02403
02404 if ( col_num != 0 )
02405 {
02406 (void)g_string_append( ddl, ", " );
02407 }
02408 g_string_append( ddl, "ADD COLUMN " );
02409 dbi_conn->provider->append_col_def( ddl, info );
02410 g_free( info->name );
02411 g_free( info );
02412 }
02413
02414 return g_string_free( ddl, FALSE );
02415 }
02416
02417 static void
02418 append_sqlite3_col_def( GString* ddl, GncSqlColumnInfo* info )
02419 {
02420 gchar* type_name;
02421
02422 if ( info->type == BCT_INT )
02423 {
02424 type_name = "integer";
02425 }
02426 else if ( info->type == BCT_INT64 )
02427 {
02428 type_name = "bigint";
02429 }
02430 else if ( info->type == BCT_DOUBLE )
02431 {
02432 type_name = "float8";
02433 }
02434 else if ( info->type == BCT_STRING || info->type == BCT_DATE
02435 || info->type == BCT_DATETIME )
02436 {
02437 type_name = "text";
02438 }
02439 else
02440 {
02441 PERR( "Unknown column type: %d\n", info->type );
02442 type_name = "";
02443 }
02444 g_string_append_printf( ddl, "%s %s", info->name, type_name );
02445 if ( info->size != 0 )
02446 {
02447 (void)g_string_append_printf( ddl, "(%d)", info->size );
02448 }
02449 if ( info->is_primary_key )
02450 {
02451 (void)g_string_append( ddl, " PRIMARY KEY" );
02452 }
02453 if ( info->is_autoinc )
02454 {
02455 (void)g_string_append( ddl, " AUTOINCREMENT" );
02456 }
02457 if ( !info->null_allowed )
02458 {
02459 (void)g_string_append( ddl, " NOT NULL" );
02460 }
02461 }
02462
02463 static gchar*
02464 conn_create_table_ddl_sqlite3( GncSqlConnection* conn,
02465 const gchar* table_name,
02466 const GList* col_info_list )
02467 {
02468 GString* ddl;
02469 const GList* list_node;
02470 guint col_num;
02471
02472 g_return_val_if_fail( conn != NULL, NULL );
02473 g_return_val_if_fail( table_name != NULL, NULL );
02474 g_return_val_if_fail( col_info_list != NULL, NULL );
02475
02476 ddl = g_string_new( "" );
02477 g_string_printf( ddl, "CREATE TABLE %s (", table_name );
02478 for ( list_node = col_info_list, col_num = 0; list_node != NULL;
02479 list_node = list_node->next, col_num++ )
02480 {
02481 GncSqlColumnInfo* info = (GncSqlColumnInfo*)(list_node->data);
02482
02483 if ( col_num != 0 )
02484 {
02485 (void)g_string_append( ddl, ", " );
02486 }
02487 append_sqlite3_col_def( ddl, info );
02488 g_free( info->name );
02489 g_free( info );
02490 }
02491 (void)g_string_append( ddl, ")" );
02492
02493 return g_string_free( ddl, FALSE );
02494 }
02495
02496 static void
02497 append_mysql_col_def( GString* ddl, GncSqlColumnInfo* info )
02498 {
02499 gchar* type_name;
02500
02501 if ( info->type == BCT_INT )
02502 {
02503 type_name = "integer";
02504 }
02505 else if ( info->type == BCT_INT64 )
02506 {
02507 type_name = "bigint";
02508 }
02509 else if ( info->type == BCT_DOUBLE )
02510 {
02511 type_name = "double";
02512 }
02513 else if ( info->type == BCT_STRING )
02514 {
02515 type_name = "varchar";
02516 }
02517 else if ( info->type == BCT_DATE )
02518 {
02519 info->size = 0;
02520 type_name = "date";
02521 }
02522 else if ( info->type == BCT_DATETIME )
02523 {
02524 info->size = 0;
02525 type_name = "TIMESTAMP NULL DEFAULT 0";
02526 }
02527 else
02528 {
02529 PERR( "Unknown column type: %d\n", info->type );
02530 type_name = "";
02531 }
02532 g_string_append_printf( ddl, "%s %s", info->name, type_name );
02533 if ( info->size != 0 )
02534 {
02535 g_string_append_printf( ddl, "(%d)", info->size );
02536 }
02537 if ( info->is_unicode )
02538 {
02539 (void)g_string_append( ddl, " CHARACTER SET utf8" );
02540 }
02541 if ( info->is_primary_key )
02542 {
02543 (void)g_string_append( ddl, " PRIMARY KEY" );
02544 }
02545 if ( info->is_autoinc )
02546 {
02547 (void)g_string_append( ddl, " AUTO_INCREMENT" );
02548 }
02549 if ( !info->null_allowed )
02550 {
02551 (void)g_string_append( ddl, " NOT NULL" );
02552 }
02553 }
02554
02555 static gchar*
02556 conn_create_table_ddl_mysql( GncSqlConnection* conn, const gchar* table_name,
02557 const GList* col_info_list )
02558 {
02559 GString* ddl;
02560 const GList* list_node;
02561 guint col_num;
02562
02563 g_return_val_if_fail( conn != NULL, NULL );
02564 g_return_val_if_fail( table_name != NULL, NULL );
02565 g_return_val_if_fail( col_info_list != NULL, NULL );
02566
02567 ddl = g_string_new( "" );
02568 g_string_printf( ddl, "CREATE TABLE %s (", table_name );
02569 for ( list_node = col_info_list, col_num = 0; list_node != NULL;
02570 list_node = list_node->next, col_num++ )
02571 {
02572 GncSqlColumnInfo* info = (GncSqlColumnInfo*)(list_node->data);
02573
02574 if ( col_num != 0 )
02575 {
02576 (void)g_string_append( ddl, ", " );
02577 }
02578 append_mysql_col_def( ddl, info );
02579 g_free( info->name );
02580 g_free( info );
02581 }
02582 (void)g_string_append( ddl, ")" );
02583
02584 return g_string_free( ddl, FALSE );
02585 }
02586
02587 static void
02588 append_pgsql_col_def( GString* ddl, GncSqlColumnInfo* info )
02589 {
02590 gchar* type_name;
02591
02592 if ( info->type == BCT_INT )
02593 {
02594 if ( info->is_autoinc )
02595 {
02596 type_name = "serial";
02597 }
02598 else
02599 {
02600 type_name = "integer";
02601 }
02602 }
02603 else if ( info->type == BCT_INT64 )
02604 {
02605 type_name = "int8";
02606 }
02607 else if ( info->type == BCT_DOUBLE )
02608 {
02609 type_name = "double precision";
02610 }
02611 else if ( info->type == BCT_STRING )
02612 {
02613 type_name = "varchar";
02614 }
02615 else if ( info->type == BCT_DATE )
02616 {
02617 info->size = 0;
02618 type_name = "date";
02619 }
02620 else if ( info->type == BCT_DATETIME )
02621 {
02622 info->size = 0;
02623 type_name = "timestamp without time zone";
02624 }
02625 else
02626 {
02627 PERR( "Unknown column type: %d\n", info->type );
02628 type_name = "";
02629 }
02630 g_string_append_printf( ddl, "%s %s", info->name, type_name );
02631 if ( info->size != 0 )
02632 {
02633 g_string_append_printf( ddl, "(%d)", info->size );
02634 }
02635 if ( info->is_primary_key )
02636 {
02637 (void)g_string_append( ddl, " PRIMARY KEY" );
02638 }
02639 if ( !info->null_allowed )
02640 {
02641 (void)g_string_append( ddl, " NOT NULL" );
02642 }
02643 }
02644
02645 static gchar*
02646 conn_create_table_ddl_pgsql( GncSqlConnection* conn, const gchar* table_name,
02647 const GList* col_info_list )
02648 {
02649 GString* ddl;
02650 const GList* list_node;
02651 guint col_num;
02652 gboolean is_unicode = FALSE;
02653
02654 g_return_val_if_fail( conn != NULL, NULL );
02655 g_return_val_if_fail( table_name != NULL, NULL );
02656 g_return_val_if_fail( col_info_list != NULL, NULL );
02657
02658 ddl = g_string_new( "" );
02659 g_string_printf( ddl, "CREATE TABLE %s (", table_name );
02660 for ( list_node = col_info_list, col_num = 0; list_node != NULL;
02661 list_node = list_node->next, col_num++ )
02662 {
02663 GncSqlColumnInfo* info = (GncSqlColumnInfo*)(list_node->data);
02664
02665 if ( col_num != 0 )
02666 {
02667 (void)g_string_append( ddl, ", " );
02668 }
02669 append_pgsql_col_def( ddl, info );
02670 is_unicode = is_unicode || info->is_unicode;
02671 g_free( info->name );
02672 g_free( info );
02673 }
02674 (void)g_string_append( ddl, ")" );
02675 if ( is_unicode )
02676 {
02677 }
02678
02679 return g_string_free( ddl, FALSE );
02680 }
02681
02682 static gboolean
02683 conn_create_table( GncSqlConnection* conn, const gchar* table_name,
02684 GList* col_info_list )
02685 {
02686 GncDbiSqlConnection* dbi_conn = (GncDbiSqlConnection*)conn;
02687 gchar* ddl;
02688 dbi_result result;
02689
02690 g_return_val_if_fail( conn != NULL, FALSE );
02691 g_return_val_if_fail( table_name != NULL, FALSE );
02692 g_return_val_if_fail( col_info_list != NULL, FALSE );
02693
02694
02695 ddl = dbi_conn->provider->create_table_ddl( conn, table_name,
02696 col_info_list );
02697 g_list_free( col_info_list );
02698 if ( ddl != NULL )
02699 {
02700 gint status;
02701
02702 DEBUG( "SQL: %s\n", ddl );
02703 result = dbi_conn_query( dbi_conn->conn, ddl );
02704 g_free( ddl );
02705 status = dbi_result_free( result );
02706 if ( status < 0 )
02707 {
02708 PERR( "Error in dbi_result_free() result\n" );
02709 qof_backend_set_error( dbi_conn->qbe, ERR_BACKEND_SERVER_ERR );
02710 }
02711 }
02712 else
02713 {
02714 return FALSE;
02715 }
02716
02717 return TRUE;
02718 }
02719
02720 static gboolean
02721 conn_create_index( GncSqlConnection* conn, const gchar* index_name,
02722 const gchar* table_name, const GncSqlColumnTableEntry* col_table )
02723 {
02724 GncDbiSqlConnection* dbi_conn = (GncDbiSqlConnection*)conn;
02725 gchar* ddl;
02726 dbi_result result;
02727 gint status;
02728
02729 g_return_val_if_fail( conn != NULL, FALSE );
02730 g_return_val_if_fail( index_name != NULL, FALSE );
02731 g_return_val_if_fail( table_name != NULL, FALSE );
02732 g_return_val_if_fail( col_table != NULL, FALSE );
02733
02734 ddl = create_index_ddl( conn, index_name, table_name, col_table );
02735 if ( ddl != NULL )
02736 {
02737 gint status;
02738
02739 DEBUG( "SQL: %s\n", ddl );
02740 result = dbi_conn_query( dbi_conn->conn, ddl );
02741 g_free( ddl );
02742 status = dbi_result_free( result );
02743 if ( status < 0 )
02744 {
02745 PERR( "Error in dbi_result_free() result\n" );
02746 qof_backend_set_error( dbi_conn->qbe, ERR_BACKEND_SERVER_ERR );
02747 }
02748 }
02749 else
02750 {
02751 return FALSE;
02752 }
02753
02754 return TRUE;
02755 }
02756
02757 static gboolean
02758 conn_add_columns_to_table( GncSqlConnection* conn, const gchar* table_name,
02759 GList* col_info_list )
02760 {
02761 GncDbiSqlConnection* dbi_conn = (GncDbiSqlConnection*)conn;
02762 gchar* ddl;
02763 dbi_result result;
02764 gint status;
02765
02766 g_return_val_if_fail( conn != NULL, FALSE );
02767 g_return_val_if_fail( table_name != NULL, FALSE );
02768 g_return_val_if_fail( col_info_list != NULL, FALSE );
02769
02770 ddl = add_columns_ddl( conn, table_name, col_info_list );
02771 if ( ddl != NULL )
02772 {
02773 gint status;
02774
02775 DEBUG( "SQL: %s\n", ddl );
02776 result = dbi_conn_query( dbi_conn->conn, ddl );
02777 g_free( ddl );
02778 status = dbi_result_free( result );
02779 if ( status < 0 )
02780 {
02781 PERR( "Error in dbi_result_free() result\n" );
02782 qof_backend_set_error( dbi_conn->qbe, ERR_BACKEND_SERVER_ERR );
02783 }
02784 }
02785 else
02786 {
02787 return FALSE;
02788 }
02789
02790 return TRUE;
02791 }
02792
02793 static gchar*
02794 conn_quote_string( const GncSqlConnection* conn, gchar* unquoted_str )
02795 {
02796 GncDbiSqlConnection* dbi_conn = (GncDbiSqlConnection*)conn;
02797 gchar* quoted_str;
02798 size_t size;
02799
02800 size = dbi_conn_quote_string_copy( dbi_conn->conn, unquoted_str,
02801 "ed_str );
02802 if ( size != 0 )
02803 {
02804 return quoted_str;
02805 }
02806 else
02807 {
02808 return NULL;
02809 }
02810 }
02811
02812 static GSList*
02813 conn_get_table_list( dbi_conn conn, const gchar* dbname )
02814 {
02815 dbi_result tables;
02816 GSList* list = NULL;
02817
02818 tables = dbi_conn_get_table_list( conn, dbname, NULL );
02819 while ( dbi_result_next_row( tables ) != 0 )
02820 {
02821 const gchar* table_name;
02822 dbi_result result;
02823
02824 table_name = dbi_result_get_string_idx( tables, 1 );
02825 list = g_slist_prepend( list, strdup( table_name ) );
02826 }
02827 dbi_result_free( tables );
02828 return list;
02829 }
02830
02831 static GSList*
02832 conn_get_table_list_sqlite3( dbi_conn conn, const gchar* dbname )
02833 {
02834 gboolean change_made;
02835
02836
02837
02838 GSList* list = conn_get_table_list( conn, dbname );
02839 change_made = TRUE;
02840 while ( list != NULL && change_made )
02841 {
02842 GSList* node;
02843
02844 change_made = FALSE;
02845 for ( node = list; node != NULL; node = node->next )
02846 {
02847 const gchar* table_name = (const gchar*)node->data;
02848
02849 if ( strcmp( table_name, "sqlite_sequence" ) == 0 )
02850 {
02851 g_free( node->data );
02852 list = g_slist_delete_link( list, node );
02853 change_made = TRUE;
02854 break;
02855 }
02856 }
02857 }
02858 return list;
02859 }
02860
02861 static GSList*
02862 conn_get_table_list_pgsql( dbi_conn conn, const gchar* dbname )
02863 {
02864 gboolean change_made;
02865
02866
02867 GSList* list = conn_get_table_list( conn, dbname );
02868 change_made = TRUE;
02869 while ( list != NULL && change_made )
02870 {
02871 GSList* node;
02872
02873 change_made = FALSE;
02874 for ( node = list; node != NULL; node = node->next )
02875 {
02876 const gchar* table_name = (const gchar*)node->data;
02877
02878 if ( strcmp( table_name, "sql_features" ) == 0 ||
02879 strcmp( table_name, "sql_implementation_info" ) == 0 ||
02880 strcmp( table_name, "sql_languages" ) == 0 ||
02881 strcmp( table_name, "sql_packages" ) == 0 ||
02882 strcmp( table_name, "sql_parts" ) == 0 ||
02883 strcmp( table_name, "sql_sizing" ) == 0 ||
02884 strcmp( table_name, "sql_sizing_profiles" ) == 0 )
02885 {
02886 g_free( node->data );
02887 list = g_slist_delete_link( list, node );
02888 change_made = TRUE;
02889 break;
02890 }
02891 }
02892 }
02893 return list;
02894 }
02895
02903 static gboolean
02904 conn_test_dbi_library( dbi_conn conn )
02905 {
02906 gint64 testlonglong = -9223372036854775807LL, resultlonglong = 0;
02907 guint64 testulonglong = 9223372036854775807LLU, resultulonglong = 0;
02908 gdouble testdouble = 1.7976921348623157E+307, resultdouble = 0.0;
02909 dbi_result result;
02910 gchar doublestr[G_ASCII_DTOSTR_BUF_SIZE], *querystr;
02911 gboolean retval = TRUE;
02912 memset( doublestr, 0, sizeof(doublestr));
02913
02914 result = dbi_conn_query( conn, "CREATE TEMPORARY TABLE numtest "
02915 "( test_int BIGINT, test_unsigned BIGINT,"
02916 " test_double FLOAT8 )" );
02917 if ( result == NULL )
02918 {
02919 PWARN("Test_DBI_Library: Create table failed");
02920 return FALSE;
02921 }
02922 dbi_result_free( result );
02923 g_ascii_dtostr( doublestr, sizeof(doublestr), testdouble );
02924 querystr = g_strdup_printf( "INSERT INTO numtest VALUES (%" G_GINT64_FORMAT
02925 ", %" G_GUINT64_FORMAT ", %s)",
02926 testlonglong, testulonglong, doublestr );
02927 result = dbi_conn_query( conn, querystr );
02928 g_free( querystr );
02929 if ( result == NULL )
02930 {
02931 PWARN("Test_DBI_Library: Failed to insert test row into table" );
02932 return FALSE;
02933 }
02934 dbi_result_free( result );
02935 gnc_push_locale( LC_NUMERIC, "C");
02936 result = dbi_conn_query( conn, "SELECT * FROM numtest" );
02937 if ( result == NULL )
02938 {
02939 const char *errmsg;
02940 dbi_conn_error( conn, &errmsg );
02941 PWARN("Test_DBI_Library: Failed to retrieve test row into table: %s",
02942 errmsg );
02943 result = dbi_conn_query( conn, "DROP TABLE numtest" );
02944 return FALSE;
02945 }
02946 while ( dbi_result_next_row( result ))
02947 {
02948 resultlonglong = dbi_result_get_longlong( result, "test_int" );
02949 resultulonglong = dbi_result_get_ulonglong( result, "test_unsigned" );
02950 resultdouble = dbi_result_get_double( result, "test_double" );
02951 }
02952 gnc_pop_locale( LC_NUMERIC );
02953 if ( testlonglong != resultlonglong )
02954 {
02955 PWARN( "Test_DBI_Library: LongLong Failed %" G_GINT64_FORMAT " != % " G_GINT64_FORMAT,
02956 testlonglong, resultlonglong );
02957 retval = FALSE;
02958 }
02959 if ( testulonglong != resultulonglong )
02960 {
02961 PWARN( "Test_DBI_Library: Unsigned longlong Failed %" G_GUINT64_FORMAT " != %" G_GUINT64_FORMAT,
02962 testulonglong, resultulonglong );
02963 retval = FALSE;
02964 }
02965
02966 if ( testdouble >= resultdouble + 0.000001e307 ||
02967 testdouble <= resultdouble - 0.000001e307 )
02968 {
02969 PWARN( "Test_DBI_Library: Double Failed %17e != %17e",
02970 testdouble, resultdouble );
02971 retval = FALSE;
02972 }
02973 return retval;
02974 }
02975
02976
02977 static GncSqlConnection*
02978 create_dbi_connection( provider_functions_t* provider,
02979 QofBackend* qbe,
02980 dbi_conn conn )
02981 {
02982 GncDbiSqlConnection* dbi_conn;
02983
02984 dbi_conn = g_new0( GncDbiSqlConnection, 1 );
02985 g_assert( dbi_conn != NULL );
02986
02987 dbi_conn->base.dispose = conn_dispose;
02988 dbi_conn->base.executeSelectStatement = conn_execute_select_statement;
02989 dbi_conn->base.executeNonSelectStatement = conn_execute_nonselect_statement;
02990 dbi_conn->base.createStatementFromSql = conn_create_statement_from_sql;
02991 dbi_conn->base.doesTableExist = conn_does_table_exist;
02992 dbi_conn->base.beginTransaction = conn_begin_transaction;
02993 dbi_conn->base.rollbackTransaction = conn_rollback_transaction;
02994 dbi_conn->base.commitTransaction = conn_commit_transaction;
02995 dbi_conn->base.createTable = conn_create_table;
02996 dbi_conn->base.createIndex = conn_create_index;
02997 dbi_conn->base.addColumnsToTable = conn_add_columns_to_table;
02998 dbi_conn->base.quoteString = conn_quote_string;
02999 dbi_conn->qbe = qbe;
03000 dbi_conn->conn = conn;
03001 dbi_conn->provider = provider;
03002 dbi_conn->conn_ok = TRUE;
03003 gnc_dbi_init_error(dbi_conn);
03004
03005 return (GncSqlConnection*)dbi_conn;
03006 }
03007
03008