summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sqlalchemy')
-rw-r--r--lib/sqlalchemy/dialects/postgresql/base.py39
-rw-r--r--lib/sqlalchemy/engine/ddl.py26
-rw-r--r--lib/sqlalchemy/events.py36
-rw-r--r--lib/sqlalchemy/types.py65
4 files changed, 112 insertions, 54 deletions
diff --git a/lib/sqlalchemy/dialects/postgresql/base.py b/lib/sqlalchemy/dialects/postgresql/base.py
index 3ae60f696..e3beeab79 100644
--- a/lib/sqlalchemy/dialects/postgresql/base.py
+++ b/lib/sqlalchemy/dialects/postgresql/base.py
@@ -449,15 +449,40 @@ class ENUM(sqltypes.Enum):
bind.dialect.has_type(bind, self.name, schema=self.schema):
bind.execute(DropEnumType(self))
- def _on_table_create(self, event, target, bind, **kw):
- self.create(bind=bind, checkfirst=True)
+ def _check_for_name_in_memos(self, checkfirst, kw):
+ """Look in the 'ddl runner' for 'memos', then
+ note our name in that collection.
+
+ This to ensure a particular named enum is operated
+ upon only once within any kind of create/drop
+ sequence without relying upon "checkfirst".
- def _on_metadata_create(self, event, target, bind, **kw):
- if self.metadata is not None:
- self.create(bind=bind, checkfirst=True)
+ """
+
+ if '_ddl_runner' in kw:
+ ddl_runner = kw['_ddl_runner']
+ if '_pg_enums' in ddl_runner.memo:
+ pg_enums = ddl_runner.memo['_pg_enums']
+ else:
+ pg_enums = ddl_runner.memo['_pg_enums'] = set()
+ present = self.name in pg_enums
+ pg_enums.add(self.name)
+ return present
+ else:
+ return False
+
+ def _on_table_create(self, target, bind, checkfirst, **kw):
+ if not self._check_for_name_in_memos(checkfirst, kw):
+ self.create(bind=bind, checkfirst=checkfirst)
+
+ def _on_metadata_create(self, target, bind, checkfirst, **kw):
+ if self.metadata is not None and \
+ not self._check_for_name_in_memos(checkfirst, kw):
+ self.create(bind=bind, checkfirst=checkfirst)
- def _on_metadata_drop(self, event, target, bind, **kw):
- self.drop(bind=bind, checkfirst=True)
+ def _on_metadata_drop(self, target, bind, checkfirst, **kw):
+ if not self._check_for_name_in_memos(checkfirst, kw):
+ self.drop(bind=bind, checkfirst=checkfirst)
colspecs = {
sqltypes.Interval:INTERVAL,
diff --git a/lib/sqlalchemy/engine/ddl.py b/lib/sqlalchemy/engine/ddl.py
index 79958baae..d6fdaee2e 100644
--- a/lib/sqlalchemy/engine/ddl.py
+++ b/lib/sqlalchemy/engine/ddl.py
@@ -21,6 +21,7 @@ class SchemaGenerator(DDLBase):
self.tables = tables and set(tables) or None
self.preparer = dialect.identifier_preparer
self.dialect = dialect
+ self.memo = {}
def _can_create_table(self, table):
self.dialect.validate_identifier(table.name)
@@ -56,7 +57,8 @@ class SchemaGenerator(DDLBase):
metadata.dispatch.before_create(metadata, self.connection,
tables=collection,
- checkfirst=self.checkfirst)
+ checkfirst=self.checkfirst,
+ _ddl_runner=self)
for seq in seq_coll:
self.traverse_single(seq, create_ok=True)
@@ -66,14 +68,16 @@ class SchemaGenerator(DDLBase):
metadata.dispatch.after_create(metadata, self.connection,
tables=collection,
- checkfirst=self.checkfirst)
+ checkfirst=self.checkfirst,
+ _ddl_runner=self)
def visit_table(self, table, create_ok=False):
if not create_ok and not self._can_create_table(table):
return
table.dispatch.before_create(table, self.connection,
- checkfirst=self.checkfirst)
+ checkfirst=self.checkfirst,
+ _ddl_runner=self)
for column in table.columns:
if column.default is not None:
@@ -86,7 +90,8 @@ class SchemaGenerator(DDLBase):
self.traverse_single(index)
table.dispatch.after_create(table, self.connection,
- checkfirst=self.checkfirst)
+ checkfirst=self.checkfirst,
+ _ddl_runner=self)
def visit_sequence(self, sequence, create_ok=False):
if not create_ok and not self._can_create_sequence(sequence):
@@ -104,6 +109,7 @@ class SchemaDropper(DDLBase):
self.tables = tables
self.preparer = dialect.identifier_preparer
self.dialect = dialect
+ self.memo = {}
def visit_metadata(self, metadata):
if self.tables:
@@ -117,7 +123,8 @@ class SchemaDropper(DDLBase):
metadata.dispatch.before_drop(metadata, self.connection,
tables=collection,
- checkfirst=self.checkfirst)
+ checkfirst=self.checkfirst,
+ _ddl_runner=self)
for table in collection:
self.traverse_single(table, drop_ok=True)
@@ -127,7 +134,8 @@ class SchemaDropper(DDLBase):
metadata.dispatch.after_drop(metadata, self.connection,
tables=collection,
- checkfirst=self.checkfirst)
+ checkfirst=self.checkfirst,
+ _ddl_runner=self)
def _can_drop_table(self, table):
self.dialect.validate_identifier(table.name)
@@ -155,7 +163,8 @@ class SchemaDropper(DDLBase):
return
table.dispatch.before_drop(table, self.connection,
- checkfirst=self.checkfirst)
+ checkfirst=self.checkfirst,
+ _ddl_runner=self)
for column in table.columns:
if column.default is not None:
@@ -164,7 +173,8 @@ class SchemaDropper(DDLBase):
self.connection.execute(schema.DropTable(table))
table.dispatch.after_drop(table, self.connection,
- checkfirst=self.checkfirst)
+ checkfirst=self.checkfirst,
+ _ddl_runner=self)
def visit_sequence(self, sequence, drop_ok=False):
if not drop_ok and not self._can_drop_sequence(sequence):
diff --git a/lib/sqlalchemy/events.py b/lib/sqlalchemy/events.py
index f7de851cc..eee2a7557 100644
--- a/lib/sqlalchemy/events.py
+++ b/lib/sqlalchemy/events.py
@@ -78,10 +78,11 @@ class DDLEvents(event.Events):
:param connection: the :class:`.Connection` where the
CREATE statement or statements will be emitted.
:param \**kw: additional keyword arguments relevant
- to the event. Currently this includes the ``tables``
- argument in the case of a :class:`.MetaData` object,
- which is the list of :class:`.Table` objects for which
- CREATE will be emitted.
+ to the event. The contents of this dictionary
+ may vary across releases, and include the
+ list of tables being generated for a metadata-level
+ event, the checkfirst flag, and other
+ elements used by internal events.
"""
@@ -93,10 +94,11 @@ class DDLEvents(event.Events):
:param connection: the :class:`.Connection` where the
CREATE statement or statements have been emitted.
:param \**kw: additional keyword arguments relevant
- to the event. Currently this includes the ``tables``
- argument in the case of a :class:`.MetaData` object,
- which is the list of :class:`.Table` objects for which
- CREATE has been emitted.
+ to the event. The contents of this dictionary
+ may vary across releases, and include the
+ list of tables being generated for a metadata-level
+ event, the checkfirst flag, and other
+ elements used by internal events.
"""
@@ -108,10 +110,11 @@ class DDLEvents(event.Events):
:param connection: the :class:`.Connection` where the
DROP statement or statements will be emitted.
:param \**kw: additional keyword arguments relevant
- to the event. Currently this includes the ``tables``
- argument in the case of a :class:`.MetaData` object,
- which is the list of :class:`.Table` objects for which
- DROP will be emitted.
+ to the event. The contents of this dictionary
+ may vary across releases, and include the
+ list of tables being generated for a metadata-level
+ event, the checkfirst flag, and other
+ elements used by internal events.
"""
@@ -123,10 +126,11 @@ class DDLEvents(event.Events):
:param connection: the :class:`.Connection` where the
DROP statement or statements have been emitted.
:param \**kw: additional keyword arguments relevant
- to the event. Currently this includes the ``tables``
- argument in the case of a :class:`.MetaData` object,
- which is the list of :class:`.Table` objects for which
- DROP has been emitted.
+ to the event. The contents of this dictionary
+ may vary across releases, and include the
+ list of tables being generated for a metadata-level
+ event, the checkfirst flag, and other
+ elements used by internal events.
"""
diff --git a/lib/sqlalchemy/types.py b/lib/sqlalchemy/types.py
index af98dd813..ae15a5d16 100644
--- a/lib/sqlalchemy/types.py
+++ b/lib/sqlalchemy/types.py
@@ -30,7 +30,7 @@ from sqlalchemy.util import pickle
from sqlalchemy.util.compat import decimal
from sqlalchemy.sql.visitors import Visitable
from sqlalchemy import util
-from sqlalchemy import processors, events
+from sqlalchemy import processors, events, event
import collections
default = util.importlater("sqlalchemy.engine", "default")
@@ -1686,26 +1686,45 @@ class SchemaType(events.SchemaEventTarget):
self.schema = kw.pop('schema', None)
self.metadata = kw.pop('metadata', None)
if self.metadata:
- self.metadata.append_ddl_listener('before-create',
- util.portable_instancemethod(self._on_metadata_create))
- self.metadata.append_ddl_listener('after-drop',
- util.portable_instancemethod(self._on_metadata_drop))
+ event.listen(
+ self.metadata,
+ "before_create",
+ util.portable_instancemethod(self._on_metadata_create)
+ )
+ event.listen(
+ self.metadata,
+ "after_drop",
+ util.portable_instancemethod(self._on_metadata_drop)
+ )
def _set_parent(self, column):
column._on_table_attach(util.portable_instancemethod(self._set_table))
def _set_table(self, column, table):
- table.append_ddl_listener('before-create',
- util.portable_instancemethod(
- self._on_table_create))
- table.append_ddl_listener('after-drop',
- util.portable_instancemethod(
- self._on_table_drop))
+ event.listen(
+ table,
+ "before_create",
+ util.portable_instancemethod(
+ self._on_table_create)
+ )
+ event.listen(
+ table,
+ "after_drop",
+ util.portable_instancemethod(self._on_table_drop)
+ )
if self.metadata is None:
- table.metadata.append_ddl_listener('before-create',
- util.portable_instancemethod(self._on_metadata_create))
- table.metadata.append_ddl_listener('after-drop',
- util.portable_instancemethod(self._on_metadata_drop))
+ # TODO: what's the difference between self.metadata
+ # and table.metadata here ?
+ event.listen(
+ table.metadata,
+ "before_create",
+ util.portable_instancemethod(self._on_metadata_create)
+ )
+ event.listen(
+ table.metadata,
+ "after_drop",
+ util.portable_instancemethod(self._on_metadata_drop)
+ )
@property
def bind(self):
@@ -1729,25 +1748,25 @@ class SchemaType(events.SchemaEventTarget):
if t.__class__ is not self.__class__ and isinstance(t, SchemaType):
t.drop(bind=bind, checkfirst=checkfirst)
- def _on_table_create(self, event, target, bind, **kw):
+ def _on_table_create(self, target, bind, **kw):
t = self.dialect_impl(bind.dialect)
if t.__class__ is not self.__class__ and isinstance(t, SchemaType):
- t._on_table_create(event, target, bind, **kw)
+ t._on_table_create(target, bind, **kw)
- def _on_table_drop(self, event, target, bind, **kw):
+ def _on_table_drop(self, target, bind, **kw):
t = self.dialect_impl(bind.dialect)
if t.__class__ is not self.__class__ and isinstance(t, SchemaType):
- t._on_table_drop(event, target, bind, **kw)
+ t._on_table_drop(target, bind, **kw)
- def _on_metadata_create(self, event, target, bind, **kw):
+ def _on_metadata_create(self, target, bind, **kw):
t = self.dialect_impl(bind.dialect)
if t.__class__ is not self.__class__ and isinstance(t, SchemaType):
- t._on_metadata_create(event, target, bind, **kw)
+ t._on_metadata_create(target, bind, **kw)
- def _on_metadata_drop(self, event, target, bind, **kw):
+ def _on_metadata_drop(self, target, bind, **kw):
t = self.dialect_impl(bind.dialect)
if t.__class__ is not self.__class__ and isinstance(t, SchemaType):
- t._on_metadata_drop(event, target, bind, **kw)
+ t._on_metadata_drop(target, bind, **kw)
class Enum(String, SchemaType):
"""Generic Enum Type.