From d9388a51944e1c5bb389a33a2cd824a7e8672115 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Sun, 22 Nov 2009 22:11:41 +0000 Subject: [PATCH] - VARCHAR/NVARCHAR will not render without a length, raises an error before passing to MySQL. Doesn't impact CAST since VARCHAR is not allowed in MySQL CAST anyway, the dialect renders CHAR/NCHAR in those cases. [ticket:1252] --- CHANGES | 5 +++++ lib/sqlalchemy/dialects/mysql/base.py | 19 ++++++++++++++----- test/dialect/test_mysql.py | 17 +++++++++++++++-- test/sql/test_types.py | 6 +++--- 4 files changed, 37 insertions(+), 10 deletions(-) diff --git a/CHANGES b/CHANGES index 989e6145d1..0f19a1f0e4 100644 --- a/CHANGES +++ b/CHANGES @@ -513,6 +513,11 @@ CHANGES - New dialects: oursql, a new native dialect, MySQL Connector/Python, a native Python port of MySQLdb, and of course zxjdbc on Jython. + + - VARCHAR/NVARCHAR will not render without a length, raises + an error before passing to MySQL. Doesn't impact + CAST since VARCHAR is not allowed in MySQL CAST anyway, + the dialect renders CHAR/NCHAR in those cases. - all the _detect_XXX() functions now run once underneath dialect.initialize() diff --git a/lib/sqlalchemy/dialects/mysql/base.py b/lib/sqlalchemy/dialects/mysql/base.py index a9acc2a013..d5ee4f5bb4 100644 --- a/lib/sqlalchemy/dialects/mysql/base.py +++ b/lib/sqlalchemy/dialects/mysql/base.py @@ -1561,19 +1561,28 @@ class MySQLTypeCompiler(compiler.GenericTypeCompiler): if type_.length: return self._extend_string(type_, {}, "VARCHAR(%d)" % type_.length) else: - return self._extend_string(type_, {}, "VARCHAR") + raise exc.InvalidRequestError("VARCHAR requires a length when rendered on MySQL") def visit_CHAR(self, type_): - return self._extend_string(type_, {'national':True}, "CHAR(%(length)s)" % {'length' : type_.length}) - + if type_.length: + return self._extend_string(type_, {}, "CHAR(%(length)s)" % {'length' : type_.length}) + else: + return self._extend_string(type_, {}, "CHAR") + def visit_NVARCHAR(self, type_): # We'll actually generate the equiv. "NATIONAL VARCHAR" instead # of "NVARCHAR". - return self._extend_string(type_, {'national':True}, "VARCHAR(%(length)s)" % {'length': type_.length}) + 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") def visit_NCHAR(self, type_): # We'll actually generate the equiv. "NATIONAL CHAR" instead of "NCHAR". - return self._extend_string(type_, {'national':True}, "CHAR(%(length)s)" % {'length': type_.length}) + if type_.length: + return self._extend_string(type_, {'national':True}, "CHAR(%(length)s)" % {'length': type_.length}) + else: + return self._extend_string(type_, {'national':True}, "CHAR") def visit_VARBINARY(self, type_): if type_.length: diff --git a/test/dialect/test_mysql.py b/test/dialect/test_mysql.py index b65ab6312d..325f518daa 100644 --- a/test/dialect/test_mysql.py +++ b/test/dialect/test_mysql.py @@ -7,7 +7,7 @@ import sets # end Py2K from sqlalchemy import * -from sqlalchemy import sql, exc, schema +from sqlalchemy import sql, exc, schema, types as sqltypes from sqlalchemy.dialects.mysql import base as mysql from sqlalchemy.test.testing import eq_ from sqlalchemy.test import * @@ -948,7 +948,20 @@ class SQLTest(TestBase, AssertsCompiledSQL): select([t]).offset(10), "SELECT t.col1, t.col2 FROM t LIMIT 10, 18446744073709551615" ) - + + def test_varchar_raise(self): + for type_ in ( + String, + VARCHAR, + String(), + VARCHAR(), + NVARCHAR(), + Unicode, + Unicode(), + ): + type_ = sqltypes.to_instance(type_) + assert_raises(exc.InvalidRequestError, type_.compile, dialect=mysql.dialect()) + def test_update_limit(self): t = sql.table('t', sql.column('col1'), sql.column('col2')) diff --git a/test/sql/test_types.py b/test/sql/test_types.py index 332e02ef5f..04c193e01f 100644 --- a/test/sql/test_types.py +++ b/test/sql/test_types.py @@ -42,8 +42,8 @@ class AdaptTest(TestBase): (DATE, "DATE"), (TIME, "TIME"), (CLOB, "CLOB"), - (VARCHAR, "VARCHAR"), - (NVARCHAR, ("NVARCHAR", "NATIONAL VARCHAR")), + (VARCHAR(10), "VARCHAR(10)"), + (NVARCHAR(10), ("NVARCHAR(10)", "NATIONAL VARCHAR(10)", "NVARCHAR2(10)")), (CHAR, "CHAR"), (NCHAR, ("NCHAR", "NATIONAL CHAR")), (BLOB, "BLOB"), @@ -52,7 +52,7 @@ class AdaptTest(TestBase): if isinstance(expected, str): expected = (expected, ) for exp in expected: - compiled = type_().compile(dialect=dialect) + compiled = types.to_instance(type_).compile(dialect=dialect) if exp in compiled: break else: -- 2.47.3