Commit 1d381de4 authored by Murray Cumming's avatar Murray Cumming

libglom: Use escape_sql_id() for column add/crop/change.

	* glom/libglom/connectionpool.cc: add_column(), drop_column(),

	* glom/libglom/connectionpool_backends/backend.[h|cc]:
	* glom/libglom/connectionpool_backends/postgres.cc
	* glom/libglom/connectionpool_backends/sqlite.[h|cc]:
	add_column(), drop_column(): Return a bool to indicate failure.
	change_columns(): Report false return values from these.

	* Makefile_tests.am
	* tests/test_selfhosting_new_then_change_columns.cc: Add a simple
	test, though we do not yet test that the expected change really
	happened.
parent 90ff2d42
2011-11-08 Murray Cumming <murrayc@murrayc.com>
libglom: Use escape_sql_id() for column add/crop/change.
* glom/libglom/connectionpool.cc: add_column(), drop_column(),
* glom/libglom/connectionpool_backends/backend.[h|cc]:
* glom/libglom/connectionpool_backends/postgres.cc
* glom/libglom/connectionpool_backends/sqlite.[h|cc]:
add_column(), drop_column(): Return a bool to indicate failure.
change_columns(): Report false return values from these.
* Makefile_tests.am
* tests/test_selfhosting_new_then_change_columns.cc: Add a simple
test, though we do not yet test that the expected change really
happened.
2011-11-08 Murray Cumming <murrayc@murrayc.com>
libglom: Add escape_sql_id() and use it for table add/drop/rename.
......
......@@ -32,6 +32,7 @@ check_PROGRAMS = \
tests/test_selfhosting_new_then_backup_restore \
tests/test_selfhosting_new_then_get_privs \
tests/test_selfhosting_new_then_alter_table \
tests/test_selfhosting_new_then_change_columns \
tests/test_selfhosting_sqlinjection \
tests/import/test_parsing \
tests/import/test_signals
......@@ -52,6 +53,7 @@ TESTS = tests/test_document_load \
tests/test_selfhosting_new_then_image \
tests/test_selfhosting_new_then_get_privs \
tests/test_selfhosting_new_then_alter_table \
tests/test_selfhosting_new_then_change_columns \
tests/test_selfhosting_sqlinjection \
tests/import/test_parsing \
tests/import/test_signals
......@@ -166,6 +168,10 @@ tests_test_selfhosting_new_then_alter_table_SOURCES = tests/test_selfhosting_new
tests_test_selfhosting_new_then_alter_table_LDADD = $(tests_ldadd)
tests_test_selfhosting_new_then_alter_table_CPPFLAGS = $(tests_cppflags)
tests_test_selfhosting_new_then_change_columns_SOURCES = tests/test_selfhosting_new_then_change_columns.cc $(sources_test_selfhosting_utils)
tests_test_selfhosting_new_then_change_columns_LDADD = $(tests_ldadd)
tests_test_selfhosting_new_then_change_columns_CPPFLAGS = $(tests_cppflags)
tests_test_selfhosting_sqlinjection_SOURCES = tests/test_selfhosting_sqlinjection.cc $(sources_test_selfhosting_utils)
tests_test_selfhosting_sqlinjection_LDADD = $(tests_ldadd)
tests_test_selfhosting_sqlinjection_CPPFLAGS = $(tests_cppflags)
......
......@@ -676,9 +676,9 @@ bool ConnectionPool::add_column(const Glib::ustring& table_name, const sharedptr
try
{
m_backend->add_column(m_refGdaConnection, table_name, field);
const bool result = m_backend->add_column(m_refGdaConnection, table_name, field);
m_refGdaConnection->update_meta_store_table(table_name, m_backend->get_public_schema_name());
return true;
return result;
}
catch(const Glib::Error& ex)
{
......@@ -701,9 +701,9 @@ bool ConnectionPool::drop_column(const Glib::ustring& table_name, const Glib::us
try
{
m_backend->drop_column(m_refGdaConnection, table_name, field_name);
const bool result = m_backend->drop_column(m_refGdaConnection, table_name, field_name);
m_refGdaConnection->update_meta_store_table(table_name, m_backend->get_public_schema_name());
return true;
return result;
}
catch(const Glib::Error& ex)
{
......
......@@ -65,7 +65,7 @@ bool Backend::set_network_shared(const SlotProgress& /* slot_progress */, bool /
return true; //Success at doing nothing.
}
void Backend::add_column(const Glib::RefPtr<Gnome::Gda::Connection>& connection, const Glib::ustring& table_name, const sharedptr<const Field>& field)
bool Backend::add_column(const Glib::RefPtr<Gnome::Gda::Connection>& connection, const Glib::ustring& table_name, const sharedptr<const Field>& field)
{
Glib::RefPtr<Gnome::Gda::ServerProvider> provider = connection->get_provider();
Glib::RefPtr<Gnome::Gda::ServerOperation> operation = provider->create_operation(connection, Gnome::Gda::SERVER_OPERATION_ADD_COLUMN);
......@@ -77,10 +77,10 @@ void Backend::add_column(const Glib::RefPtr<Gnome::Gda::Connection>& connection,
operation->set_value_at("/COLUMN_DEF_P/COLUMN_PKEY", field->get_primary_key());
operation->set_value_at("/COLUMN_DEF_P/COLUMN_UNIQUE", field->get_unique_key());
provider->perform_operation(connection, operation);
return provider->perform_operation(connection, operation);
}
void Backend::drop_column(const Glib::RefPtr<Gnome::Gda::Connection>& connection, const Glib::ustring& table_name, const Glib::ustring& field_name)
bool Backend::drop_column(const Glib::RefPtr<Gnome::Gda::Connection>& connection, const Glib::ustring& table_name, const Glib::ustring& field_name)
{
Glib::RefPtr<Gnome::Gda::ServerProvider> provider = connection->get_provider();
Glib::RefPtr<Gnome::Gda::ServerOperation> operation = provider->create_operation(connection, Gnome::Gda::SERVER_OPERATION_DROP_COLUMN);
......@@ -88,7 +88,7 @@ void Backend::drop_column(const Glib::RefPtr<Gnome::Gda::Connection>& connection
//TODO: Quote table name and column name?
operation->set_value_at("/COLUMN_DESC_P/TABLE_NAME", table_name);
operation->set_value_at("/COLUMN_DESC_P/COLUMN_NAME", field_name);
provider->perform_operation(connection, operation);
return provider->perform_operation(connection, operation);
}
void Backend::set_database_directory_uri(const std::string& directory_uri)
......
......@@ -177,11 +177,11 @@ protected:
/** @throws Glib::Error (from libgdamm)
*/
virtual void add_column(const Glib::RefPtr<Gnome::Gda::Connection>& connection, const Glib::ustring& table_name, const sharedptr<const Field>& field);
virtual bool add_column(const Glib::RefPtr<Gnome::Gda::Connection>& connection, const Glib::ustring& table_name, const sharedptr<const Field>& field);
/** @throws Glib::Error (from libgdamm)
*/
virtual void drop_column(const Glib::RefPtr<Gnome::Gda::Connection>& connection, const Glib::ustring& table_name, const Glib::ustring& field_name);
virtual bool drop_column(const Glib::RefPtr<Gnome::Gda::Connection>& connection, const Glib::ustring& table_name, const Glib::ustring& field_name);
virtual bool change_columns(const Glib::RefPtr<Gnome::Gda::Connection>& connection, const Glib::ustring& table_name, const type_vec_const_fields& old_fields, const type_vec_const_fields& new_fields) throw() = 0;
......
......@@ -24,6 +24,7 @@
#include <libglom/connectionpool_backends/postgres.h>
#include <libglom/spawn_with_feedback.h>
#include <libglom/utils.h>
#include <libglom/db_utils.h>
#include <libgdamm/config.h>
#include <giomm/file.h>
#include <glibmm/convert.h>
......@@ -176,10 +177,15 @@ bool Postgres::change_columns(const Glib::RefPtr<Gnome::Gda::Connection>& connec
// primary key columns.
temp_field->set_primary_key(false);
add_column(connection, table_name, temp_field);
const bool added = add_column(connection, table_name, temp_field);
if(!added)
{
std::cerr << G_STRFUNC << ": add_column() failed." << std::endl;
//TODO: Stop the transaction and return?
}
Glib::ustring conversion_command;
const Glib::ustring field_name_old_quoted = "\"" + old_fields[i]->get_name() + "\"";
const Glib::ustring field_name_old_quoted = DbUtils::escape_sql_id(old_fields[i]->get_name());
const Field::glom_field_type old_field_type = old_fields[i]->get_glom_type();
if(Field::get_conversion_possible(old_fields[i]->get_glom_type(), new_fields[i]->get_glom_type()))
......@@ -263,7 +269,8 @@ bool Postgres::change_columns(const Glib::RefPtr<Gnome::Gda::Connection>& connec
}
}
connection->statement_execute_non_select("UPDATE \"" + table_name + "\" SET \"" + TEMP_COLUMN_NAME + "\" = " + conversion_command);
//TODO: Use SqlBuilder here?
connection->statement_execute_non_select("UPDATE " + DbUtils::escape_sql_id(table_name) + " SET " + DbUtils::escape_sql_id(TEMP_COLUMN_NAME) + " = " + conversion_command);
}
else
{
......@@ -272,12 +279,12 @@ bool Postgres::change_columns(const Glib::RefPtr<Gnome::Gda::Connection>& connec
drop_column(connection, table_name, old_fields[i]->get_name());
connection->statement_execute_non_select("ALTER TABLE \"" + table_name + "\" RENAME COLUMN \"" + TEMP_COLUMN_NAME + "\" TO \"" + new_fields[i]->get_name() + "\"");
connection->statement_execute_non_select("ALTER TABLE " + DbUtils::escape_sql_id(table_name) + " RENAME COLUMN " + DbUtils::escape_sql_id(TEMP_COLUMN_NAME) + " TO " + DbUtils::escape_sql_id(new_fields[i]->get_name()));
// Read primary key constraint
if(new_fields[i]->get_primary_key())
{
connection->statement_execute_non_select("ALTER TABLE \"" + table_name + "\" ADD PRIMARY KEY (\"" + new_fields[i]->get_name() + "\")");
connection->statement_execute_non_select("ALTER TABLE " + DbUtils::escape_sql_id(table_name) + " ADD PRIMARY KEY (" + DbUtils::escape_sql_id(new_fields[i]->get_name()) + ")");
}
}
else
......@@ -298,19 +305,19 @@ bool Postgres::change_columns(const Glib::RefPtr<Gnome::Gda::Connection>& connec
primary_key_was_set = true;
// Primary key was added
connection->statement_execute_non_select("ALTER TABLE \"" + table_name + "\" ADD PRIMARY KEY (\"" + old_fields[i]->get_name() + "\")");
connection->statement_execute_non_select("ALTER TABLE " + DbUtils::escape_sql_id(table_name) + " ADD PRIMARY KEY (" + DbUtils::escape_sql_id(old_fields[i]->get_name()) + ")");
// Remove unique key constraint, because this is already implied in
// the field being primary key.
if(old_fields[i]->get_unique_key())
connection->statement_execute_non_select("ALTER TABLE \"" + table_name + "\" DROP CONSTRAINT \"" + old_fields[i]->get_name() + "_key");
connection->statement_execute_non_select("ALTER TABLE " + DbUtils::escape_sql_id(table_name) + " DROP CONSTRAINT " + DbUtils::escape_sql_id(old_fields[i]->get_name() + "_key"));
}
else
{
primary_key_was_unset = true;
// Primary key was removed
connection->statement_execute_non_select("ALTER TABLE \"" + table_name + "\" DROP CONSTRAINT \"" + table_name + "_pkey\"");
connection->statement_execute_non_select("ALTER TABLE " + DbUtils::escape_sql_id(table_name) + " DROP CONSTRAINT " + DbUtils::escape_sql_id(table_name + "_pkey"));
}
}
......@@ -321,11 +328,11 @@ bool Postgres::change_columns(const Glib::RefPtr<Gnome::Gda::Connection>& connec
// to do that separately if we already made it a primary key
if(!primary_key_was_set && new_fields[i]->get_unique_key())
{
connection->statement_execute_non_select("ALTER TABLE \"" + table_name + "\" ADD CONSTRAINT \"" + old_fields[i]->get_name() + "_key\" UNIQUE (\"" + old_fields[i]->get_name() + "\")");
connection->statement_execute_non_select("ALTER TABLE " + DbUtils::escape_sql_id(table_name) + " ADD CONSTRAINT " + DbUtils::escape_sql_id(old_fields[i]->get_name() + "_key") + " UNIQUE (" + DbUtils::escape_sql_id(old_fields[i]->get_name()) + ")");
}
else if(!primary_key_was_unset && !new_fields[i]->get_unique_key() && !new_fields[i]->get_primary_key())
{
connection->statement_execute_non_select("ALTER TABLE \"" + table_name + "\" DROP CONSTRAINT \"" + old_fields[i]->get_name() + "_key\"");
connection->statement_execute_non_select("ALTER TABLE " + DbUtils::escape_sql_id(table_name) + " DROP CONSTRAINT " + DbUtils::escape_sql_id(old_fields[i]->get_name() + "_key"));
}
}
......@@ -333,13 +340,13 @@ bool Postgres::change_columns(const Glib::RefPtr<Gnome::Gda::Connection>& connec
{
if(old_fields[i]->get_default_value() != new_fields[i]->get_default_value())
{
connection->statement_execute_non_select("ALTER TABLE \"" + table_name + "\" ALTER COLUMN \"" + old_fields[i]->get_name() + "\" SET DEFAULT " + new_fields[i]->sql(new_fields[i]->get_default_value(), connection));
connection->statement_execute_non_select("ALTER TABLE " + DbUtils::escape_sql_id(table_name) + " ALTER COLUMN " + DbUtils::escape_sql_id(old_fields[i]->get_name()) + " SET DEFAULT " + new_fields[i]->sql(new_fields[i]->get_default_value(), connection));
}
}
if(old_fields[i]->get_name() != new_fields[i]->get_name())
{
connection->statement_execute_non_select("ALTER TABLE \"" + table_name + "\" RENAME COLUMN \"" + old_fields[i]->get_name() + "\" TO \"" + new_fields[i]->get_name() + "\"");
connection->statement_execute_non_select("ALTER TABLE " + DbUtils::escape_sql_id(table_name) + " RENAME COLUMN " + DbUtils::escape_sql_id(old_fields[i]->get_name()) + " TO " + DbUtils::escape_sql_id(new_fields[i]->get_name()));
}
}
}
......
......@@ -21,6 +21,7 @@
#include <libglom/libglom_config.h>
#include <libglom/connectionpool_backends/sqlite.h>
#include <libglom/utils.h>
#include <libglom/db_utils.h>
#include <giomm/file.h>
#include <libgdamm/metastore.h>
......@@ -204,35 +205,35 @@ bool Sqlite::recreate_table(const Glib::RefPtr<Gnome::Gda::Connection>& connecti
{
case Field::TYPE_TEXT:
if(column->gtype == G_TYPE_BOOLEAN)
trans_fields += Glib::ustring("(CASE WHEN \"") + column->column_name + "\" = 1 THEN 'true' "
"WHEN \"" + column->column_name + "\" = 0 THEN 'false' "
"WHEN \"" + column->column_name + "\" IS NULL THEN 'false' END)";
trans_fields += "(CASE WHEN "+ DbUtils::escape_sql_id(column->column_name) + " = 1 THEN 'true' "
"WHEN " + DbUtils::escape_sql_id(column->column_name) + " = 0 THEN 'false' "
"WHEN " + DbUtils::escape_sql_id(column->column_name) + " IS NULL THEN 'false' END)";
else if(column->gtype == GDA_TYPE_BLOB)
trans_fields += "''";
else
// Make sure we don't insert NULL strings, as we ignore that concept in Glom.
trans_fields += Glib::ustring("(CASE WHEN \"") + column->column_name + "\" IS NULL THEN '' "
"WHEN \"" + column->column_name + "\" IS NOT NULL THEN \"" + column->column_name + "\" END)";
trans_fields += "(CASE WHEN "+ DbUtils::escape_sql_id(column->column_name) + " IS NULL THEN '' "
"WHEN " + DbUtils::escape_sql_id(column->column_name) + " IS NOT NULL THEN " + DbUtils::escape_sql_id(column->column_name) + " END)";
break;
case Field::TYPE_NUMERIC:
if(column->gtype == G_TYPE_BOOLEAN)
trans_fields += Glib::ustring("(CASE WHEN \"") + column->column_name + "\" = 0 THEN 0 "
"WHEN \"" + column->column_name + "\" != 0 THEN 1 "
"WHEN \"" + column->column_name + "\" IS NULL THEN 0 END)";
trans_fields += "(CASE WHEN "+ DbUtils::escape_sql_id(column->column_name) + " = 0 THEN 0 "
"WHEN " + DbUtils::escape_sql_id(column->column_name) + " != 0 THEN 1 "
"WHEN " + DbUtils::escape_sql_id(column->column_name) + " IS NULL THEN 0 END)";
else if(column->gtype == GDA_TYPE_BLOB || column->gtype == G_TYPE_DATE || column->gtype == GDA_TYPE_TIME)
trans_fields += '0';
else
trans_fields += Glib::ustring("CAST(") + column->column_name + " AS real)";
trans_fields += Glib::ustring("CAST(")+ DbUtils::escape_sql_id(column->column_name) + " AS real)";
break;
case Field::TYPE_BOOLEAN:
if(column->gtype == G_TYPE_STRING)
trans_fields += Glib::ustring("(CASE WHEN \"") + column->column_name + "\" = 'true' THEN 1 "
"WHEN \"" + column->column_name + "\" = 'false' THEN 0 "
"WHEN \"" + column->column_name + "\" IS NULL THEN 0 END)";
trans_fields += "(CASE WHEN "+ DbUtils::escape_sql_id(column->column_name) + " = 'true' THEN 1 "
"WHEN " + DbUtils::escape_sql_id(column->column_name) + " = 'false' THEN 0 "
"WHEN " + DbUtils::escape_sql_id(column->column_name) + " IS NULL THEN 0 END)";
else if(column->gtype == G_TYPE_DOUBLE)
trans_fields += Glib::ustring("(CASE WHEN \"") + column->column_name + "\" = 0 THEN 0 "
"WHEN \"" + column->column_name + "\" != 0 THEN 1 "
"WHEN \"" + column->column_name + "\" IS NULL THEN 0 END)";
trans_fields += "(CASE WHEN "+ DbUtils::escape_sql_id(column->column_name) + " = 0 THEN 0 "
"WHEN " + DbUtils::escape_sql_id(column->column_name) + " != 0 THEN 1 "
"WHEN " + DbUtils::escape_sql_id(column->column_name) + " IS NULL THEN 0 END)";
else if(column->gtype == G_TYPE_BOOLEAN)
trans_fields += column->column_name;
else
......@@ -242,13 +243,13 @@ bool Sqlite::recreate_table(const Glib::RefPtr<Gnome::Gda::Connection>& connecti
if(column->gtype == G_TYPE_BOOLEAN || column->gtype == GDA_TYPE_BLOB || column->gtype == G_TYPE_DOUBLE)
trans_fields += "NULL";
else
trans_fields += Glib::ustring("date(") + column->column_name + ')';
trans_fields += Glib::ustring("date(")+ DbUtils::escape_sql_id(column->column_name) + ')';
break;
case Field::TYPE_TIME:
if(column->gtype == G_TYPE_BOOLEAN || column->gtype == GDA_TYPE_BLOB || column->gtype == G_TYPE_DOUBLE)
trans_fields += "NULL";
else
trans_fields += Glib::ustring("time(") + column->column_name + ')';
trans_fields += Glib::ustring("time(")+ DbUtils::escape_sql_id(column->column_name) + ')';
break;
case Field::TYPE_IMAGE:
if(column->gtype == GDA_TYPE_BLOB)
......@@ -282,7 +283,7 @@ bool Sqlite::recreate_table(const Glib::RefPtr<Gnome::Gda::Connection>& connecti
if(!trans_fields.empty())
trans_fields += ',';
Gnome::Gda::Value default_value = field->get_default_value();
const Gnome::Gda::Value default_value = field->get_default_value();
if(default_value.get_value_type() != G_TYPE_NONE && !default_value.is_null())
trans_fields += field->sql(default_value, connection);
else
......@@ -324,9 +325,11 @@ bool Sqlite::recreate_table(const Glib::RefPtr<Gnome::Gda::Connection>& connecti
if(!trans_fields.empty())
{
connection->statement_execute_non_select(Glib::ustring("INSERT INTO \"") + TEMPORARY_TABLE_NAME + "\" SELECT " + trans_fields + " FROM \"" + table_name + "\"");
connection->statement_execute_non_select("DROP TABLE " + table_name);
connection->statement_execute_non_select(Glib::ustring("ALTER TABLE \"") + TEMPORARY_TABLE_NAME + "\" RENAME TO \"" + table_name + "\"");
const Glib::ustring query_insert = "INSERT INTO " + DbUtils::escape_sql_id(TEMPORARY_TABLE_NAME) + " SELECT " + trans_fields + " FROM " + DbUtils::escape_sql_id(table_name);
//std::cout << "debug: query_insert=" << query_insert << std::endl;
connection->statement_execute_non_select(query_insert);
connection->statement_execute_non_select("DROP TABLE " + DbUtils::escape_sql_id(table_name));
connection->statement_execute_non_select("ALTER TABLE " + DbUtils::escape_sql_id(TEMPORARY_TABLE_NAME) + " RENAME TO " + DbUtils::escape_sql_id(table_name));
connection->commit_transaction(TRANSACTION_NAME);
......@@ -351,23 +354,23 @@ bool Sqlite::recreate_table(const Glib::RefPtr<Gnome::Gda::Connection>& connecti
return false;
}
void Sqlite::add_column(const Glib::RefPtr<Gnome::Gda::Connection>& connection, const Glib::ustring& table_name, const sharedptr<const Field>& field)
bool Sqlite::add_column(const Glib::RefPtr<Gnome::Gda::Connection>& connection, const Glib::ustring& table_name, const sharedptr<const Field>& field)
{
// Sqlite does not support adding primary key columns. So recreate the table
// in that case.
if(!field->get_primary_key())
{
Backend::add_column(connection, table_name, field);
return Backend::add_column(connection, table_name, field);
}
else
{
recreate_table(connection, table_name, type_vec_strings(), type_vec_const_fields(1, field), type_mapFieldChanges());
return recreate_table(connection, table_name, type_vec_strings(), type_vec_const_fields(1, field), type_mapFieldChanges());
}
}
void Sqlite::drop_column(const Glib::RefPtr<Gnome::Gda::Connection>& connection, const Glib::ustring& table_name, const Glib::ustring& field_name)
bool Sqlite::drop_column(const Glib::RefPtr<Gnome::Gda::Connection>& connection, const Glib::ustring& table_name, const Glib::ustring& field_name)
{
recreate_table(connection, table_name, type_vec_strings(1, field_name), type_vec_const_fields(), type_mapFieldChanges());
return recreate_table(connection, table_name, type_vec_strings(1, field_name), type_vec_const_fields(), type_mapFieldChanges());
}
bool Sqlite::change_columns(const Glib::RefPtr<Gnome::Gda::Connection>& connection, const Glib::ustring& table_name, const type_vec_const_fields& old_fields, const type_vec_const_fields& new_fields) throw()
......
......@@ -52,8 +52,8 @@ private:
bool recreate_table(const Glib::RefPtr<Gnome::Gda::Connection>& connection, const Glib::ustring& table_name, const type_vec_strings& fields_removed, const type_vec_const_fields& fields_added, const type_mapFieldChanges& fields_changed) throw();
virtual void add_column(const Glib::RefPtr<Gnome::Gda::Connection>& connection, const Glib::ustring& table_name, const sharedptr<const Field>& field);
virtual void drop_column(const Glib::RefPtr<Gnome::Gda::Connection>& connection, const Glib::ustring& table_name, const Glib::ustring& field_name);
virtual bool add_column(const Glib::RefPtr<Gnome::Gda::Connection>& connection, const Glib::ustring& table_name, const sharedptr<const Field>& field);
virtual bool drop_column(const Glib::RefPtr<Gnome::Gda::Connection>& connection, const Glib::ustring& table_name, const Glib::ustring& field_name);
virtual bool change_columns(const Glib::RefPtr<Gnome::Gda::Connection>& connection, const Glib::ustring& table_name, const type_vec_const_fields& old_fields, const type_vec_const_fields& new_fields) throw();
virtual Glib::RefPtr<Gnome::Gda::Connection> connect(const Glib::ustring& database, const Glib::ustring& username, const Glib::ustring& password);
......
/* Glom
*
* Copyright (C) 2010 Openismus GmbH
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program; if not, write to the
71 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "tests/test_selfhosting_utils.h"
#include <libglom/init.h>
#include <libglom/utils.h>
#include <libglom/db_utils.h>
#include <libglom/connectionpool.h>
#include <glibmm/fileutils.h>
#include <glibmm/miscutils.h>
#include <libgda/gda-blob-op.h>
#include <glib.h> //For g_assert()
#include <iostream>
#include <cstdlib> //For EXIT_SUCCESS and EXIT_FAILURE
#include <cstring> //For memcmp().
static bool test(Glom::Document::HostingMode hosting_mode)
{
Glom::Document document;
const bool recreated =
test_create_and_selfhost_from_example("example_smallbusiness.glom", document, hosting_mode);
if(!recreated)
{
std::cerr << "Recreation failed." << std::endl;
return false;
}
const Glib::ustring table_name = "contacts";
const Glom::sharedptr<const Glom::Field> field = document.get_field(table_name, "date_of_birth");
if(!field)
{
std::cerr << "Failure: Could not get field." << std::endl;
return false;
}
Glom::sharedptr<Glom::Field> field_new = Glom::glom_sharedptr_clone(field);
if(!field_new)
{
std::cerr << "Failure: field_new is null." << std::endl;
return false;
}
field_new->set_glom_type(Glom::Field::TYPE_TEXT);
Glom::ConnectionPool* connection_pool = Glom::ConnectionPool::get_instance();
if(!connection_pool)
{
std::cerr << "Failure: connection_pool is null." << std::endl;
return false;
}
//Test that change_column() does not fail horribly:
//TODO: Start with some data that can be converted meaningfully,
//and check that the result is as expected:
try
{
const bool test = connection_pool->change_column(table_name, field, field_new);
if(!test)
{
std::cerr << "Failure: change_column() failed." << std::endl;
return false;
}
}
catch(const Glib::Error& ex)
{
std::cerr << "Failure: change_column() threw an exception: " << ex.what() << std::endl;
return false;
}
//Try another change:
field_new->set_glom_type(Glom::Field::TYPE_NUMERIC);
try
{
const bool test = connection_pool->change_column(table_name, field, field_new);
if(!test)
{
std::cerr << "Failure: change_column() failed." << std::endl;
return false;
}
}
catch(const Glib::Error& ex)
{
std::cerr << "Failure: change_column() threw an exception: " << ex.what() << std::endl;
return false;
}
//Try another change:
field_new->set_name("somenewfieldname");
try
{
const bool test = connection_pool->change_column(table_name, field, field_new);
if(!test)
{
std::cerr << "Failure: change_column() failed." << std::endl;
return false;
}
}
catch(const Glib::Error& ex)
{
std::cerr << "Failure: change_column() threw an exception: " << ex.what() << std::endl;
return false;
}
test_selfhosting_cleanup();
return true;
}
int main()
{
Glom::libglom_init();
if(!test(Glom::Document::HOSTING_MODE_POSTGRES_SELF))
{
std::cerr << "Failed with PostgreSQL" << std::endl;
test_selfhosting_cleanup();
return EXIT_FAILURE;
}
if(!test(Glom::Document::HOSTING_MODE_SQLITE))
{
std::cerr << "Failed with SQLite" << std::endl;
test_selfhosting_cleanup();
return EXIT_FAILURE;
}
Glom::libglom_deinit();
return EXIT_SUCCESS;
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment