summaryrefslogtreecommitdiff
path: root/odb/odb/relational/pgsql/schema.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'odb/odb/relational/pgsql/schema.cxx')
-rw-r--r--odb/odb/relational/pgsql/schema.cxx266
1 files changed, 266 insertions, 0 deletions
diff --git a/odb/odb/relational/pgsql/schema.cxx b/odb/odb/relational/pgsql/schema.cxx
new file mode 100644
index 0000000..b9c3f2e
--- /dev/null
+++ b/odb/odb/relational/pgsql/schema.cxx
@@ -0,0 +1,266 @@
+// file : odb/relational/pgsql/schema.cxx
+// license : GNU GPL v3; see accompanying LICENSE file
+
+#include <odb/relational/schema.hxx>
+
+#include <odb/relational/pgsql/common.hxx>
+#include <odb/relational/pgsql/context.hxx>
+
+using namespace std;
+
+namespace relational
+{
+ namespace pgsql
+ {
+ namespace schema
+ {
+ namespace relational = relational::schema;
+ using relational::table_set;
+
+ //
+ // Drop.
+ //
+
+ struct drop_table: relational::drop_table, context
+ {
+ drop_table (base const& x): base (x) {}
+
+ virtual void
+ traverse (sema_rel::table& t, bool migration)
+ {
+ // For migration drop foreign keys explicitly in pre-migration.
+ //
+ if (migration)
+ {
+ base::traverse (t, migration);
+ return;
+ }
+
+ // For schema creation we use the CASCADE clause to drop foreign
+ // keys.
+ //
+ if (pass_ != 2)
+ return;
+
+ pre_statement ();
+ os << "DROP TABLE " << (migration ? "" : "IF EXISTS ") <<
+ quote_id (t.name ()) << " CASCADE" << endl;
+ post_statement ();
+ }
+ };
+ entry<drop_table> drop_table_;
+
+ //
+ // Create.
+ //
+
+ struct create_column: relational::create_column, context
+ {
+ create_column (base const& x): base (x) {}
+
+ virtual void
+ type (sema_rel::column& c, bool auto_)
+ {
+ if (auto_)
+ {
+ // This should never fail since we have already parsed this.
+ //
+ sql_type const& t (parse_sql_type (c.type ()));
+
+ // The model creation code makes sure it is one of these type.
+ //
+ if (t.type == sql_type::INTEGER)
+ os << "SERIAL";
+ else if (t.type == sql_type::BIGINT)
+ os << "BIGSERIAL";
+ }
+ else
+ base::type (c, auto_);
+ }
+ };
+ entry<create_column> create_column_;
+
+ struct create_foreign_key: relational::create_foreign_key, context
+ {
+ create_foreign_key (base const& x): base (x) {}
+
+ virtual void
+ deferrable (sema_rel::deferrable d)
+ {
+ os << endl
+ << " INITIALLY " << d;
+ }
+ };
+ entry<create_foreign_key> create_foreign_key_;
+
+ struct create_index: relational::create_index, context
+ {
+ create_index (base const& x): base (x) {}
+
+ virtual void
+ create (sema_rel::index& in)
+ {
+ os << "CREATE ";
+
+ if (!in.type ().empty ())
+ {
+ // Handle the CONCURRENTLY keyword.
+ //
+ string const& t (in.type ());
+
+ if (t == "concurrently" || t == "CONCURRENTLY")
+ {
+ os << "INDEX " << t;
+ }
+ else
+ {
+ size_t p (t.rfind (' '));
+ string s (t, (p != string::npos ? p + 1 : 0), string::npos);
+
+ if (s == "concurrently" || s == "CONCURRENTLY")
+ os << string (t, 0, p) << " INDEX " << s;
+ else
+ os << t << " INDEX";
+ }
+ }
+ else
+ os << "INDEX";
+
+ os << " " << name (in) << endl
+ << " ON " << table_name (in);
+
+ if (!in.method ().empty ())
+ os << " USING " << in.method ();
+
+ os << " (";
+ columns (in);
+ os << ")" << endl;
+
+ if (!in.options ().empty ())
+ os << ' ' << in.options () << endl;
+ }
+ };
+ entry<create_index> create_index_;
+
+ //
+ // Alter.
+ //
+
+ struct alter_column: relational::alter_column, context
+ {
+ alter_column (base const& x): base (x) {}
+
+ virtual void
+ alter (sema_rel::column& c)
+ {
+ os << quote_id (c.name ()) << " " <<
+ (c.null () ? "DROP" : "SET") << " NOT NULL";
+ }
+ };
+ entry<alter_column> alter_column_;
+
+ //
+ // Schema version table.
+ //
+
+ struct version_table: relational::version_table, context
+ {
+ version_table (base const& x): base (x) {}
+
+ // PostgreSQL prior to 9.1 doesn't support IF NOT EXISTS in
+ // CREATE TABLE. We also cannot use IF-ELSE construct in plain
+ // SQL. To make it at least work for a single schema, we are
+ // going to drop the schema version table after the DROP
+ // statements and then unconditionally create it after CREATE.
+ //
+ virtual void
+ create_table ()
+ {
+ if (options.pgsql_server_version () >= pgsql_version (9, 1))
+ {
+ pre_statement ();
+
+ os << "CREATE TABLE IF NOT EXISTS " << qt_ << " (" << endl
+ << " " << qn_ << " TEXT NOT NULL PRIMARY KEY," << endl
+ << " " << qv_ << " BIGINT NOT NULL," << endl
+ << " " << qm_ << " BOOLEAN NOT NULL)" << endl;
+
+ post_statement ();
+ }
+ }
+
+ virtual void
+ drop ()
+ {
+ pre_statement ();
+
+ if (options.pgsql_server_version () >= pgsql_version (9, 1))
+ os << "DELETE FROM " << qt_ << endl
+ << " WHERE " << qn_ << " = " << qs_ << endl;
+ else
+ os << "DROP TABLE IF EXISTS " << qt_ << endl;
+
+ post_statement ();
+ }
+
+ virtual void
+ create (sema_rel::version v)
+ {
+ pre_statement ();
+
+ if (options.pgsql_server_version () >= pgsql_version (9, 1))
+ {
+ os << "INSERT INTO " << qt_ << " (" << endl
+ << " " << qn_ << ", " << qv_ << ", " << qm_ << ")" << endl
+ << " SELECT " << qs_ << ", " << v << ", FALSE" << endl
+ << " WHERE NOT EXISTS (" << endl
+ << " SELECT 1 FROM " << qt_ << " WHERE " << qn_ << " = " <<
+ qs_ << ")" << endl;
+ }
+ else
+ {
+ os << "CREATE TABLE " << qt_ << " (" << endl
+ << " " << qn_ << " TEXT NOT NULL PRIMARY KEY," << endl
+ << " " << qv_ << " BIGINT NOT NULL," << endl
+ << " " << qm_ << " BOOLEAN NOT NULL)" << endl;
+
+ post_statement ();
+ pre_statement ();
+
+ os << "INSERT INTO " << qt_ << " (" << endl
+ << " " << qn_ << ", " << qv_ << ", " << qm_ << ")" << endl
+ << " VALUES (" << qs_ << ", " << v << ", FALSE)" << endl;
+ }
+
+ post_statement ();
+ }
+
+ virtual void
+ migrate_pre (sema_rel::version v)
+ {
+ pre_statement ();
+
+ os << "UPDATE " << qt_ << endl
+ << " SET " << qv_ << " = " << v << ", " << qm_ << " = TRUE" << endl
+ << " WHERE " << qn_ << " = " << qs_ << endl;
+
+ post_statement ();
+ }
+
+ virtual void
+ migrate_post ()
+ {
+ pre_statement ();
+
+ os << "UPDATE " << qt_ << endl
+ << " SET " << qm_ << " = FALSE" << endl
+ << " WHERE " << qn_ << " = " << qs_ << endl;
+
+ post_statement ();
+ }
+
+ };
+ entry<version_table> version_table_;
+ }
+ }
+}