def upgrade(): bind = op.get_bind() engine = bind.engine op.add_column( ML2_PORT_BINDING, sa.Column('status', sa.String(length=16), nullable=False, server_default=constants.PORT_BINDING_STATUS_ACTIVE)) if (engine.name == MYSQL_ENGINE and not ndb.ndb_status(engine)): op.execute("ALTER TABLE ml2_port_bindings DROP PRIMARY KEY," "ADD PRIMARY KEY(port_id, host);") else: inspector = insp.from_engine(bind) fk_name = utils.get_foreign_key_constraint_name( engine, 'ml2_port_bindings', 'port_id') op.drop_constraint(fk_name, ML2_PORT_BINDING, type_='foreignkey') pk_constraint = inspector.get_pk_constraint(ML2_PORT_BINDING) op.drop_constraint(pk_constraint.get('name'), ML2_PORT_BINDING, type_='primary') op.create_primary_key(op.f('pk_ml2_port_bindings'), ML2_PORT_BINDING, ['port_id', 'host']) op.create_foreign_key(fk_name, ML2_PORT_BINDING, 'ports', ["port_id"], ["id"], ondelete='CASCADE')
def _init_events(engine, mysql_sql_mode=None, **kw): """Set up event listeners for MySQL.""" if mysql_sql_mode is not None: @sqlalchemy.event.listens_for(engine, "connect") def _set_session_sql_mode(dbapi_con, connection_rec): cursor = dbapi_con.cursor() cursor.execute("SET SESSION sql_mode = %s", [mysql_sql_mode]) @sqlalchemy.event.listens_for(engine, "first_connect") def _check_effective_sql_mode(dbapi_con, connection_rec): if mysql_sql_mode is not None: _set_session_sql_mode(dbapi_con, connection_rec) cursor = dbapi_con.cursor() cursor.execute("SHOW VARIABLES LIKE 'sql_mode'") realmode = cursor.fetchone() if realmode is None: LOG.warning('Unable to detect effective SQL mode') else: realmode = realmode[1] LOG.debug('MySQL server mode set to %s', realmode) if 'TRADITIONAL' not in realmode.upper() and \ 'STRICT_ALL_TABLES' not in realmode.upper(): LOG.warning( "MySQL SQL mode is '%s', " "consider enabling TRADITIONAL or STRICT_ALL_TABLES", realmode) if ndb.ndb_status(engine): ndb.init_ndb_events(engine)
def test_ndb_enabled(self): self.init_db(True) self.assertTrue(ndb.ndb_status(self.engine)) self.assertIsInstance(self.test_table.c.test1.type, TINYTEXT) self.assertIsInstance(self.test_table.c.test2.type, Text) self.assertIsInstance(self.test_table.c.test3.type, String) self.assertEqual(64, self.test_table.c.test3.type.length) self.assertEqual([], utils.get_non_ndbcluster_tables(self.engine))
def test_ndb_disabled(self): self.init_db(False) self.assertFalse(ndb.ndb_status(self.engine)) self.assertIsInstance(self.test_table.c.test1.type, String) self.assertEqual(255, self.test_table.c.test1.type.length) self.assertIsInstance(self.test_table.c.test2.type, String) self.assertEqual(4096, self.test_table.c.test2.type.length) self.assertIsInstance(self.test_table.c.test3.type, String) self.assertEqual(255, self.test_table.c.test3.type.length) self.assertEqual([], utils.get_non_innodb_tables(self.engine))
def autonested_transaction(sess): """This is a convenience method to not bother with 'nested' parameter.""" # If we are using MySQL Cluster (NDB), disable nesting. if ndb.ndb_status(sess.get_bind()): try: session_context = sess.begin(subtransactions=True, nested=False) except exc.InvalidRequestError: session_context = sess.begin(subtransactions=False, nested=False) finally: with session_context as tx: yield tx else: if sess.is_active: session_context = sess.begin(nested=True) else: session_context = sess.begin(subtransactions=True) with session_context as tx: yield tx
def suspend_fk_constraints_for_col_alter(engine, table_name, column_name, referents=[]): """Detect foreign key constraints, drop, and recreate. This is used to guard against a column ALTER that on some backends cannot proceed unless foreign key constraints are not present. e.g.:: from oslo_db.sqlalchemy.util import ( suspend_fk_constraints_for_col_alter ) with suspend_fk_constraints_for_col_alter( migrate_engine, "user_table", referents=[ "local_user", "nonlocal_user", "project" ]): user_table.c.domain_id.alter(nullable=False) :param engine: a SQLAlchemy engine (or connection) :param table_name: target table name. All foreign key constraints that refer to the table_name / column_name will be dropped and recreated. :param column_name: target column name. all foreign key constraints which refer to this column, either partially or fully, will be dropped and recreated. :param referents: sequence of string table names to search for foreign key constraints. A future version of this function may no longer require this argument, however for the moment it is required. """ if (not ndb.ndb_status(engine)): yield else: with engine.connect() as conn: insp = inspect(conn) fks = [] for ref_table_name in referents: for fk in insp.get_foreign_keys(ref_table_name): if not fk.get('name'): raise AssertionError("foreign key hasn't a name.") if fk['referred_table'] == table_name and \ column_name in fk['referred_columns']: fk['source_table'] = ref_table_name if 'options' not in fk: fk['options'] = {} fks.append(fk) ctx = MigrationContext.configure(conn) op = Operations(ctx) for fk in fks: op.drop_constraint(fk['name'], fk['source_table'], type_="foreignkey") yield for fk in fks: op.create_foreign_key( fk['name'], fk['source_table'], fk['referred_table'], fk['constrained_columns'], fk['referred_columns'], onupdate=fk['options'].get('onupdate'), ondelete=fk['options'].get('ondelete'), deferrable=fk['options'].get('deferrable'), initially=fk['options'].get('initially'), )
def suspend_fk_constraints_for_col_alter( engine, table_name, column_name, referents=[]): """Detect foreign key constraints, drop, and recreate. This is used to guard against a column ALTER that on some backends cannot proceed unless foreign key constraints are not present. e.g.:: from oslo_db.sqlalchemy.util import ( suspend_fk_constraints_for_col_alter ) with suspend_fk_constraints_for_col_alter( migrate_engine, "user_table", referents=[ "local_user", "nonlocal_user", "project" ]): user_table.c.domain_id.alter(nullable=False) :param engine: a SQLAlchemy engine (or connection) :param table_name: target table name. All foreign key constraints that refer to the table_name / column_name will be dropped and recreated. :param column_name: target column name. all foreign key constraints which refer to this column, either partially or fully, will be dropped and recreated. :param referents: sequence of string table names to search for foreign key constraints. A future version of this function may no longer require this argument, however for the moment it is required. """ if ( not ndb.ndb_status(engine) ): yield else: with engine.connect() as conn: insp = inspect(conn) fks = [] for ref_table_name in referents: for fk in insp.get_foreign_keys(ref_table_name): if not fk.get('name'): raise AssertionError("foreign key hasn't a name.") if fk['referred_table'] == table_name and \ column_name in fk['referred_columns']: fk['source_table'] = ref_table_name if 'options' not in fk: fk['options'] = {} fks.append(fk) ctx = MigrationContext.configure(conn) op = Operations(ctx) for fk in fks: op.drop_constraint( fk['name'], fk['source_table'], type_="foreignkey") yield for fk in fks: op.create_foreign_key( fk['name'], fk['source_table'], fk['referred_table'], fk['constrained_columns'], fk['referred_columns'], onupdate=fk['options'].get('onupdate'), ondelete=fk['options'].get('ondelete'), deferrable=fk['options'].get('deferrable'), initially=fk['options'].get('initially'), )