# drizzle/base.py# Copyright (C) 2005-2012 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"""Support for the Drizzle database.Drizzle is a variant of MySQL. Unlike MySQL, Drizzle's default storage engineis InnoDB (transactions, foreign-keys) rather than MyISAM. For more`Notable Differences <http://docs.drizzle.org/mysql_differences.html>`_, visitthe `Drizzle Documentation <http://docs.drizzle.org/index.html>`_.The SQLAlchemy Drizzle dialect leans heavily on the MySQL dialect, so much ofthe :doc:`SQLAlchemy MySQL <mysql>` documentation is also relevant.Connecting----------See the individual driver sections below for details on connecting."""fromsqlalchemyimportexcfromsqlalchemyimportlogfromsqlalchemyimporttypesassqltypesfromsqlalchemy.engineimportreflectionfromsqlalchemy.dialects.mysqlimportbaseasmysql_dialectfromsqlalchemy.typesimportDATE,DATETIME,BOOLEAN,TIME, \
BLOB,BINARY,VARBINARYclass_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):ifisinstance(self,(REAL,DOUBLE))and \
((precisionisNoneandscaleisnotNone)or(precisionisnotNoneandscaleisNone)):raiseexc.ArgumentError("You must specify both precision and scale or omit ""both altogether.")super(_FloatType,self).__init__(precision=precision,asdecimal=asdecimal,**kw)self.scale=scaleclass_StringType(mysql_dialect._StringType):"""Base for Drizzle string types."""def__init__(self,collation=None,binary=False,**kw):kw['national']=Falsesuper(_StringType,self).__init__(collation=collation,binary=binary,**kw)classNUMERIC(_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)classDECIMAL(_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)classDOUBLE(_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)classREAL(_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)classFLOAT(_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)defbind_processor(self,dialect):returnNoneclassINTEGER(sqltypes.INTEGER):"""Drizzle INTEGER type."""__visit_name__='INTEGER'def__init__(self,**kw):"""Construct an INTEGER."""super(INTEGER,self).__init__(**kw)classBIGINT(sqltypes.BIGINT):"""Drizzle BIGINTEGER type."""__visit_name__='BIGINT'def__init__(self,**kw):"""Construct a BIGINTEGER."""super(BIGINT,self).__init__(**kw)class_DrizzleTime(mysql_dialect._MSTime):"""Drizzle TIME type."""classTIMESTAMP(sqltypes.TIMESTAMP):"""Drizzle TIMESTAMP type."""__visit_name__='TIMESTAMP'classTEXT(_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)classVARCHAR(_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)classCHAR(_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)classENUM(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):defget_dbapi_type(self,dbapi):returndbapi.NUMERICcolspecs={sqltypes.Numeric:NUMERIC,sqltypes.Float:FLOAT,sqltypes.Time:_DrizzleTime,sqltypes.Enum:ENUM,sqltypes.Boolean:_DrizzleBoolean,}# All the types we have in Drizzleischema_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,}classDrizzleCompiler(mysql_dialect.MySQLCompiler):defvisit_typeclause(self,typeclause):type_=typeclause.type.dialect_impl(self.dialect)ifisinstance(type_,sqltypes.Integer):return'INTEGER'else:returnsuper(DrizzleCompiler,self).visit_typeclause(typeclause)defvisit_cast(self,cast,**kwargs):type_=self.process(cast.typeclause)iftype_isNone:returnself.process(cast.clause)return'CAST(%s AS %s)'%(self.process(cast.clause),type_)classDrizzleDDLCompiler(mysql_dialect.MySQLDDLCompiler):passclassDrizzleTypeCompiler(mysql_dialect.MySQLTypeCompiler):def_extend_numeric(self,type_,spec):returnspecdef_extend_string(self,type_,defaults,spec):"""Extend a string-type declaration with standard SQL COLLATE annotations and Drizzle specific extensions. """defattr(name):returngetattr(type_,name,defaults.get(name))ifattr('collation'):collation='COLLATE %s'%type_.collationelifattr('binary'):collation='BINARY'else:collation=Nonereturn' '.join([cforcin(spec,collation)ifcisnotNone])defvisit_NCHAR(self,type):raiseNotImplementedError("Drizzle does not support NCHAR")defvisit_NVARCHAR(self,type):raiseNotImplementedError("Drizzle does not support NVARCHAR")defvisit_FLOAT(self,type_):iftype_.scaleisnotNoneandtype_.precisionisnotNone:return"FLOAT(%s, %s)"%(type_.precision,type_.scale)else:return"FLOAT"defvisit_BOOLEAN(self,type_):return"BOOLEAN"defvisit_BLOB(self,type_):return"BLOB"classDrizzleExecutionContext(mysql_dialect.MySQLExecutionContext):passclassDrizzleIdentifierPreparer(mysql_dialect.MySQLIdentifierPreparer):passclassDrizzleDialect(mysql_dialect.MySQLDialect):"""Details of the Drizzle dialect. Not used directly in application code. """name='drizzle'_supports_cast=Truesupports_sequences=Falsesupports_native_boolean=Truesupports_views=Falsedefault_paramstyle='format'colspecs=colspecsstatement_compiler=DrizzleCompilerddl_compiler=DrizzleDDLCompilertype_compiler=DrizzleTypeCompilerischema_names=ischema_namespreparer=DrizzleIdentifierPreparerdefon_connect(self):"""Force autocommit - Drizzle Bug#707842 doesn't set this properly"""defconnect(conn):conn.autocommit(False)returnconnectdefdo_commit(self,connection):"""Execute a COMMIT."""connection.commit()defdo_rollback(self,connection):"""Execute a ROLLBACK."""connection.rollback()@reflection.cachedefget_table_names(self,connection,schema=None,**kw):"""Return a Unicode SHOW TABLES from a given schema."""ifschemaisnotNone:current_schema=schemaelse:current_schema=self.default_schema_namecharset='utf8'rp=connection.execute("SHOW TABLES FROM %s"%self.identifier_preparer.quote_identifier(current_schema))return[row[0]forrowinself._compat_fetchall(rp,charset=charset)]@reflection.cachedefget_view_names(self,connection,schema=None,**kw):raiseNotImplementedErrordef_detect_casing(self,connection):"""Sniff out identifier case sensitivity. Cached per-connection. This value can not change without a server restart. """return0def_detect_collations(self,connection):"""Pull the active COLLATIONS list from the server. Cached per-connection. """collations={}charset=self._connection_charsetrs=connection.execute('SELECT CHARACTER_SET_NAME, COLLATION_NAME FROM'' data_dictionary.COLLATIONS')forrowinself._compat_fetchall(rs,charset):collations[row[0]]=row[1]returncollationsdef_detect_ansiquotes(self,connection):"""Detect and adjust for the ANSI_QUOTES sql mode."""self._server_ansiquotes=Falseself._backslash_escapes=Falselog.class_logger(DrizzleDialect)