From d03b5327b778434884b1884c28173e24f08ade61 Mon Sep 17 00:00:00 2001 From: Jason Kirtland Date: Wed, 2 May 2007 00:41:52 +0000 Subject: [PATCH] - MySQL ENUM types can now optionally ensure that values are within the enum's allowed range on insert and update, with strict=True - Added new 'dialect' category of unit tests, and migrated MySQL-specific dialect tests there. - Noted the max identifier length in the MySQL dialect (the max alias length, actually) --- lib/sqlalchemy/databases/mysql.py | 61 ++++++- test/alltests.py | 3 +- test/dialect/__init__.py | 0 test/dialect/alltests.py | 19 +++ test/dialect/mysql.py | 268 ++++++++++++++++++++++++++++++ test/sql/testtypes.py | 196 ---------------------- 6 files changed, 345 insertions(+), 202 deletions(-) create mode 100644 test/dialect/__init__.py create mode 100644 test/dialect/alltests.py create mode 100644 test/dialect/mysql.py diff --git a/lib/sqlalchemy/databases/mysql.py b/lib/sqlalchemy/databases/mysql.py index 42a755f175..d7f65b80b1 100644 --- a/lib/sqlalchemy/databases/mysql.py +++ b/lib/sqlalchemy/databases/mysql.py @@ -265,21 +265,68 @@ class MSMediumBlob(MSBinary): return "MEDIUMBLOB" class MSEnum(MSString): + """MySQL ENUM datatype.""" + def __init__(self, *enums, **kw): - self.__enums_hidden = enums - length = 0 + """ + Construct an ENUM. + + Example: + Column('myenum', MSEnum("'foo'", "'bar'", "'baz'")) + Column('another', MSEnum("'foo'", "'bar'", "'baz'", strict=True)) + + Arguments are: + + enums + The range of valid values for this ENUM. Values will be used + exactly as they appear when generating schemas + + strict + Defaults to False: ensure that a given value is in this ENUM's + range of permissible value when inserting or updating rows. + + charset + Defaults to None: a column-level character set for this string + value. Takes precendence to 'ascii' or 'unicode' short-hand. + + collation + Defaults to None: a column-level collation for this string value. + Takes precedence to 'binary' short-hand. + + ascii + Defaults to False: short-hand for the ascii character set, + generates ASCII in schema. + + unicode + Defaults to False: short-hand for the utf8 character set, + generates UNICODE in schema. + + binary + Defaults to False: short-hand, pick the binary collation type + that matches the column's character set. Generates BINARY in schema. + """ + + self.__ddl_values = enums + strip_enums = [] for a in enums: if a[0:1] == '"' or a[0:1] == "'": a = a[1:-1] - if len(a) > length: - length=len(a) strip_enums.append(a) + self.enums = strip_enums + self.strict = kw.pop('strict', False) + length = max([len(v) for v in strip_enums]) super(MSEnum, self).__init__(length, **kw) + def convert_bind_param(self, value, engine): + if self.strict and value is not None and value not in self.enums: + raise exceptions.InvalidRequestError('"%s" not a valid value for ' + 'this enum' % value) + return super(MSEnum, self).convert_bind_param(value, engine) + def get_col_spec(self): - return self._extend("ENUM(%s)" % ",".join(self.__enums_hidden)) + return self._extend("ENUM(%s)" % ",".join(self.__ddl_values)) class MSBoolean(sqltypes.Boolean): def get_col_spec(self): @@ -407,6 +454,10 @@ class MySQLDialect(ansisql.ANSIDialect): def type_descriptor(self, typeobj): return sqltypes.adapt_type(typeobj, colspecs) + # identifiers are 64, however aliases can be 255... + def max_identifier_length(self): + return 255; + def supports_sane_rowcount(self): return True diff --git a/test/alltests.py b/test/alltests.py index 3fbace0160..e3266f5632 100644 --- a/test/alltests.py +++ b/test/alltests.py @@ -5,12 +5,13 @@ import orm.alltests as orm import base.alltests as base import sql.alltests as sql import engine.alltests as engine +import dialect.alltests as dialect import ext.alltests as ext import zblog.alltests as zblog def suite(): alltests = unittest.TestSuite() - for suite in (base, engine, sql, orm, ext, zblog): + for suite in (base, engine, sql, dialect, orm, ext, zblog): alltests.addTest(suite.suite()) return alltests diff --git a/test/dialect/__init__.py b/test/dialect/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/dialect/alltests.py b/test/dialect/alltests.py new file mode 100644 index 0000000000..6a11b85a3f --- /dev/null +++ b/test/dialect/alltests.py @@ -0,0 +1,19 @@ +import testbase +import unittest + +def suite(): + modules_to_test = ( + 'dialect.mysql', + ) + alltests = unittest.TestSuite() + for name in modules_to_test: + mod = __import__(name) + for token in name.split('.')[1:]: + mod = getattr(mod, token) + alltests.addTest(unittest.findTestCases(mod, suiteClass=None)) + return alltests + + + +if __name__ == '__main__': + testbase.main(suite()) diff --git a/test/dialect/mysql.py b/test/dialect/mysql.py new file mode 100644 index 0000000000..63df5dd139 --- /dev/null +++ b/test/dialect/mysql.py @@ -0,0 +1,268 @@ +from testbase import PersistTest, AssertMixin +import testbase +from sqlalchemy import * +from sqlalchemy.databases import mysql +import sys, StringIO + +db = testbase.db + +class TypesTest(AssertMixin): + "Test MySQL column types" + + @testbase.supported('mysql') + def test_numeric(self): + "Exercise type specification and options for numeric types." + + columns = [ + # column type, args, kwargs, expected ddl + # e.g. Column(Integer(10, unsigned=True)) == 'INTEGER(10) UNSIGNED' + (mysql.MSNumeric, [], {}, + 'NUMERIC(10, 2)'), + (mysql.MSNumeric, [None], {}, + 'NUMERIC'), + (mysql.MSNumeric, [12], {}, + 'NUMERIC(12, 2)'), + (mysql.MSNumeric, [12, 4], {'unsigned':True}, + 'NUMERIC(12, 4) UNSIGNED'), + (mysql.MSNumeric, [12, 4], {'zerofill':True}, + 'NUMERIC(12, 4) ZEROFILL'), + (mysql.MSNumeric, [12, 4], {'zerofill':True, 'unsigned':True}, + 'NUMERIC(12, 4) UNSIGNED ZEROFILL'), + + (mysql.MSDecimal, [], {}, + 'DECIMAL(10, 2)'), + (mysql.MSDecimal, [None], {}, + 'DECIMAL'), + (mysql.MSDecimal, [12], {}, + 'DECIMAL(12, 2)'), + (mysql.MSDecimal, [12, None], {}, + 'DECIMAL(12)'), + (mysql.MSDecimal, [12, 4], {'unsigned':True}, + 'DECIMAL(12, 4) UNSIGNED'), + (mysql.MSDecimal, [12, 4], {'zerofill':True}, + 'DECIMAL(12, 4) ZEROFILL'), + (mysql.MSDecimal, [12, 4], {'zerofill':True, 'unsigned':True}, + 'DECIMAL(12, 4) UNSIGNED ZEROFILL'), + + (mysql.MSDouble, [None, None], {}, + 'DOUBLE'), + (mysql.MSDouble, [12], {}, + 'DOUBLE(12, 2)'), + (mysql.MSDouble, [12, 4], {'unsigned':True}, + 'DOUBLE(12, 4) UNSIGNED'), + (mysql.MSDouble, [12, 4], {'zerofill':True}, + 'DOUBLE(12, 4) ZEROFILL'), + (mysql.MSDouble, [12, 4], {'zerofill':True, 'unsigned':True}, + 'DOUBLE(12, 4) UNSIGNED ZEROFILL'), + + (mysql.MSFloat, [], {}, + 'FLOAT(10)'), + (mysql.MSFloat, [None], {}, + 'FLOAT'), + (mysql.MSFloat, [12], {}, + 'FLOAT(12)'), + (mysql.MSFloat, [12, 4], {}, + 'FLOAT(12, 4)'), + (mysql.MSFloat, [12, 4], {'unsigned':True}, + 'FLOAT(12, 4) UNSIGNED'), + (mysql.MSFloat, [12, 4], {'zerofill':True}, + 'FLOAT(12, 4) ZEROFILL'), + (mysql.MSFloat, [12, 4], {'zerofill':True, 'unsigned':True}, + 'FLOAT(12, 4) UNSIGNED ZEROFILL'), + + (mysql.MSInteger, [], {}, + 'INTEGER'), + (mysql.MSInteger, [4], {}, + 'INTEGER(4)'), + (mysql.MSInteger, [4], {'unsigned':True}, + 'INTEGER(4) UNSIGNED'), + (mysql.MSInteger, [4], {'zerofill':True}, + 'INTEGER(4) ZEROFILL'), + (mysql.MSInteger, [4], {'zerofill':True, 'unsigned':True}, + 'INTEGER(4) UNSIGNED ZEROFILL'), + + (mysql.MSBigInteger, [], {}, + 'BIGINT'), + (mysql.MSBigInteger, [4], {}, + 'BIGINT(4)'), + (mysql.MSBigInteger, [4], {'unsigned':True}, + 'BIGINT(4) UNSIGNED'), + (mysql.MSBigInteger, [4], {'zerofill':True}, + 'BIGINT(4) ZEROFILL'), + (mysql.MSBigInteger, [4], {'zerofill':True, 'unsigned':True}, + 'BIGINT(4) UNSIGNED ZEROFILL'), + + (mysql.MSSmallInteger, [], {}, + 'SMALLINT'), + (mysql.MSSmallInteger, [4], {}, + 'SMALLINT(4)'), + (mysql.MSSmallInteger, [4], {'unsigned':True}, + 'SMALLINT(4) UNSIGNED'), + (mysql.MSSmallInteger, [4], {'zerofill':True}, + 'SMALLINT(4) ZEROFILL'), + (mysql.MSSmallInteger, [4], {'zerofill':True, 'unsigned':True}, + 'SMALLINT(4) UNSIGNED ZEROFILL'), + ] + + table_args = ['test_mysql_numeric', db] + for index, spec in enumerate(columns): + type_, args, kw, res = spec + table_args.append(Column('c%s' % index, type_(*args, **kw))) + + numeric_table = Table(*table_args) + gen = db.dialect.schemagenerator(db, None, None) + + for col in numeric_table.c: + index = int(col.name[1:]) + self.assertEquals(gen.get_column_specification(col), + "%s %s" % (col.name, columns[index][3])) + + try: + numeric_table.create(checkfirst=True) + assert True + except: + raise + numeric_table.drop() + + @testbase.supported('mysql') + def test_charset(self): + """Exercise CHARACTER SET and COLLATE-related options on string-type + columns.""" + + columns = [ + (mysql.MSChar, [1], {}, + 'CHAR(1)'), + (mysql.MSChar, [1], {'binary':True}, + 'CHAR(1) BINARY'), + (mysql.MSChar, [1], {'ascii':True}, + 'CHAR(1) ASCII'), + (mysql.MSChar, [1], {'unicode':True}, + 'CHAR(1) UNICODE'), + (mysql.MSChar, [1], {'ascii':True, 'binary':True}, + 'CHAR(1) ASCII BINARY'), + (mysql.MSChar, [1], {'unicode':True, 'binary':True}, + 'CHAR(1) UNICODE BINARY'), + (mysql.MSChar, [1], {'charset':'utf8'}, + 'CHAR(1) CHARACTER SET utf8'), + (mysql.MSChar, [1], {'charset':'utf8', 'binary':True}, + 'CHAR(1) CHARACTER SET utf8 BINARY'), + (mysql.MSChar, [1], {'charset':'utf8', 'unicode':True}, + 'CHAR(1) CHARACTER SET utf8'), + (mysql.MSChar, [1], {'charset':'utf8', 'ascii':True}, + 'CHAR(1) CHARACTER SET utf8'), + (mysql.MSChar, [1], {'collation': 'utf8_bin'}, + 'CHAR(1) COLLATE utf8_bin'), + (mysql.MSChar, [1], {'charset': 'utf8', 'collation': 'utf8_bin'}, + 'CHAR(1) CHARACTER SET utf8 COLLATE utf8_bin'), + (mysql.MSChar, [1], {'charset': 'utf8', 'binary': True}, + 'CHAR(1) CHARACTER SET utf8 BINARY'), + (mysql.MSChar, [1], {'charset': 'utf8', 'collation': 'utf8_bin', + 'binary': True}, + 'CHAR(1) CHARACTER SET utf8 COLLATE utf8_bin'), + (mysql.MSChar, [1], {'national':True}, + 'NATIONAL CHAR(1)'), + (mysql.MSChar, [1], {'national':True, 'charset':'utf8'}, + 'NATIONAL CHAR(1)'), + (mysql.MSChar, [1], {'national':True, 'charset':'utf8', 'binary':True}, + 'NATIONAL CHAR(1) BINARY'), + (mysql.MSChar, [1], {'national':True, 'binary':True, 'unicode':True}, + 'NATIONAL CHAR(1) BINARY'), + (mysql.MSChar, [1], {'national':True, 'collation':'utf8_bin'}, + 'NATIONAL CHAR(1) COLLATE utf8_bin'), + + (mysql.MSString, [1], {'charset':'utf8', 'collation':'utf8_bin'}, + 'VARCHAR(1) CHARACTER SET utf8 COLLATE utf8_bin'), + (mysql.MSString, [1], {'national':True, 'collation':'utf8_bin'}, + 'NATIONAL VARCHAR(1) COLLATE utf8_bin'), + + (mysql.MSTinyText, [], {'charset':'utf8', 'collation':'utf8_bin'}, + 'TINYTEXT CHARACTER SET utf8 COLLATE utf8_bin'), + + (mysql.MSMediumText, [], {'charset':'utf8', 'binary':True}, + 'MEDIUMTEXT CHARACTER SET utf8 BINARY'), + + (mysql.MSLongText, [], {'ascii':True}, + 'LONGTEXT ASCII'), + + (mysql.MSEnum, ["'foo'", "'bar'"], {'unicode':True}, + '''ENUM('foo','bar') UNICODE''') + ] + + table_args = ['test_mysql_charset', db] + for index, spec in enumerate(columns): + type_, args, kw, res = spec + table_args.append(Column('c%s' % index, type_(*args, **kw))) + + charset_table = Table(*table_args) + gen = db.dialect.schemagenerator(db, None, None) + + for col in charset_table.c: + index = int(col.name[1:]) + self.assertEquals(gen.get_column_specification(col), + "%s %s" % (col.name, columns[index][3])) + + try: + charset_table.create(checkfirst=True) + assert True + except: + raise + charset_table.drop() + + @testbase.supported('mysql') + def test_enum(self): + "Exercise the ENUM type" + + enum_table = Table('mysql_enum', db, + Column('e1', mysql.MSEnum('"a"', "'b'")), + Column('e2', mysql.MSEnum('"a"', "'b'"), nullable=False), + Column('e3', mysql.MSEnum('"a"', "'b'", strict=True)), + Column('e4', mysql.MSEnum('"a"', "'b'", strict=True), nullable=False)) + spec = lambda c: db.dialect.schemagenerator(db, None, None).get_column_specification(c) + + self.assertEqual(spec(enum_table.c.e1), """e1 ENUM("a",'b')""") + self.assertEqual(spec(enum_table.c.e2), """e2 ENUM("a",'b') NOT NULL""") + self.assertEqual(spec(enum_table.c.e3), """e3 ENUM("a",'b')""") + self.assertEqual(spec(enum_table.c.e4), """e4 ENUM("a",'b') NOT NULL""") + enum_table.drop() + enum_table.create() + + try: + enum_table.insert().execute(e1=None, e2=None, e3=None, e4=None) + self.assert_(False) + except exceptions.SQLError: + self.assert_(True) + + try: + enum_table.insert().execute(e1='c', e2='c', e3='c', e4='c') + self.assert_(False) + except exceptions.InvalidRequestError: + self.assert_(True) + + enum_table.insert().execute() + enum_table.insert().execute(e1='a', e2='a', e3='a', e4='a') + enum_table.insert().execute(e1='b', e2='b', e3='b', e4='b') + + # Insert out of range enums, push stderr aside to avoid expected + # warnings cluttering test output + try: + aside = sys.stderr + sys.stderr = StringIO.StringIO() + + con = db.connect() + self.assert_(not con.connection.show_warnings()) + con.execute(insert(enum_table, {'e1':'c', 'e2':'c', + 'e3':'a', 'e4':'a'})) + self.assert_(con.connection.show_warnings()) + finally: + sys.stderr = aside + + res = enum_table.select().execute().fetchall() + + # This is known to fail with MySQLDB versions < 1.2.2 + self.assertEqual(res, [(None, 'a', None, 'a'), + ('a', 'a', 'a', 'a'), + ('b', 'b', 'b', 'b'), + ('', '', 'a', 'a')]) + +if __name__ == "__main__": + testbase.main() diff --git a/test/sql/testtypes.py b/test/sql/testtypes.py index b23b77d4ed..676cd8e3f0 100644 --- a/test/sql/testtypes.py +++ b/test/sql/testtypes.py @@ -134,202 +134,6 @@ class ColumnsTest(AssertMixin): for aCol in testTable.c: self.assertEquals(expectedResults[aCol.name], db.dialect.schemagenerator(db, None, None).get_column_specification(aCol)) - - @testbase.supported('mysql') - def test_mysql_numeric(self): - import sqlalchemy.databases.mysql as my - - columns = [ - # column type, args, kwargs, expected ddl - # e.g. Column(Integer(10, unsigned=True)) == 'INTEGER(10) UNSIGNED' - (my.MSNumeric, [], {}, - 'NUMERIC(10, 2)'), - (my.MSNumeric, [None], {}, - 'NUMERIC'), - (my.MSNumeric, [12], {}, - 'NUMERIC(12, 2)'), - (my.MSNumeric, [12, 4], {'unsigned':True}, - 'NUMERIC(12, 4) UNSIGNED'), - (my.MSNumeric, [12, 4], {'zerofill':True}, - 'NUMERIC(12, 4) ZEROFILL'), - (my.MSNumeric, [12, 4], {'zerofill':True, 'unsigned':True}, - 'NUMERIC(12, 4) UNSIGNED ZEROFILL'), - - (my.MSDecimal, [], {}, - 'DECIMAL(10, 2)'), - (my.MSDecimal, [None], {}, - 'DECIMAL'), - (my.MSDecimal, [12], {}, - 'DECIMAL(12, 2)'), - (my.MSDecimal, [12, None], {}, - 'DECIMAL(12)'), - (my.MSDecimal, [12, 4], {'unsigned':True}, - 'DECIMAL(12, 4) UNSIGNED'), - (my.MSDecimal, [12, 4], {'zerofill':True}, - 'DECIMAL(12, 4) ZEROFILL'), - (my.MSDecimal, [12, 4], {'zerofill':True, 'unsigned':True}, - 'DECIMAL(12, 4) UNSIGNED ZEROFILL'), - - (my.MSDouble, [None, None], {}, - 'DOUBLE'), - (my.MSDouble, [12], {}, - 'DOUBLE(12, 2)'), - (my.MSDouble, [12, 4], {'unsigned':True}, - 'DOUBLE(12, 4) UNSIGNED'), - (my.MSDouble, [12, 4], {'zerofill':True}, - 'DOUBLE(12, 4) ZEROFILL'), - (my.MSDouble, [12, 4], {'zerofill':True, 'unsigned':True}, - 'DOUBLE(12, 4) UNSIGNED ZEROFILL'), - - (my.MSFloat, [], {}, - 'FLOAT(10)'), - (my.MSFloat, [None], {}, - 'FLOAT'), - (my.MSFloat, [12], {}, - 'FLOAT(12)'), - (my.MSFloat, [12, 4], {}, - 'FLOAT(12, 4)'), - (my.MSFloat, [12, 4], {'unsigned':True}, - 'FLOAT(12, 4) UNSIGNED'), - (my.MSFloat, [12, 4], {'zerofill':True}, - 'FLOAT(12, 4) ZEROFILL'), - (my.MSFloat, [12, 4], {'zerofill':True, 'unsigned':True}, - 'FLOAT(12, 4) UNSIGNED ZEROFILL'), - - (my.MSInteger, [], {}, - 'INTEGER'), - (my.MSInteger, [4], {}, - 'INTEGER(4)'), - (my.MSInteger, [4], {'unsigned':True}, - 'INTEGER(4) UNSIGNED'), - (my.MSInteger, [4], {'zerofill':True}, - 'INTEGER(4) ZEROFILL'), - (my.MSInteger, [4], {'zerofill':True, 'unsigned':True}, - 'INTEGER(4) UNSIGNED ZEROFILL'), - - (my.MSBigInteger, [], {}, - 'BIGINT'), - (my.MSBigInteger, [4], {}, - 'BIGINT(4)'), - (my.MSBigInteger, [4], {'unsigned':True}, - 'BIGINT(4) UNSIGNED'), - (my.MSBigInteger, [4], {'zerofill':True}, - 'BIGINT(4) ZEROFILL'), - (my.MSBigInteger, [4], {'zerofill':True, 'unsigned':True}, - 'BIGINT(4) UNSIGNED ZEROFILL'), - - (my.MSSmallInteger, [], {}, - 'SMALLINT'), - (my.MSSmallInteger, [4], {}, - 'SMALLINT(4)'), - (my.MSSmallInteger, [4], {'unsigned':True}, - 'SMALLINT(4) UNSIGNED'), - (my.MSSmallInteger, [4], {'zerofill':True}, - 'SMALLINT(4) ZEROFILL'), - (my.MSSmallInteger, [4], {'zerofill':True, 'unsigned':True}, - 'SMALLINT(4) UNSIGNED ZEROFILL'), - ] - - table_args = ['testMyNumeric', db] - for index, spec in enumerate(columns): - type_, args, kw, res = spec - table_args.append(Column('c%s' % index, type_(*args, **kw))) - - numeric_table = Table(*table_args) - gen = db.dialect.schemagenerator(db, None, None) - - for col in numeric_table.c: - index = int(col.name[1:]) - self.assertEquals(gen.get_column_specification(col), - "%s %s" % (col.name, columns[index][3])) - - try: - numeric_table.create(checkfirst=True) - assert True - except: - raise - numeric_table.drop() - - -class CharsetTest(AssertMixin): - - @testbase.supported('mysql') - def testcharset(self): - import sqlalchemy.databases.mysql as my - - columns = [ - (my.MSChar, [1], {}, - 'CHAR(1)'), - (my.MSChar, [1], {'binary':True}, - 'CHAR(1) BINARY'), - (my.MSChar, [1], {'ascii':True}, - 'CHAR(1) ASCII'), - (my.MSChar, [1], {'unicode':True}, - 'CHAR(1) UNICODE'), - (my.MSChar, [1], {'ascii':True, 'binary':True}, - 'CHAR(1) ASCII BINARY'), - (my.MSChar, [1], {'unicode':True, 'binary':True}, - 'CHAR(1) UNICODE BINARY'), - (my.MSChar, [1], {'charset':'utf8'}, - 'CHAR(1) CHARACTER SET utf8'), - (my.MSChar, [1], {'charset':'utf8', 'binary':True}, - 'CHAR(1) CHARACTER SET utf8 BINARY'), - (my.MSChar, [1], {'charset':'utf8', 'unicode':True}, - 'CHAR(1) CHARACTER SET utf8'), - (my.MSChar, [1], {'charset':'utf8', 'ascii':True}, - 'CHAR(1) CHARACTER SET utf8'), - (my.MSChar, [1], {'collation': 'utf8_bin'}, - 'CHAR(1) COLLATE utf8_bin'), - (my.MSChar, [1], {'charset': 'utf8', 'collation': 'utf8_bin'}, - 'CHAR(1) CHARACTER SET utf8 COLLATE utf8_bin'), - (my.MSChar, [1], {'charset': 'utf8', 'binary': True}, - 'CHAR(1) CHARACTER SET utf8 BINARY'), - (my.MSChar, [1], {'charset': 'utf8', 'collation': 'utf8_bin', - 'binary': True}, - 'CHAR(1) CHARACTER SET utf8 COLLATE utf8_bin'), - (my.MSChar, [1], {'national':True}, - 'NATIONAL CHAR(1)'), - (my.MSChar, [1], {'national':True, 'charset':'utf8'}, - 'NATIONAL CHAR(1)'), - (my.MSChar, [1], {'national':True, 'charset':'utf8', 'binary':True}, - 'NATIONAL CHAR(1) BINARY'), - (my.MSChar, [1], {'national':True, 'binary':True, 'unicode':True}, - 'NATIONAL CHAR(1) BINARY'), - (my.MSChar, [1], {'national':True, 'collation':'utf8_bin'}, - 'NATIONAL CHAR(1) COLLATE utf8_bin'), - (my.MSString, [1], {'charset':'utf8', 'collation':'utf8_bin'}, - 'VARCHAR(1) CHARACTER SET utf8 COLLATE utf8_bin'), - (my.MSString, [1], {'national':True, 'collation':'utf8_bin'}, - 'NATIONAL VARCHAR(1) COLLATE utf8_bin'), - (my.MSTinyText, [], {'charset':'utf8', 'collation':'utf8_bin'}, - 'TINYTEXT CHARACTER SET utf8 COLLATE utf8_bin'), - (my.MSMediumText, [], {'charset':'utf8', 'binary':True}, - 'MEDIUMTEXT CHARACTER SET utf8 BINARY'), - (my.MSLongText, [], {'ascii':True}, - 'LONGTEXT ASCII'), - (my.MSEnum, ["'foo'", "'bar'"], {'unicode':True}, - '''ENUM('foo','bar') UNICODE''') - ] - - table_args = ['testCharset', db] - for index, spec in enumerate(columns): - type_, args, kw, res = spec - table_args.append(Column('c%s' % index, type_(*args, **kw))) - - charset_table = Table(*table_args) - gen = db.dialect.schemagenerator(db, None, None) - - for col in charset_table.c: - index = int(col.name[1:]) - self.assertEquals(gen.get_column_specification(col), - "%s %s" % (col.name, columns[index][3])) - - try: - charset_table.create(checkfirst=True) - assert True - except: - raise - charset_table.drop() class UnicodeTest(AssertMixin): """tests the Unicode type. also tests the TypeDecorator with instances in the types package.""" -- 2.47.2