diff options
Diffstat (limited to 'lib/sqlalchemy/dialects/mysql')
| -rw-r--r-- | lib/sqlalchemy/dialects/mysql/base.py | 75 | ||||
| -rw-r--r-- | lib/sqlalchemy/dialects/mysql/mysqldb.py | 153 |
2 files changed, 59 insertions, 169 deletions
diff --git a/lib/sqlalchemy/dialects/mysql/base.py b/lib/sqlalchemy/dialects/mysql/base.py index 8b8380471..b495cc36e 100644 --- a/lib/sqlalchemy/dialects/mysql/base.py +++ b/lib/sqlalchemy/dialects/mysql/base.py @@ -81,7 +81,7 @@ foreign keys. For these tables, you may supply a autoload=True ) -When creating tables, SQLAlchemy will automatically set ``AUTO_INCREMENT``` on +When creating tables, SQLAlchemy will automatically set ``AUTO_INCREMENT`` on an integer primary key column:: >>> t = Table('mytable', metadata, @@ -152,14 +152,6 @@ available. update(..., mysql_limit=10) -Troubleshooting ---------------- - -If you have problems that seem server related, first check that you are -using the most recent stable MySQL-Python package available. The Database -Notes page on the wiki at http://www.sqlalchemy.org is a good resource for -timely information affecting MySQL in SQLAlchemy. - """ import datetime, inspect, re, sys @@ -1161,7 +1153,7 @@ class MySQLCompiler(compiler.SQLCompiler): return 'CHAR' elif isinstance(type_, sqltypes._Binary): return 'BINARY' - elif isinstance(type_, NUMERIC): + elif isinstance(type_, sqltypes.NUMERIC): return self.dialect.type_compiler.process(type_).replace('NUMERIC', 'DECIMAL') else: return None @@ -1257,7 +1249,7 @@ class MySQLCompiler(compiler.SQLCompiler): if update_stmt._whereclause is not None: text += " WHERE " + self.process(update_stmt._whereclause) - limit = update_stmt.kwargs.get('mysql_limit', None) + limit = update_stmt.kwargs.get('%s_limit' % self.dialect.name, None) if limit: text += " LIMIT %s" % limit @@ -1275,8 +1267,9 @@ class MySQLDDLCompiler(compiler.DDLCompiler): """Get table constraints.""" constraint_string = super(MySQLDDLCompiler, self).create_table_constraints(table) - is_innodb = table.kwargs.has_key('mysql_engine') and \ - table.kwargs['mysql_engine'].lower() == 'innodb' + engine_key = '%s_engine' % self.dialect.name + is_innodb = table.kwargs.has_key(engine_key) and \ + table.kwargs[engine_key].lower() == 'innodb' auto_inc_column = table._autoincrement_column @@ -1319,8 +1312,8 @@ class MySQLDDLCompiler(compiler.DDLCompiler): table_opts = [] for k in table.kwargs: - if k.startswith('mysql_'): - opt = k[6:].upper() + if k.startswith('%s_' % self.dialect.name): + opt = k[len(self.dialect.name)+1:].upper() arg = table.kwargs[k] if opt in _options_of_type_string: @@ -1417,17 +1410,25 @@ class MySQLTypeCompiler(compiler.GenericTypeCompiler): if type_.precision is None: return self._extend_numeric(type_, "NUMERIC") elif type_.scale is None: - return self._extend_numeric(type_, "NUMERIC(%(precision)s)" % {'precision': type_.precision}) + return self._extend_numeric(type_, + "NUMERIC(%(precision)s)" % + {'precision': type_.precision}) else: - return self._extend_numeric(type_, "NUMERIC(%(precision)s, %(scale)s)" % {'precision': type_.precision, 'scale' : type_.scale}) + return self._extend_numeric(type_, + "NUMERIC(%(precision)s, %(scale)s)" % + {'precision': type_.precision, 'scale' : type_.scale}) def visit_DECIMAL(self, type_): if type_.precision is None: return self._extend_numeric(type_, "DECIMAL") elif type_.scale is None: - return self._extend_numeric(type_, "DECIMAL(%(precision)s)" % {'precision': type_.precision}) + return self._extend_numeric(type_, + "DECIMAL(%(precision)s)" % + {'precision': type_.precision}) else: - return self._extend_numeric(type_, "DECIMAL(%(precision)s, %(scale)s)" % {'precision': type_.precision, 'scale' : type_.scale}) + return self._extend_numeric(type_, + "DECIMAL(%(precision)s, %(scale)s)" % + {'precision': type_.precision, 'scale' : type_.scale}) def visit_DOUBLE(self, type_): if type_.precision is not None and type_.scale is not None: @@ -1446,8 +1447,11 @@ class MySQLTypeCompiler(compiler.GenericTypeCompiler): return self._extend_numeric(type_, 'REAL') def visit_FLOAT(self, type_): - if self._mysql_type(type_) and type_.scale is not None and type_.precision is not None: - return self._extend_numeric(type_, "FLOAT(%s, %s)" % (type_.precision, type_.scale)) + if self._mysql_type(type_) and \ + type_.scale is not None and \ + type_.precision is not None: + return self._extend_numeric(type_, + "FLOAT(%s, %s)" % (type_.precision, type_.scale)) elif type_.precision is not None: return self._extend_numeric(type_, "FLOAT(%s)" % (type_.precision,)) else: @@ -1455,19 +1459,25 @@ class MySQLTypeCompiler(compiler.GenericTypeCompiler): def visit_INTEGER(self, type_): if self._mysql_type(type_) and type_.display_width is not None: - return self._extend_numeric(type_, "INTEGER(%(display_width)s)" % {'display_width': type_.display_width}) + return self._extend_numeric(type_, + "INTEGER(%(display_width)s)" % + {'display_width': type_.display_width}) else: return self._extend_numeric(type_, "INTEGER") def visit_BIGINT(self, type_): if self._mysql_type(type_) and type_.display_width is not None: - return self._extend_numeric(type_, "BIGINT(%(display_width)s)" % {'display_width': type_.display_width}) + return self._extend_numeric(type_, + "BIGINT(%(display_width)s)" % + {'display_width': type_.display_width}) else: return self._extend_numeric(type_, "BIGINT") def visit_MEDIUMINT(self, type_): if self._mysql_type(type_) and type_.display_width is not None: - return self._extend_numeric(type_, "MEDIUMINT(%(display_width)s)" % {'display_width': type_.display_width}) + return self._extend_numeric(type_, + "MEDIUMINT(%(display_width)s)" % + {'display_width': type_.display_width}) else: return self._extend_numeric(type_, "MEDIUMINT") @@ -1479,7 +1489,10 @@ class MySQLTypeCompiler(compiler.GenericTypeCompiler): def visit_SMALLINT(self, type_): if self._mysql_type(type_) and type_.display_width is not None: - return self._extend_numeric(type_, "SMALLINT(%(display_width)s)" % {'display_width': type_.display_width}) + return self._extend_numeric(type_, + "SMALLINT(%(display_width)s)" % + {'display_width': type_.display_width} + ) else: return self._extend_numeric(type_, "SMALLINT") @@ -1526,7 +1539,9 @@ class MySQLTypeCompiler(compiler.GenericTypeCompiler): if type_.length: return self._extend_string(type_, {}, "VARCHAR(%d)" % type_.length) else: - raise exc.InvalidRequestError("VARCHAR requires a length when rendered on MySQL") + raise exc.InvalidRequestError( + "VARCHAR requires a length on dialect %s" % + self.dialect.name) def visit_CHAR(self, type_): if type_.length: @@ -1540,7 +1555,9 @@ class MySQLTypeCompiler(compiler.GenericTypeCompiler): if type_.length: return self._extend_string(type_, {'national':True}, "VARCHAR(%(length)s)" % {'length': type_.length}) else: - raise exc.InvalidRequestError("NVARCHAR requires a length when rendered on MySQL") + raise exc.InvalidRequestError( + "NVARCHAR requires a length on dialect %s" % + self.dialect.name) def visit_NCHAR(self, type_): # We'll actually generate the equiv. "NATIONAL CHAR" instead of "NCHAR". @@ -2090,7 +2107,7 @@ class MySQLTableDefinitionParser(object): self.dialect = dialect self.preparer = preparer self._prep_regexes() - + def parse(self, show_create, charset): state = ReflectedState() state.charset = charset @@ -2194,7 +2211,7 @@ class MySQLTableDefinitionParser(object): options.pop(nope, None) for opt, val in options.items(): - state.table_options['mysql_%s' % opt] = val + state.table_options['%s_%s' % (self.dialect.name, opt)] = val def _parse_column(self, line, state): """Extract column details. diff --git a/lib/sqlalchemy/dialects/mysql/mysqldb.py b/lib/sqlalchemy/dialects/mysql/mysqldb.py index e9e1cdbba..003502b13 100644 --- a/lib/sqlalchemy/dialects/mysql/mysqldb.py +++ b/lib/sqlalchemy/dialects/mysql/mysqldb.py @@ -50,156 +50,29 @@ The recommended connection form with SQLAlchemy is:: """ -import re - from sqlalchemy.dialects.mysql.base import (MySQLDialect, MySQLExecutionContext, MySQLCompiler, MySQLIdentifierPreparer) -from sqlalchemy.engine import base as engine_base, default -from sqlalchemy.sql import operators as sql_operators -from sqlalchemy import exc, log, schema, sql, types as sqltypes, util -from sqlalchemy import processors - -class MySQLExecutionContext_mysqldb(MySQLExecutionContext): - - @property - def rowcount(self): - if hasattr(self, '_rowcount'): - return self._rowcount - else: - return self.cursor.rowcount - +from sqlalchemy.connectors.mysqldb import ( + MySQLDBExecutionContext, + MySQLDBCompiler, + MySQLDBIdentifierPreparer, + MySQLDBConnector + ) -class MySQLCompiler_mysqldb(MySQLCompiler): - def visit_mod(self, binary, **kw): - return self.process(binary.left) + " %% " + self.process(binary.right) +class MySQLExecutionContext_mysqldb(MySQLDBExecutionContext, MySQLExecutionContext): + pass - def post_process_text(self, text): - return text.replace('%', '%%') +class MySQLCompiler_mysqldb(MySQLDBCompiler, MySQLCompiler): + pass -class MySQLIdentifierPreparer_mysqldb(MySQLIdentifierPreparer): - def _escape_identifier(self, value): - value = value.replace(self.escape_quote, self.escape_to_quote) - return value.replace("%", "%%") +class MySQLIdentifierPreparer_mysqldb(MySQLDBIdentifierPreparer, MySQLIdentifierPreparer): + pass -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' +class MySQLDialect_mysqldb(MySQLDBConnector, MySQLDialect): execution_ctx_cls = MySQLExecutionContext_mysqldb statement_compiler = MySQLCompiler_mysqldb preparer = MySQLIdentifierPreparer_mysqldb - colspecs = util.update_copy( - MySQLDialect.colspecs, - { - } - ) - - @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 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, '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 = {} - for key in ['ssl_ca', 'ssl_key', 'ssl_cert', 'ssl_capath', 'ssl_cipher']: - 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: - from MySQLdb.constants import CLIENT as CLIENT_FLAGS - client_flag |= CLIENT_FLAGS.FOUND_ROWS - except: - pass - 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.""" - - # Note: MySQL-python 1.2.1c7 seems to ignore changes made - # on a connection via set_character_set() - if self.server_version_info < (4, 1, 0): - try: - return connection.connection.character_set_name() - except AttributeError: - # < 1.2.1 final MySQL-python drivers have no charset support. - # a query is needed. - pass - - # Prefer 'character_set_results' for the current connection over the - # value in the driver. SET NAMES or individual variable SETs will - # change the charset without updating the driver's view of the world. - # - # If it's decided that issuing that sort of SQL leaves you SOL, then - # this can prefer the driver value. - rs = connection.execute("SHOW VARIABLES LIKE 'character_set%%'") - opts = dict([(row[0], row[1]) for row in self._compat_fetchall(rs)]) - - if 'character_set_results' in opts: - return opts['character_set_results'] - try: - return connection.connection.character_set_name() - except AttributeError: - # Still no charset on < 1.2.1 final... - if 'character_set' in opts: - return opts['character_set'] - else: - util.warn( - "Could not detect the connection character set with this " - "combination of MySQL server and MySQL-python. " - "MySQL-python >= 1.2.2 is recommended. Assuming latin1.") - return 'latin1' - - dialect = MySQLDialect_mysqldb |
