aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2013-09-16 07:07:33 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2013-09-16 07:07:33 +0200
commit5a5bf7fc225ac225dbc03df55f6be7c56cb419aa (patch)
treedba57ca78b11572bfa51aaa2a430d7002e1e9563
parent04ef42158ed426cffdf4dfd72944bc6f89ec6efb (diff)
Implement logical column drop for SQLite
-rw-r--r--odb/relational/sqlite/schema.cxx107
-rw-r--r--odb/semantics/relational/column.hxx7
2 files changed, 102 insertions, 12 deletions
diff --git a/odb/relational/sqlite/schema.cxx b/odb/relational/sqlite/schema.cxx
index ac9a753..96eaf68 100644
--- a/odb/relational/sqlite/schema.cxx
+++ b/odb/relational/sqlite/schema.cxx
@@ -19,6 +19,45 @@ namespace relational
// Drop.
//
+ struct drop_column: trav_rel::drop_column, relational::common
+ {
+ drop_column (relational::common const& c)
+ : relational::common (c), first_ (true) {}
+
+ virtual void
+ traverse (sema_rel::drop_column& dc)
+ {
+ // SQLite does not support dropping columns. If this column is
+ // not NULLable, then there is nothing we can do. Otherwise, do
+ // a logical DROP by setting all the values to NULL.
+ //
+ sema_rel::column& c (find<sema_rel::column> (dc));
+
+ if (!c.null ())
+ {
+ cerr << "error: SQLite does not support dropping of columns" <<
+ endl;
+ cerr << "info: first dropped column is '" << dc.name () <<
+ "' in table '" << dc.table ().name () << "'" << endl;
+ cerr << "info: could have perform logical drop if the column " <<
+ "allowed NULL values" << endl;
+ throw operation_failed ();
+ }
+
+ if (first_)
+ first_ = false;
+ else
+ os << "," << endl
+ << " ";
+
+ os << quote_id (dc.name ()) << " = NULL";
+ }
+
+ private:
+ bool first_;
+ };
+ // Not registered as an override.
+
struct drop_index: relational::drop_index, context
{
drop_index (base const& x): base (x) {}
@@ -263,16 +302,41 @@ namespace relational
throw operation_failed ();
}
- // SQLite does not support dropping constraints.
+ // SQLite does not support dropping constraints. We are going to
+ // ignore this if the column is NULL'able since in most cases
+ // the constraint is going to be dropped as a result of the
+ // column drop (e.g., an object pointer member got deleted).
+ // If we were not to allow this, then it would be impossible
+ // to do logical drop for pointer columns.
//
- if (sema_rel::drop_foreign_key* dfk =
- check<sema_rel::drop_foreign_key> (at))
+ for (sema_rel::alter_table::names_iterator i (at.names_begin ());
+ i != at.names_end (); ++i)
{
- cerr << "error: SQLite does not support dropping of foreign keys"
- << endl;
- cerr << "info: first dropped foreign key is '" << dfk->name () <<
- "' in table '" << at.name () << "'" << endl;
- throw operation_failed ();
+ using sema_rel::foreign_key;
+ using sema_rel::drop_foreign_key;
+
+ drop_foreign_key* dfk (
+ dynamic_cast<drop_foreign_key*> (&i->nameable ()));
+
+ if (dfk == 0)
+ continue;
+
+ foreign_key& fk (find<foreign_key> (*dfk));
+
+ for (foreign_key::contains_iterator j (fk.contains_begin ());
+ j != fk.contains_end (); ++j)
+ {
+ if (j->column ().null ())
+ continue;
+
+ cerr << "error: SQLite does not support dropping of foreign " <<
+ "keys" << endl;
+ cerr << "info: first dropped foreign key is '" << dfk->name () <<
+ "' in table '" << at.name () << "'" << endl;
+ cerr << "info: could have ignored it if the contained " <<
+ "column(s) allowed NULL values" << endl;
+ throw operation_failed ();
+ }
}
}
};
@@ -285,17 +349,36 @@ namespace relational
virtual void
alter (sema_rel::alter_table& at)
{
- // SQLite does not support dropping columns.
+ // SQLite does not support altering columns (we have to do this
+ // in both alter_table_pre/post because of the
+ // check_alter_column_null() test in the common code).
//
- if (sema_rel::drop_column* dc = check<sema_rel::drop_column> (at))
+ if (sema_rel::alter_column* ac = check<sema_rel::alter_column> (at))
{
- cerr << "error: SQLite does not support dropping of columns"
+ cerr << "error: SQLite does not support altering of columns"
<< endl;
- cerr << "info: first dropped column is '" << dc->name () <<
+ cerr << "info: first altered column is '" << ac->name () <<
"' in table '" << at.name () << "'" << endl;
throw operation_failed ();
}
+ // Try to do logical column drop.
+ //
+ if (check<sema_rel::drop_column> (at))
+ {
+ pre_statement ();
+
+ os << "UPDATE " << quote_id (at.name ()) << endl
+ << " SET ";
+
+ drop_column dc (*this);
+ trav_rel::unames n (dc);
+ names (at, n);
+ os << endl;
+
+ post_statement ();
+ }
+
// SQLite doesn't support adding foreign keys other than inline
// via a column definition. See if there are any that we couldn't
// handle that way.
diff --git a/odb/semantics/relational/column.hxx b/odb/semantics/relational/column.hxx
index 11a76e0..8c6436e 100644
--- a/odb/semantics/relational/column.hxx
+++ b/odb/semantics/relational/column.hxx
@@ -128,6 +128,13 @@ namespace semantics
: unameable (c, g) {}
drop_column (xml::parser&, uscope&, graph&);
+ public:
+ typedef relational::table table_type;
+
+ table_type&
+ table () const {return dynamic_cast<table_type&> (scope ());}
+
+ public:
virtual drop_column&
clone (uscope&, graph&) const;