From 905d7551a8f761cb6676cd8f9e67663708d90328 Mon Sep 17 00:00:00 2001 From: Phil Longstaff Date: Mon, 16 Feb 2009 16:22:18 +0000 Subject: [PATCH] Fix 64 bit integer handling. In an sqlite3 db, column types are basically ignored. However, libdbi uses the column type name to determine how big it thinks the integer value is. Therefore, change all 64 bit integer values (including num/denom in numeric values) to 'bigint'. Tables will be automatically upgraded when an sqlite3 file is opened. git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@17927 57a11ea4-9604-0410-9ed3-97b8803252fd --- src/backend/dbi/gnc-backend-dbi.c | 25 +++++------- src/backend/sql/gnc-backend-sql.c | 40 +++++++++++++++++++ src/backend/sql/gnc-backend-sql.h | 13 ++++++ src/backend/sql/gnc-lots-sql.c | 16 +------- src/backend/sql/gnc-price-sql.c | 4 ++ src/backend/sql/gnc-slots-sql.c | 6 ++- src/backend/sql/gnc-transaction-sql.c | 8 ++++ .../business-core/sql/gnc-bill-term-sql.c | 6 ++- .../business-core/sql/gnc-customer-sql.c | 4 ++ .../business-core/sql/gnc-employee-sql.c | 4 ++ .../business-core/sql/gnc-entry-sql.c | 4 ++ .../business-core/sql/gnc-invoice-sql.c | 4 ++ .../business-core/sql/gnc-tax-table-sql.c | 8 ++++ 13 files changed, 110 insertions(+), 32 deletions(-) diff --git a/src/backend/dbi/gnc-backend-dbi.c b/src/backend/dbi/gnc-backend-dbi.c index 9e42faf13f..1d4aa55764 100644 --- a/src/backend/dbi/gnc-backend-dbi.c +++ b/src/backend/dbi/gnc-backend-dbi.c @@ -676,24 +676,13 @@ row_get_value_at_col_name( GncSqlRow* row, const gchar* col_name ) GncDbiSqlRow* dbi_row = (GncDbiSqlRow*)row; gushort type; GValue* value; - long long v64; - gint64 raw_int64_value; - gint raw_int_value; type = dbi_result_get_field_type( dbi_row->result, col_name ); value = g_new0( GValue, 1 ); switch( type ) { case DBI_TYPE_INTEGER: g_value_init( value, G_TYPE_INT64 ); - - // FIXME: Bug in LibDBI: 64 bit int values returned incorrectly - v64 = dbi_result_get_longlong( dbi_row->result, col_name ); - raw_int64_value = dbi_result_get_longlong( dbi_row->result, col_name ); - raw_int_value = dbi_result_get_int( dbi_row->result, col_name ); - if( raw_int_value < 0 && raw_int64_value > 0 ) { - raw_int64_value = raw_int_value; - } - g_value_set_int64( value, raw_int64_value ); + g_value_set_int64( value, dbi_result_get_longlong( dbi_row->result, col_name ) ); break; case DBI_TYPE_DECIMAL: g_value_init( value, G_TYPE_DOUBLE ); @@ -998,9 +987,11 @@ conn_get_column_type_name( GncSqlConnection* conn, GType type, gint size ) if( dbi_conn->provider == GNC_DBI_PROVIDER_SQLITE ) { switch( type ) { case G_TYPE_INT: - case G_TYPE_INT64: return "integer"; break; + case G_TYPE_INT64: + return "bigint"; + break; case G_TYPE_DOUBLE: return "real"; break; @@ -1014,9 +1005,11 @@ conn_get_column_type_name( GncSqlConnection* conn, GType type, gint size ) } else if( dbi_conn->provider == GNC_DBI_PROVIDER_MYSQL ) { switch( type ) { case G_TYPE_INT: - case G_TYPE_INT64: return "integer"; break; + case G_TYPE_INT64: + return "bigint"; + break; case G_TYPE_DOUBLE: return "double"; break; @@ -1030,9 +1023,11 @@ conn_get_column_type_name( GncSqlConnection* conn, GType type, gint size ) } else if( dbi_conn->provider == GNC_DBI_PROVIDER_PGSQL ) { switch( type ) { case G_TYPE_INT: - case G_TYPE_INT64: return "integer"; break; + case G_TYPE_INT64: + return "int8"; + break; case G_TYPE_DOUBLE: return "double precision"; break; diff --git a/src/backend/sql/gnc-backend-sql.c b/src/backend/sql/gnc-backend-sql.c index 0e312545aa..521fc4dfae 100644 --- a/src/backend/sql/gnc-backend-sql.c +++ b/src/backend/sql/gnc-backend-sql.c @@ -2405,6 +2405,12 @@ gnc_sql_create_table( GncSqlBackend* be, const gchar* table_name, { gboolean ok; + g_return_val_if_fail( be != NULL, FALSE ); + g_return_val_if_fail( table_name != NULL, FALSE ); + g_return_val_if_fail( col_table != NULL, FALSE ); + + DEBUG( "Creating %s table\n", table_name ); + ok = do_create_table( be, table_name, col_table ); if( ok ) { ok = gnc_sql_set_table_version( be, table_name, table_version ); @@ -2416,6 +2422,10 @@ gboolean gnc_sql_create_temp_table( const GncSqlBackend* be, const gchar* table_name, const GncSqlColumnTableEntry* col_table ) { + g_return_val_if_fail( be != NULL, FALSE ); + g_return_val_if_fail( table_name != NULL, FALSE ); + g_return_val_if_fail( col_table != NULL, FALSE ); + return do_create_table( be, table_name, col_table ); } @@ -2454,6 +2464,36 @@ gnc_sql_get_table_version( const GncSqlBackend* be, const gchar* table_name ) return GPOINTER_TO_INT(g_hash_table_lookup( be->versions, table_name )); } +/* Create a temporary table, copy the data from the old table, delete the + old table, then rename the new one. */ +void +gnc_sql_upgrade_table( GncSqlBackend* be, const gchar* table_name, + const GncSqlColumnTableEntry* col_table ) +{ + gchar* sql; + gchar* temp_table_name; + GncSqlStatement* stmt; + + g_return_if_fail( be != NULL ); + g_return_if_fail( table_name != NULL ); + g_return_if_fail( col_table != NULL ); + + DEBUG( "Upgrading %s table\n", table_name ); + + temp_table_name = g_strdup_printf( "%s_new", table_name ); + gnc_sql_create_temp_table( be, temp_table_name, col_table ); + sql = g_strdup_printf( "INSERT INTO %s SELECT * FROM %s", + temp_table_name, table_name ); + (void)gnc_sql_execute_nonselect_sql( be, sql ); + + sql = g_strdup_printf( "DROP TABLE %s", table_name ); + (void)gnc_sql_execute_nonselect_sql( be, sql ); + + sql = g_strdup_printf( "ALTER TABLE %s RENAME TO %s", temp_table_name, table_name ); + (void)gnc_sql_execute_nonselect_sql( be, sql ); + g_free( temp_table_name ); +} + /* ================================================================= */ #define VERSION_TABLE_NAME "versions" #define MAX_TABLE_NAME_LEN 50 diff --git a/src/backend/sql/gnc-backend-sql.h b/src/backend/sql/gnc-backend-sql.h index a30c8e25f1..da43182786 100644 --- a/src/backend/sql/gnc-backend-sql.h +++ b/src/backend/sql/gnc-backend-sql.h @@ -678,6 +678,19 @@ gboolean gnc_sql_commit_standard_item( GncSqlBackend* be, QofInstance* inst, con */ gint64 gnc_sql_get_integer_value( const GValue* value ); +/** + * Upgrades a table to a new structure. The upgrade is done by creating a new table with + * the new structure, SELECTing the old data into the new table, deleting the old table, + * then renaming the new table. Therefore, this will only work if the new table structure + * is similar enough to the old table that the SELECT will work. + * + * @param be SQL backend + * @param table_name SQL table name + * @param col_table Column table + */ +void gnc_sql_upgrade_table( GncSqlBackend* be, const gchar* table_name, + const GncSqlColumnTableEntry* col_table ); + void _retrieve_guid_( gpointer pObject, gpointer pValue ); gpointer gnc_sql_compile_query( QofBackend* pBEnd, QofQuery* pQuery ); diff --git a/src/backend/sql/gnc-lots-sql.c b/src/backend/sql/gnc-lots-sql.c index 576e210699..7aeb1adef8 100644 --- a/src/backend/sql/gnc-lots-sql.c +++ b/src/backend/sql/gnc-lots-sql.c @@ -167,22 +167,8 @@ create_lots_tables( GncSqlBackend* be ) Create a temporary table, copy the data from the old table, delete the old table, then rename the new one. */ - gchar* sql; -#define TEMP_TABLE_NAME "lots_new" - GncSqlStatement* stmt; - - gnc_sql_create_temp_table( be, TEMP_TABLE_NAME, col_table ); - sql = g_strdup_printf( "INSERT INTO %s SELECT * FROM %s", - TEMP_TABLE_NAME, TABLE_NAME ); - (void)gnc_sql_execute_nonselect_sql( be, sql ); - - sql = g_strdup_printf( "DROP TABLE %s", TABLE_NAME ); - (void)gnc_sql_execute_nonselect_sql( be, sql ); - - sql = g_strdup_printf( "ALTER TABLE %s RENAME TO %s", - TEMP_TABLE_NAME, TABLE_NAME ); - (void)gnc_sql_execute_nonselect_sql( be, sql ); + gnc_sql_upgrade_table( be, TABLE_NAME, col_table ); gnc_sql_set_table_version( be, TABLE_NAME, TABLE_VERSION ); } } diff --git a/src/backend/sql/gnc-price-sql.c b/src/backend/sql/gnc-price-sql.c index 1588a476d0..cf61bd5c46 100644 --- a/src/backend/sql/gnc-price-sql.c +++ b/src/backend/sql/gnc-price-sql.c @@ -127,6 +127,10 @@ create_prices_tables( GncSqlBackend* be ) version = gnc_sql_get_table_version( be, TABLE_NAME ); if( version == 0 ) { gnc_sql_create_table( be, TABLE_NAME, TABLE_VERSION, col_table ); + } else if( version == 1 ) { + /* Upgrade 64 bit int handling */ + gnc_sql_upgrade_table( be, TABLE_NAME, col_table ); + gnc_sql_set_table_version( be, TABLE_NAME, TABLE_VERSION ); } } diff --git a/src/backend/sql/gnc-slots-sql.c b/src/backend/sql/gnc-slots-sql.c index e59002572f..2a73ab309a 100644 --- a/src/backend/sql/gnc-slots-sql.c +++ b/src/backend/sql/gnc-slots-sql.c @@ -40,7 +40,7 @@ static QofLogModule log_module = G_LOG_DOMAIN; #define TABLE_NAME "slots" -#define TABLE_VERSION 1 +#define TABLE_VERSION 2 typedef struct { GncSqlBackend* be; @@ -560,6 +560,10 @@ create_slots_tables( GncSqlBackend* be ) PERR( "Unable to create index: %s\n", error->message ); } #endif + } else if( version == 1 ) { + /* Upgrade 64-bit int values to proper definition */ + gnc_sql_upgrade_table( be, TABLE_NAME, col_table ); + gnc_sql_set_table_version( be, TABLE_NAME, TABLE_VERSION ); } } diff --git a/src/backend/sql/gnc-transaction-sql.c b/src/backend/sql/gnc-transaction-sql.c index 24c2a49986..ce0194403b 100644 --- a/src/backend/sql/gnc-transaction-sql.c +++ b/src/backend/sql/gnc-transaction-sql.c @@ -506,11 +506,19 @@ create_transaction_tables( GncSqlBackend* be ) version = gnc_sql_get_table_version( be, TRANSACTION_TABLE ); if( version == 0 ) { gnc_sql_create_table( be, TRANSACTION_TABLE, TX_TABLE_VERSION, tx_col_table ); + } else if( version == 1 ) { + /* Upgrade 64 bit int handling */ + gnc_sql_upgrade_table( be, TRANSACTION_TABLE, tx_col_table ); + gnc_sql_set_table_version( be, TRANSACTION_TABLE, TX_TABLE_VERSION ); } version = gnc_sql_get_table_version( be, SPLIT_TABLE ); if( version == 0 ) { gnc_sql_create_table( be, SPLIT_TABLE, SPLIT_TABLE_VERSION, split_col_table ); + } else if( version == 1 ) { + /* Upgrade 64 bit int handling */ + gnc_sql_upgrade_table( be, SPLIT_TABLE, split_col_table ); + gnc_sql_set_table_version( be, SPLIT_TABLE, SPLIT_TABLE_VERSION ); } } /* ================================================================= */ diff --git a/src/business/business-core/sql/gnc-bill-term-sql.c b/src/business/business-core/sql/gnc-bill-term-sql.c index 2cdc930844..d40bd34cb4 100644 --- a/src/business/business-core/sql/gnc-bill-term-sql.c +++ b/src/business/business-core/sql/gnc-bill-term-sql.c @@ -182,7 +182,11 @@ create_billterm_tables( GncSqlBackend* be ) version = gnc_sql_get_table_version( be, TABLE_NAME ); if( version == 0 ) { gnc_sql_create_table( be, TABLE_NAME, TABLE_VERSION, col_table ); - } + } else if( version == 1 ) { + /* Upgrade 64 bit int handling */ + gnc_sql_upgrade_table( be, TABLE_NAME, col_table ); + gnc_sql_set_table_version( be, TABLE_NAME, TABLE_VERSION ); + } } /* ================================================================= */ diff --git a/src/business/business-core/sql/gnc-customer-sql.c b/src/business/business-core/sql/gnc-customer-sql.c index 2894334209..dead0d655d 100644 --- a/src/business/business-core/sql/gnc-customer-sql.c +++ b/src/business/business-core/sql/gnc-customer-sql.c @@ -143,6 +143,10 @@ create_customer_tables( GncSqlBackend* be ) version = gnc_sql_get_table_version( be, TABLE_NAME ); if( version == 0 ) { gnc_sql_create_table( be, TABLE_NAME, TABLE_VERSION, col_table ); + } else if( version == 1 ) { + /* Upgrade 64 bit int handling */ + gnc_sql_upgrade_table( be, TABLE_NAME, col_table ); + gnc_sql_set_table_version( be, TABLE_NAME, TABLE_VERSION ); } } diff --git a/src/business/business-core/sql/gnc-employee-sql.c b/src/business/business-core/sql/gnc-employee-sql.c index f9046e2464..a9f6946a8d 100644 --- a/src/business/business-core/sql/gnc-employee-sql.c +++ b/src/business/business-core/sql/gnc-employee-sql.c @@ -140,6 +140,10 @@ create_employee_tables( GncSqlBackend* be ) version = gnc_sql_get_table_version( be, TABLE_NAME ); if( version == 0 ) { gnc_sql_create_table( be, TABLE_NAME, TABLE_VERSION, col_table ); + } else if( version == 1 ) { + /* Upgrade 64 bit int handling */ + gnc_sql_upgrade_table( be, TABLE_NAME, col_table ); + gnc_sql_set_table_version( be, TABLE_NAME, TABLE_VERSION ); } } diff --git a/src/business/business-core/sql/gnc-entry-sql.c b/src/business/business-core/sql/gnc-entry-sql.c index 65ee8e5cfa..3140f1c2bd 100644 --- a/src/business/business-core/sql/gnc-entry-sql.c +++ b/src/business/business-core/sql/gnc-entry-sql.c @@ -163,6 +163,10 @@ create_entry_tables( GncSqlBackend* be ) version = gnc_sql_get_table_version( be, TABLE_NAME ); if( version == 0 ) { gnc_sql_create_table( be, TABLE_NAME, TABLE_VERSION, col_table ); + } else if( version == 1 ) { + /* Upgrade 64 bit int handling */ + gnc_sql_upgrade_table( be, TABLE_NAME, col_table ); + gnc_sql_set_table_version( be, TABLE_NAME, TABLE_VERSION ); } } diff --git a/src/business/business-core/sql/gnc-invoice-sql.c b/src/business/business-core/sql/gnc-invoice-sql.c index 8bfc7e7a91..02b323923b 100644 --- a/src/business/business-core/sql/gnc-invoice-sql.c +++ b/src/business/business-core/sql/gnc-invoice-sql.c @@ -147,6 +147,10 @@ create_invoice_tables( GncSqlBackend* be ) version = gnc_sql_get_table_version( be, TABLE_NAME ); if( version == 0 ) { gnc_sql_create_table( be, TABLE_NAME, TABLE_VERSION, col_table ); + } else if( version == 1 ) { + /* Upgrade 64 bit int handling */ + gnc_sql_upgrade_table( be, TABLE_NAME, col_table ); + gnc_sql_set_table_version( be, TABLE_NAME, TABLE_VERSION ); } } diff --git a/src/business/business-core/sql/gnc-tax-table-sql.c b/src/business/business-core/sql/gnc-tax-table-sql.c index 1c1aca6924..e108cfd844 100644 --- a/src/business/business-core/sql/gnc-tax-table-sql.c +++ b/src/business/business-core/sql/gnc-tax-table-sql.c @@ -259,11 +259,19 @@ create_taxtable_tables( GncSqlBackend* be ) version = gnc_sql_get_table_version( be, TT_TABLE_NAME ); if( version == 0 ) { gnc_sql_create_table( be, TT_TABLE_NAME, TT_TABLE_VERSION, tt_col_table ); + } else if( version == 1 ) { + /* Upgrade 64 bit int handling */ + gnc_sql_upgrade_table( be, TT_TABLE_NAME, tt_col_table ); + gnc_sql_set_table_version( be, TT_TABLE_NAME, TT_TABLE_VERSION ); } version = gnc_sql_get_table_version( be, TTENTRIES_TABLE_NAME ); if( version == 0 ) { gnc_sql_create_table( be, TTENTRIES_TABLE_NAME, TTENTRIES_TABLE_VERSION, ttentries_col_table ); + } else if( version == 1 ) { + /* Upgrade 64 bit int handling */ + gnc_sql_upgrade_table( be, TTENTRIES_TABLE_NAME, ttentries_col_table ); + gnc_sql_set_table_version( be, TTENTRIES_TABLE_NAME, TTENTRIES_TABLE_VERSION ); } }