]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- remove drizzle dialect
authorMike Bayer <mike_mp@zzzcomputing.com>
Fri, 30 May 2014 22:06:09 +0000 (18:06 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Fri, 30 May 2014 22:06:09 +0000 (18:06 -0400)
- restore mysqldb fully within dialects/mysql/, it's no longer a connector.
fixes #2984

doc/build/changelog/changelog_10.rst
doc/build/changelog/migration_10.rst
doc/build/dialects/drizzle.rst [deleted file]
doc/build/dialects/index.rst
lib/sqlalchemy/connectors/mysqldb.py [deleted file]
lib/sqlalchemy/databases/__init__.py
lib/sqlalchemy/dialects/__init__.py
lib/sqlalchemy/dialects/drizzle/__init__.py [deleted file]
lib/sqlalchemy/dialects/drizzle/base.py [deleted file]
lib/sqlalchemy/dialects/drizzle/mysqldb.py [deleted file]
lib/sqlalchemy/dialects/mysql/mysqldb.py

index 36281a13efb2becd488936772739d298be22feb6..9004f5681ea7d018f4cbcced74ef140fd3105668 100644 (file)
 .. changelog::
        :version: 1.0.0
 
+    .. change::
+        :tags: removed
+
+        The Drizzle dialect has been removed from the Core; it is now
+        available as `sqlalchemy-drizzle <https://bitbucket.org/zzzeek/sqlalchemy-drizzle>`_,
+        an independent, third party dialect.  The dialect is still based
+        almost entirely off of the MySQL dialect present in SQLAlchemy.
+
+        .. seealso::
+
+            :ref:`change_2984`
+
     .. change::
         :tags: enhancement, orm
         :tickets: 3061
index 3c6286b6034812211918338fa86c70946af0ad58..1e5156dce1d621177e2e5a99f5289198fe484811 100644 (file)
@@ -143,3 +143,19 @@ Behavioral Improvements
 
 Dialect Changes
 ===============
+
+.. _change_2984:
+
+Drizzle Dialect is now an External Dialect
+------------------------------------------
+
+The dialect for `Drizzle <http://www.drizzle.org/>`_ is now an external
+dialect, available at https://bitbucket.org/zzzeek/sqlalchemy-drizzle.
+This dialect was added to SQLAlchemy right before SQLAlchemy was able to
+accommodate third party dialects well; going forward, all databases that aren't
+within the "ubiquitous use" category are third party dialects.
+The dialect's implementation hasn't changed and is still based on the
+MySQL + MySQLdb dialects within SQLAlchemy.  The dialect is as of yet
+unreleased and in "attic" status; however it passes the majority of tests
+and is generally in decent working order, if someone wants to pick up
+on polishing it.
diff --git a/doc/build/dialects/drizzle.rst b/doc/build/dialects/drizzle.rst
deleted file mode 100644 (file)
index c89bba0..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-.. _drizzle_toplevel:
-
-Drizzle
-=======
-
-.. automodule:: sqlalchemy.dialects.drizzle.base
-
-Drizzle Data Types
-------------------
-
-As with all SQLAlchemy dialects, all UPPERCASE types that are known to be
-valid with Drizzle are importable from the top level dialect::
-
-    from sqlalchemy.dialects.drizzle import \
-            BIGINT, BINARY, BLOB, BOOLEAN, CHAR, DATE, DATETIME,
-            DECIMAL, DOUBLE, ENUM, FLOAT, INT, INTEGER,
-            NUMERIC, TEXT, TIME, TIMESTAMP, VARBINARY, VARCHAR
-
-Types which are specific to Drizzle, or have Drizzle-specific
-construction arguments, are as follows:
-
-.. currentmodule:: sqlalchemy.dialects.drizzle
-
-.. autoclass:: BIGINT
-    :members: __init__
-     
-
-.. autoclass:: CHAR
-    :members: __init__
-     
-
-.. autoclass:: DECIMAL
-    :members: __init__
-     
-
-.. autoclass:: DOUBLE
-    :members: __init__
-     
-
-.. autoclass:: ENUM
-    :members: __init__
-     
-
-.. autoclass:: FLOAT
-    :members: __init__
-     
-
-.. autoclass:: INTEGER
-    :members: __init__
-     
-
-.. autoclass:: NUMERIC
-    :members: __init__
-     
-
-.. autoclass:: REAL
-    :members: __init__
-     
-
-.. autoclass:: TEXT
-    :members: __init__
-     
-
-.. autoclass:: TIMESTAMP
-    :members: __init__
-     
-
-.. autoclass:: VARCHAR
-    :members: __init__
-     
-
-
-MySQL-Python
-------------
-
-.. automodule:: sqlalchemy.dialects.drizzle.mysqldb
index 01ff659952bb642a50f8884126e2a868d4816df6..da2699b2b71471f2bd1e836a6af0d42b4f48a185 100644 (file)
@@ -16,7 +16,6 @@ Included Dialects
     :maxdepth: 1
     :glob:
 
-    drizzle
     firebird
     mssql
     mysql
@@ -39,6 +38,9 @@ External Dialects
    The "classic" dialects such as SQLite, MySQL, Postgresql, Oracle,
    SQL Server, and Firebird will remain in the Core for the time being.
 
+.. versionchanged:: 1.0
+    The Drizzle dialect has been moved into the third party system.
+
 Current external dialect projects for SQLAlchemy include:
 
 Production Ready
@@ -71,6 +73,7 @@ Community members interested in these dialects should feel free to pick up on
 their current codebase and fork off into working libraries.
 
 * `sqlalchemy-access <https://bitbucket.org/zzzeek/sqlalchemy-access>`_ - driver for Microsoft Access.
+* `sqlalchemy-drizzle <https://bitbucket.org/zzzeek/sqlalchemy-drizzle>`_ - driver for the Drizzle MySQL variant.
 * `sqlalchemy-informixdb <https://bitbucket.org/zzzeek/sqlalchemy-informixdb>`_ - driver for the informixdb DBAPI.
 * `sqlalchemy-maxdb <https://bitbucket.org/zzzeek/sqlalchemy-maxdb>`_ - driver for the MaxDB database
 
diff --git a/lib/sqlalchemy/connectors/mysqldb.py b/lib/sqlalchemy/connectors/mysqldb.py
deleted file mode 100644 (file)
index e4efb22..0000000
+++ /dev/null
@@ -1,144 +0,0 @@
-# connectors/mysqldb.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors <see AUTHORS file>
-#
-# This module is part of SQLAlchemy and is released under
-# the MIT License: http://www.opensource.org/licenses/mit-license.php
-
-"""Define behaviors common to MySQLdb dialects.
-
-Currently includes MySQL and Drizzle.
-
-"""
-
-from . import Connector
-from ..engine import base as engine_base, default
-from ..sql import operators as sql_operators
-from .. import exc, log, schema, sql, types as sqltypes, util, processors
-import re
-
-
-# the subclassing of Connector by all classes
-# here is not strictly necessary
-
-
-class MySQLDBExecutionContext(Connector):
-
-    @property
-    def rowcount(self):
-        if hasattr(self, '_rowcount'):
-            return self._rowcount
-        else:
-            return self.cursor.rowcount
-
-
-class MySQLDBCompiler(Connector):
-    def visit_mod_binary(self, binary, operator, **kw):
-        return self.process(binary.left, **kw) + " %% " + \
-                    self.process(binary.right, **kw)
-
-    def post_process_text(self, text):
-        return text.replace('%', '%%')
-
-
-class MySQLDBIdentifierPreparer(Connector):
-
-    def _escape_identifier(self, value):
-        value = value.replace(self.escape_quote, self.escape_to_quote)
-        return value.replace("%", "%%")
-
-
-class MySQLDBConnector(Connector):
-    driver = 'mysqldb'
-    supports_unicode_statements = False
-    supports_sane_rowcount = True
-    supports_sane_multi_rowcount = True
-
-    supports_native_decimal = True
-
-    default_paramstyle = 'format'
-
-    @classmethod
-    def dbapi(cls):
-        # is overridden when pymysql is used
-        return __import__('MySQLdb')
-
-
-    def do_executemany(self, cursor, statement, parameters, context=None):
-        rowcount = cursor.executemany(statement, parameters)
-        if context is not None:
-            context._rowcount = rowcount
-
-    def create_connect_args(self, url):
-        opts = url.translate_connect_args(database='db', username='user',
-                                          password='passwd')
-        opts.update(url.query)
-
-        util.coerce_kw_type(opts, 'compress', bool)
-        util.coerce_kw_type(opts, 'connect_timeout', int)
-        util.coerce_kw_type(opts, 'read_timeout', int)
-        util.coerce_kw_type(opts, 'client_flag', int)
-        util.coerce_kw_type(opts, 'local_infile', int)
-        # Note: using either of the below will cause all strings to be returned
-        # as Unicode, both in raw SQL operations and with column types like
-        # String and MSString.
-        util.coerce_kw_type(opts, 'use_unicode', bool)
-        util.coerce_kw_type(opts, 'charset', str)
-
-        # Rich values 'cursorclass' and 'conv' are not supported via
-        # query string.
-
-        ssl = {}
-        keys = ['ssl_ca', 'ssl_key', 'ssl_cert', 'ssl_capath', 'ssl_cipher']
-        for key in keys:
-            if key in opts:
-                ssl[key[4:]] = opts[key]
-                util.coerce_kw_type(ssl, key[4:], str)
-                del opts[key]
-        if ssl:
-            opts['ssl'] = ssl
-
-        # FOUND_ROWS must be set in CLIENT_FLAGS to enable
-        # supports_sane_rowcount.
-        client_flag = opts.get('client_flag', 0)
-        if self.dbapi is not None:
-            try:
-                CLIENT_FLAGS = __import__(
-                                    self.dbapi.__name__ + '.constants.CLIENT'
-                                    ).constants.CLIENT
-                client_flag |= CLIENT_FLAGS.FOUND_ROWS
-            except (AttributeError, ImportError):
-                self.supports_sane_rowcount = False
-            opts['client_flag'] = client_flag
-        return [[], opts]
-
-    def _get_server_version_info(self, connection):
-        dbapi_con = connection.connection
-        version = []
-        r = re.compile('[.\-]')
-        for n in r.split(dbapi_con.get_server_info()):
-            try:
-                version.append(int(n))
-            except ValueError:
-                version.append(n)
-        return tuple(version)
-
-    def _extract_error_code(self, exception):
-        return exception.args[0]
-
-    def _detect_charset(self, connection):
-        """Sniff out the character set in use for connection results."""
-
-        try:
-            # note: the SQL here would be
-            # "SHOW VARIABLES LIKE 'character_set%%'"
-            cset_name = connection.connection.character_set_name
-        except AttributeError:
-            util.warn(
-                "No 'character_set_name' can be detected with "
-                "this MySQL-Python version; "
-                "please upgrade to a recent version of MySQL-Python.  "
-                "Assuming latin1.")
-            return 'latin1'
-        else:
-            return cset_name()
-
index 915eefa4a53035ca499900321e045e4149cc75f4..57de841fa8d40e5b39c020915c4a938d7798750b 100644 (file)
@@ -12,7 +12,6 @@ from ..dialects.sqlite import base as sqlite
 from ..dialects.postgresql import base as postgresql
 postgres = postgresql
 from ..dialects.mysql import base as mysql
-from ..dialects.drizzle import base as drizzle
 from ..dialects.oracle import base as oracle
 from ..dialects.firebird import base as firebird
 from ..dialects.mssql import base as mssql
@@ -20,7 +19,6 @@ from ..dialects.sybase import base as sybase
 
 
 __all__ = (
-    'drizzle',
     'firebird',
     'mssql',
     'mysql',
index 974d4f787567321707589687beee71e48ff17144..b5ef85aba907feb808e6e97b0e031caef6321c2f 100644 (file)
@@ -5,7 +5,6 @@
 # the MIT License: http://www.opensource.org/licenses/mit-license.php
 
 __all__ = (
-    'drizzle',
     'firebird',
     'mssql',
     'mysql',
diff --git a/lib/sqlalchemy/dialects/drizzle/__init__.py b/lib/sqlalchemy/dialects/drizzle/__init__.py
deleted file mode 100644 (file)
index 1392b8e..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-from sqlalchemy.dialects.drizzle import base, mysqldb
-
-base.dialect = mysqldb.dialect
-
-from sqlalchemy.dialects.drizzle.base import \
-    BIGINT, BINARY, BLOB, \
-    BOOLEAN, CHAR, DATE, \
-    DATETIME, DECIMAL, DOUBLE, \
-    ENUM, FLOAT, INTEGER, \
-    NUMERIC, REAL, TEXT, \
-    TIME, TIMESTAMP, VARBINARY, \
-    VARCHAR, dialect
-
-__all__ = (
-    'BIGINT', 'BINARY', 'BLOB',
-    'BOOLEAN', 'CHAR', 'DATE',
-    'DATETIME', 'DECIMAL', 'DOUBLE',
-    'ENUM', 'FLOAT', 'INTEGER',
-    'NUMERIC', 'REAL', 'TEXT',
-    'TIME', 'TIMESTAMP', 'VARBINARY',
-    'VARCHAR', 'dialect'
-)
diff --git a/lib/sqlalchemy/dialects/drizzle/base.py b/lib/sqlalchemy/dialects/drizzle/base.py
deleted file mode 100644 (file)
index b5addb4..0000000
+++ /dev/null
@@ -1,498 +0,0 @@
-# drizzle/base.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors <see AUTHORS file>
-# Copyright (C) 2010-2011 Monty Taylor <mordred@inaugust.com>
-#
-# This module is part of SQLAlchemy and is released under
-# the MIT License: http://www.opensource.org/licenses/mit-license.php
-
-
-"""
-
-.. dialect:: drizzle
-    :name: Drizzle
-
-Drizzle is a variant of MySQL. Unlike MySQL, Drizzle's default storage engine
-is InnoDB (transactions, foreign-keys) rather than MyISAM. For more
-`Notable Differences <http://docs.drizzle.org/mysql_differences.html>`_, visit
-the `Drizzle Documentation <http://docs.drizzle.org/index.html>`_.
-
-The SQLAlchemy Drizzle dialect leans heavily on the MySQL dialect, so much of
-the :doc:`SQLAlchemy MySQL <mysql>` documentation is also relevant.
-
-
-"""
-
-from sqlalchemy import exc
-from sqlalchemy import log
-from sqlalchemy import types as sqltypes
-from sqlalchemy.engine import reflection
-from sqlalchemy.dialects.mysql import base as mysql_dialect
-from sqlalchemy.types import DATE, DATETIME, BOOLEAN, TIME, \
-                             BLOB, BINARY, VARBINARY
-
-
-class _NumericType(object):
-    """Base for Drizzle numeric types."""
-
-    def __init__(self, **kw):
-        super(_NumericType, self).__init__(**kw)
-
-
-class _FloatType(_NumericType, sqltypes.Float):
-    def __init__(self, precision=None, scale=None, asdecimal=True, **kw):
-        if isinstance(self, (REAL, DOUBLE)) and \
-            (
-                (precision is None and scale is not None) or
-                (precision is not None and scale is None)
-            ):
-            raise exc.ArgumentError(
-                "You must specify both precision and scale or omit "
-                "both altogether.")
-
-        super(_FloatType, self).__init__(precision=precision,
-                                         asdecimal=asdecimal, **kw)
-        self.scale = scale
-
-
-class _StringType(mysql_dialect._StringType):
-    """Base for Drizzle string types."""
-
-    def __init__(self, collation=None, binary=False, **kw):
-        kw['national'] = False
-        super(_StringType, self).__init__(collation=collation, binary=binary,
-                                          **kw)
-
-
-class NUMERIC(_NumericType, sqltypes.NUMERIC):
-    """Drizzle NUMERIC type."""
-
-    __visit_name__ = 'NUMERIC'
-
-    def __init__(self, precision=None, scale=None, asdecimal=True, **kw):
-        """Construct a NUMERIC.
-
-        :param precision: Total digits in this number.  If scale and precision
-          are both None, values are stored to limits allowed by the server.
-
-        :param scale: The number of digits after the decimal point.
-
-        """
-
-        super(NUMERIC, self).__init__(precision=precision, scale=scale,
-                                      asdecimal=asdecimal, **kw)
-
-
-class DECIMAL(_NumericType, sqltypes.DECIMAL):
-    """Drizzle DECIMAL type."""
-
-    __visit_name__ = 'DECIMAL'
-
-    def __init__(self, precision=None, scale=None, asdecimal=True, **kw):
-        """Construct a DECIMAL.
-
-        :param precision: Total digits in this number.  If scale and precision
-          are both None, values are stored to limits allowed by the server.
-
-        :param scale: The number of digits after the decimal point.
-
-        """
-        super(DECIMAL, self).__init__(precision=precision, scale=scale,
-                                      asdecimal=asdecimal, **kw)
-
-
-class DOUBLE(_FloatType):
-    """Drizzle DOUBLE type."""
-
-    __visit_name__ = 'DOUBLE'
-
-    def __init__(self, precision=None, scale=None, asdecimal=True, **kw):
-        """Construct a DOUBLE.
-
-        :param precision: Total digits in this number.  If scale and precision
-          are both None, values are stored to limits allowed by the server.
-
-        :param scale: The number of digits after the decimal point.
-
-        """
-
-        super(DOUBLE, self).__init__(precision=precision, scale=scale,
-                                     asdecimal=asdecimal, **kw)
-
-
-class REAL(_FloatType, sqltypes.REAL):
-    """Drizzle REAL type."""
-
-    __visit_name__ = 'REAL'
-
-    def __init__(self, precision=None, scale=None, asdecimal=True, **kw):
-        """Construct a REAL.
-
-        :param precision: Total digits in this number.  If scale and precision
-          are both None, values are stored to limits allowed by the server.
-
-        :param scale: The number of digits after the decimal point.
-
-        """
-
-        super(REAL, self).__init__(precision=precision, scale=scale,
-                                   asdecimal=asdecimal, **kw)
-
-
-class FLOAT(_FloatType, sqltypes.FLOAT):
-    """Drizzle FLOAT type."""
-
-    __visit_name__ = 'FLOAT'
-
-    def __init__(self, precision=None, scale=None, asdecimal=False, **kw):
-        """Construct a FLOAT.
-
-        :param precision: Total digits in this number.  If scale and precision
-          are both None, values are stored to limits allowed by the server.
-
-        :param scale: The number of digits after the decimal point.
-
-        """
-
-        super(FLOAT, self).__init__(precision=precision, scale=scale,
-                                    asdecimal=asdecimal, **kw)
-
-    def bind_processor(self, dialect):
-        return None
-
-
-class INTEGER(sqltypes.INTEGER):
-    """Drizzle INTEGER type."""
-
-    __visit_name__ = 'INTEGER'
-
-    def __init__(self, **kw):
-        """Construct an INTEGER."""
-
-        super(INTEGER, self).__init__(**kw)
-
-
-class BIGINT(sqltypes.BIGINT):
-    """Drizzle BIGINTEGER type."""
-
-    __visit_name__ = 'BIGINT'
-
-    def __init__(self, **kw):
-        """Construct a BIGINTEGER."""
-
-        super(BIGINT, self).__init__(**kw)
-
-
-class TIME(mysql_dialect.TIME):
-    """Drizzle TIME type."""
-
-
-class TIMESTAMP(sqltypes.TIMESTAMP):
-    """Drizzle TIMESTAMP type."""
-
-    __visit_name__ = 'TIMESTAMP'
-
-
-class TEXT(_StringType, sqltypes.TEXT):
-    """Drizzle TEXT type, for text up to 2^16 characters."""
-
-    __visit_name__ = 'TEXT'
-
-    def __init__(self, length=None, **kw):
-        """Construct a TEXT.
-
-        :param length: Optional, if provided the server may optimize storage
-          by substituting the smallest TEXT type sufficient to store
-          ``length`` characters.
-
-        :param collation: Optional, a column-level collation for this string
-          value.  Takes precedence to 'binary' short-hand.
-
-        :param binary: Defaults to False: short-hand, pick the binary
-          collation type that matches the column's character set.  Generates
-          BINARY in schema.  This does not affect the type of data stored,
-          only the collation of character data.
-
-        """
-
-        super(TEXT, self).__init__(length=length, **kw)
-
-
-class VARCHAR(_StringType, sqltypes.VARCHAR):
-    """Drizzle VARCHAR type, for variable-length character data."""
-
-    __visit_name__ = 'VARCHAR'
-
-    def __init__(self, length=None, **kwargs):
-        """Construct a VARCHAR.
-
-        :param collation: Optional, a column-level collation for this string
-          value.  Takes precedence to 'binary' short-hand.
-
-        :param binary: Defaults to False: short-hand, pick the binary
-          collation type that matches the column's character set.  Generates
-          BINARY in schema.  This does not affect the type of data stored,
-          only the collation of character data.
-
-        """
-
-        super(VARCHAR, self).__init__(length=length, **kwargs)
-
-
-class CHAR(_StringType, sqltypes.CHAR):
-    """Drizzle CHAR type, for fixed-length character data."""
-
-    __visit_name__ = 'CHAR'
-
-    def __init__(self, length=None, **kwargs):
-        """Construct a CHAR.
-
-        :param length: Maximum data length, in characters.
-
-        :param binary: Optional, use the default binary collation for the
-          national character set.  This does not affect the type of data
-          stored, use a BINARY type for binary data.
-
-        :param collation: Optional, request a particular collation.  Must be
-          compatible with the national character set.
-
-        """
-
-        super(CHAR, self).__init__(length=length, **kwargs)
-
-
-class ENUM(mysql_dialect.ENUM):
-    """Drizzle ENUM type."""
-
-    def __init__(self, *enums, **kw):
-        """Construct an ENUM.
-
-        Example:
-
-          Column('myenum', ENUM("foo", "bar", "baz"))
-
-        :param enums: The range of valid values for this ENUM.  Values will be
-          quoted when generating the schema according to the quoting flag (see
-          below).
-
-        :param strict: Defaults to False: ensure that a given value is in this
-          ENUM's range of permissible values when inserting or updating rows.
-          Note that Drizzle will not raise a fatal error if you attempt to
-          store an out of range value- an alternate value will be stored
-          instead.
-          (See Drizzle ENUM documentation.)
-
-        :param collation: Optional, a column-level collation for this string
-          value.  Takes precedence to 'binary' short-hand.
-
-        :param binary: Defaults to False: short-hand, pick the binary
-          collation type that matches the column's character set.  Generates
-          BINARY in schema.  This does not affect the type of data stored,
-          only the collation of character data.
-
-        :param quoting: Defaults to 'auto': automatically determine enum value
-          quoting.  If all enum values are surrounded by the same quoting
-          character, then use 'quoted' mode.  Otherwise, use 'unquoted' mode.
-
-          'quoted': values in enums are already quoted, they will be used
-          directly when generating the schema - this usage is deprecated.
-
-          'unquoted': values in enums are not quoted, they will be escaped and
-          surrounded by single quotes when generating the schema.
-
-          Previous versions of this type always required manually quoted
-          values to be supplied; future versions will always quote the string
-          literals for you.  This is a transitional option.
-
-        """
-
-        super(ENUM, self).__init__(*enums, **kw)
-
-
-class _DrizzleBoolean(sqltypes.Boolean):
-    def get_dbapi_type(self, dbapi):
-        return dbapi.NUMERIC
-
-
-colspecs = {
-    sqltypes.Numeric: NUMERIC,
-    sqltypes.Float: FLOAT,
-    sqltypes.Time: TIME,
-    sqltypes.Enum: ENUM,
-    sqltypes.Boolean: _DrizzleBoolean,
-}
-
-
-# All the types we have in Drizzle
-ischema_names = {
-    'BIGINT': BIGINT,
-    'BINARY': BINARY,
-    'BLOB': BLOB,
-    'BOOLEAN': BOOLEAN,
-    'CHAR': CHAR,
-    'DATE': DATE,
-    'DATETIME': DATETIME,
-    'DECIMAL': DECIMAL,
-    'DOUBLE': DOUBLE,
-    'ENUM': ENUM,
-    'FLOAT': FLOAT,
-    'INT': INTEGER,
-    'INTEGER': INTEGER,
-    'NUMERIC': NUMERIC,
-    'TEXT': TEXT,
-    'TIME': TIME,
-    'TIMESTAMP': TIMESTAMP,
-    'VARBINARY': VARBINARY,
-    'VARCHAR': VARCHAR,
-}
-
-
-class DrizzleCompiler(mysql_dialect.MySQLCompiler):
-
-    def visit_typeclause(self, typeclause):
-        type_ = typeclause.type.dialect_impl(self.dialect)
-        if isinstance(type_, sqltypes.Integer):
-            return 'INTEGER'
-        else:
-            return super(DrizzleCompiler, self).visit_typeclause(typeclause)
-
-    def visit_cast(self, cast, **kwargs):
-        type_ = self.process(cast.typeclause)
-        if type_ is None:
-            return self.process(cast.clause)
-
-        return 'CAST(%s AS %s)' % (self.process(cast.clause), type_)
-
-
-class DrizzleDDLCompiler(mysql_dialect.MySQLDDLCompiler):
-    pass
-
-
-class DrizzleTypeCompiler(mysql_dialect.MySQLTypeCompiler):
-    def _extend_numeric(self, type_, spec):
-        return spec
-
-    def _extend_string(self, type_, defaults, spec):
-        """Extend a string-type declaration with standard SQL
-        COLLATE annotations and Drizzle specific extensions.
-
-        """
-
-        def attr(name):
-            return getattr(type_, name, defaults.get(name))
-
-        if attr('collation'):
-            collation = 'COLLATE %s' % type_.collation
-        elif attr('binary'):
-            collation = 'BINARY'
-        else:
-            collation = None
-
-        return ' '.join([c for c in (spec, collation)
-                         if c is not None])
-
-    def visit_NCHAR(self, type):
-        raise NotImplementedError("Drizzle does not support NCHAR")
-
-    def visit_NVARCHAR(self, type):
-        raise NotImplementedError("Drizzle does not support NVARCHAR")
-
-    def visit_FLOAT(self, type_):
-        if type_.scale is not None and type_.precision is not None:
-            return "FLOAT(%s, %s)" % (type_.precision, type_.scale)
-        else:
-            return "FLOAT"
-
-    def visit_BOOLEAN(self, type_):
-        return "BOOLEAN"
-
-    def visit_BLOB(self, type_):
-        return "BLOB"
-
-
-class DrizzleExecutionContext(mysql_dialect.MySQLExecutionContext):
-    pass
-
-
-class DrizzleIdentifierPreparer(mysql_dialect.MySQLIdentifierPreparer):
-    pass
-
-
-@log.class_logger
-class DrizzleDialect(mysql_dialect.MySQLDialect):
-    """Details of the Drizzle dialect.
-
-    Not used directly in application code.
-    """
-
-    name = 'drizzle'
-
-    _supports_cast = True
-    supports_sequences = False
-    supports_native_boolean = True
-    supports_views = False
-
-    default_paramstyle = 'format'
-    colspecs = colspecs
-
-    statement_compiler = DrizzleCompiler
-    ddl_compiler = DrizzleDDLCompiler
-    type_compiler = DrizzleTypeCompiler
-    ischema_names = ischema_names
-    preparer = DrizzleIdentifierPreparer
-
-    def on_connect(self):
-        """Force autocommit - Drizzle Bug#707842 doesn't set this properly"""
-
-        def connect(conn):
-            conn.autocommit(False)
-        return connect
-
-    @reflection.cache
-    def get_table_names(self, connection, schema=None, **kw):
-        """Return a Unicode SHOW TABLES from a given schema."""
-
-        if schema is not None:
-            current_schema = schema
-        else:
-            current_schema = self.default_schema_name
-
-        charset = 'utf8'
-        rp = connection.execute("SHOW TABLES FROM %s" %
-            self.identifier_preparer.quote_identifier(current_schema))
-        return [row[0] for row in self._compat_fetchall(rp, charset=charset)]
-
-    @reflection.cache
-    def get_view_names(self, connection, schema=None, **kw):
-        raise NotImplementedError
-
-    def _detect_casing(self, connection):
-        """Sniff out identifier case sensitivity.
-
-        Cached per-connection. This value can not change without a server
-        restart.
-        """
-
-        return 0
-
-    def _detect_collations(self, connection):
-        """Pull the active COLLATIONS list from the server.
-
-        Cached per-connection.
-        """
-
-        collations = {}
-        charset = self._connection_charset
-        rs = connection.execute(
-            'SELECT CHARACTER_SET_NAME, COLLATION_NAME FROM'
-            ' data_dictionary.COLLATIONS')
-        for row in self._compat_fetchall(rs, charset):
-            collations[row[0]] = row[1]
-        return collations
-
-    def _detect_ansiquotes(self, connection):
-        """Detect and adjust for the ANSI_QUOTES sql mode."""
-
-        self._server_ansiquotes = False
-        self._backslash_escapes = False
-
-
diff --git a/lib/sqlalchemy/dialects/drizzle/mysqldb.py b/lib/sqlalchemy/dialects/drizzle/mysqldb.py
deleted file mode 100644 (file)
index 7d91cc3..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-"""
-.. dialect:: drizzle+mysqldb
-    :name: MySQL-Python
-    :dbapi: mysqldb
-    :connectstring: drizzle+mysqldb://<user>:<password>@<host>[:<port>]/<dbname>
-    :url: http://sourceforge.net/projects/mysql-python
-
-
-"""
-
-from sqlalchemy.dialects.drizzle.base import (
-    DrizzleDialect,
-    DrizzleExecutionContext,
-    DrizzleCompiler,
-    DrizzleIdentifierPreparer)
-from sqlalchemy.connectors.mysqldb import (
-    MySQLDBExecutionContext,
-    MySQLDBCompiler,
-    MySQLDBIdentifierPreparer,
-    MySQLDBConnector)
-
-
-class DrizzleExecutionContext_mysqldb(MySQLDBExecutionContext,
-                                      DrizzleExecutionContext):
-    pass
-
-
-class DrizzleCompiler_mysqldb(MySQLDBCompiler, DrizzleCompiler):
-    pass
-
-
-class DrizzleIdentifierPreparer_mysqldb(MySQLDBIdentifierPreparer,
-                                        DrizzleIdentifierPreparer):
-    pass
-
-
-class DrizzleDialect_mysqldb(MySQLDBConnector, DrizzleDialect):
-    execution_ctx_cls = DrizzleExecutionContext_mysqldb
-    statement_compiler = DrizzleCompiler_mysqldb
-    preparer = DrizzleIdentifierPreparer_mysqldb
-
-    def _detect_charset(self, connection):
-        """Sniff out the character set in use for connection results."""
-
-        return 'utf8'
-
-
-dialect = DrizzleDialect_mysqldb
index 7fb63f13bc7595672a2f8dd7b63d3fc4bd03c72f..19e28754125139fe1b85ae263782b8b6074e3922 100644 (file)
@@ -41,44 +41,71 @@ It is strongly advised to use the latest version of MySQL-Python.
 """
 
 from .base import (MySQLDialect, MySQLExecutionContext,
-                                            MySQLCompiler, MySQLIdentifierPreparer)
-from ...connectors.mysqldb import (
-                        MySQLDBExecutionContext,
-                        MySQLDBCompiler,
-                        MySQLDBIdentifierPreparer,
-                        MySQLDBConnector
-                    )
+                                        MySQLCompiler, MySQLIdentifierPreparer)
 from .base import TEXT
 from ... import sql
+from ... import util
+import re
 
-class MySQLExecutionContext_mysqldb(MySQLDBExecutionContext, MySQLExecutionContext):
-    pass
 
+class MySQLExecutionContext_mysqldb(MySQLExecutionContext):
 
-class MySQLCompiler_mysqldb(MySQLDBCompiler, MySQLCompiler):
-    pass
+    @property
+    def rowcount(self):
+        if hasattr(self, '_rowcount'):
+            return self._rowcount
+        else:
+            return self.cursor.rowcount
+
+class MySQLCompiler_mysqldb(MySQLCompiler):
+    def visit_mod_binary(self, binary, operator, **kw):
+        return self.process(binary.left, **kw) + " %% " + \
+                    self.process(binary.right, **kw)
+
+    def post_process_text(self, text):
+        return text.replace('%', '%%')
 
+class MySQLIdentifierPreparer_mysqldb(MySQLIdentifierPreparer):
 
-class MySQLIdentifierPreparer_mysqldb(MySQLDBIdentifierPreparer, MySQLIdentifierPreparer):
-    pass
+    def _escape_identifier(self, value):
+        value = value.replace(self.escape_quote, self.escape_to_quote)
+        return value.replace("%", "%%")
 
 
-class MySQLDialect_mysqldb(MySQLDBConnector, MySQLDialect):
+class MySQLDialect_mysqldb(MySQLDialect):
+    driver = 'mysqldb'
+    supports_unicode_statements = False
+    supports_sane_rowcount = True
+    supports_sane_multi_rowcount = True
+
+    supports_native_decimal = True
+
+    default_paramstyle = 'format'
     execution_ctx_cls = MySQLExecutionContext_mysqldb
     statement_compiler = MySQLCompiler_mysqldb
     preparer = MySQLIdentifierPreparer_mysqldb
 
+
+    @classmethod
+    def dbapi(cls):
+        return __import__('MySQLdb')
+
+    def do_executemany(self, cursor, statement, parameters, context=None):
+        rowcount = cursor.executemany(statement, parameters)
+        if context is not None:
+            context._rowcount = rowcount
+
     def _check_unicode_returns(self, connection):
         # work around issue fixed in
         # https://github.com/farcepest/MySQLdb1/commit/cd44524fef63bd3fcb71947392326e9742d520e8
         # specific issue w/ the utf8_bin collation and unicode returns
 
         has_utf8_bin = connection.scalar(
-                                "show collation where %s = 'utf8' and %s = 'utf8_bin'"
-                                    % (
-                                    self.identifier_preparer.quote("Charset"),
-                                    self.identifier_preparer.quote("Collation")
-                                ))
+                        "show collation where %s = 'utf8' and %s = 'utf8_bin'"
+                            % (
+                            self.identifier_preparer.quote("Charset"),
+                            self.identifier_preparer.quote("Collation")
+                        ))
         if has_utf8_bin:
             additional_tests = [
                 sql.collate(sql.cast(
@@ -88,7 +115,83 @@ class MySQLDialect_mysqldb(MySQLDBConnector, MySQLDialect):
             ]
         else:
             additional_tests = []
-        return super(MySQLDBConnector, self)._check_unicode_returns(
+        return super(MySQLDialect_mysqldb, self)._check_unicode_returns(
                             connection, additional_tests)
 
+
+    def create_connect_args(self, url):
+        opts = url.translate_connect_args(database='db', username='user',
+                                          password='passwd')
+        opts.update(url.query)
+
+        util.coerce_kw_type(opts, 'compress', bool)
+        util.coerce_kw_type(opts, 'connect_timeout', int)
+        util.coerce_kw_type(opts, 'read_timeout', int)
+        util.coerce_kw_type(opts, 'client_flag', int)
+        util.coerce_kw_type(opts, 'local_infile', int)
+        # Note: using either of the below will cause all strings to be returned
+        # as Unicode, both in raw SQL operations and with column types like
+        # String and MSString.
+        util.coerce_kw_type(opts, 'use_unicode', bool)
+        util.coerce_kw_type(opts, 'charset', str)
+
+        # Rich values 'cursorclass' and 'conv' are not supported via
+        # query string.
+
+        ssl = {}
+        keys = ['ssl_ca', 'ssl_key', 'ssl_cert', 'ssl_capath', 'ssl_cipher']
+        for key in keys:
+            if key in opts:
+                ssl[key[4:]] = opts[key]
+                util.coerce_kw_type(ssl, key[4:], str)
+                del opts[key]
+        if ssl:
+            opts['ssl'] = ssl
+
+        # FOUND_ROWS must be set in CLIENT_FLAGS to enable
+        # supports_sane_rowcount.
+        client_flag = opts.get('client_flag', 0)
+        if self.dbapi is not None:
+            try:
+                CLIENT_FLAGS = __import__(
+                                    self.dbapi.__name__ + '.constants.CLIENT'
+                                    ).constants.CLIENT
+                client_flag |= CLIENT_FLAGS.FOUND_ROWS
+            except (AttributeError, ImportError):
+                self.supports_sane_rowcount = False
+            opts['client_flag'] = client_flag
+        return [[], opts]
+
+    def _get_server_version_info(self, connection):
+        dbapi_con = connection.connection
+        version = []
+        r = re.compile('[.\-]')
+        for n in r.split(dbapi_con.get_server_info()):
+            try:
+                version.append(int(n))
+            except ValueError:
+                version.append(n)
+        return tuple(version)
+
+    def _extract_error_code(self, exception):
+        return exception.args[0]
+
+    def _detect_charset(self, connection):
+        """Sniff out the character set in use for connection results."""
+
+        try:
+            # note: the SQL here would be
+            # "SHOW VARIABLES LIKE 'character_set%%'"
+            cset_name = connection.connection.character_set_name
+        except AttributeError:
+            util.warn(
+                "No 'character_set_name' can be detected with "
+                "this MySQL-Python version; "
+                "please upgrade to a recent version of MySQL-Python.  "
+                "Assuming latin1.")
+            return 'latin1'
+        else:
+            return cset_name()
+
+
 dialect = MySQLDialect_mysqldb