summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/databases/sybase.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sqlalchemy/databases/sybase.py')
-rw-r--r--lib/sqlalchemy/databases/sybase.py875
1 files changed, 0 insertions, 875 deletions
diff --git a/lib/sqlalchemy/databases/sybase.py b/lib/sqlalchemy/databases/sybase.py
deleted file mode 100644
index f5b48e147..000000000
--- a/lib/sqlalchemy/databases/sybase.py
+++ /dev/null
@@ -1,875 +0,0 @@
-# sybase.py
-# Copyright (C) 2007 Fisch Asset Management AG http://www.fam.ch
-# Coding: Alexander Houben alexander.houben@thor-solutions.ch
-#
-# This module is part of SQLAlchemy and is released under
-# the MIT License: http://www.opensource.org/licenses/mit-license.php
-
-"""
-Sybase database backend.
-
-Known issues / TODO:
-
- * Uses the mx.ODBC driver from egenix (version 2.1.0)
- * The current version of sqlalchemy.databases.sybase only supports
- mx.ODBC.Windows (other platforms such as mx.ODBC.unixODBC still need
- some development)
- * Support for pyodbc has been built in but is not yet complete (needs
- further development)
- * Results of running tests/alltests.py:
- Ran 934 tests in 287.032s
- FAILED (failures=3, errors=1)
- * Tested on 'Adaptive Server Anywhere 9' (version 9.0.1.1751)
-"""
-
-import datetime, operator
-
-from sqlalchemy import util, sql, schema, exc
-from sqlalchemy.sql import compiler, expression
-from sqlalchemy.engine import default, base
-from sqlalchemy import types as sqltypes
-from sqlalchemy.sql import operators as sql_operators
-from sqlalchemy import MetaData, Table, Column
-from sqlalchemy import String, Integer, SMALLINT, CHAR, ForeignKey
-
-
-__all__ = [
- 'SybaseTypeError'
- 'SybaseNumeric', 'SybaseFloat', 'SybaseInteger', 'SybaseBigInteger',
- 'SybaseTinyInteger', 'SybaseSmallInteger',
- 'SybaseDateTime_mxodbc', 'SybaseDateTime_pyodbc',
- 'SybaseDate_mxodbc', 'SybaseDate_pyodbc',
- 'SybaseTime_mxodbc', 'SybaseTime_pyodbc',
- 'SybaseText', 'SybaseString', 'SybaseChar', 'SybaseBinary',
- 'SybaseBoolean', 'SybaseTimeStamp', 'SybaseMoney', 'SybaseSmallMoney',
- 'SybaseUniqueIdentifier',
- ]
-
-
-RESERVED_WORDS = set([
- "add", "all", "alter", "and",
- "any", "as", "asc", "backup",
- "begin", "between", "bigint", "binary",
- "bit", "bottom", "break", "by",
- "call", "capability", "cascade", "case",
- "cast", "char", "char_convert", "character",
- "check", "checkpoint", "close", "comment",
- "commit", "connect", "constraint", "contains",
- "continue", "convert", "create", "cross",
- "cube", "current", "current_timestamp", "current_user",
- "cursor", "date", "dbspace", "deallocate",
- "dec", "decimal", "declare", "default",
- "delete", "deleting", "desc", "distinct",
- "do", "double", "drop", "dynamic",
- "else", "elseif", "encrypted", "end",
- "endif", "escape", "except", "exception",
- "exec", "execute", "existing", "exists",
- "externlogin", "fetch", "first", "float",
- "for", "force", "foreign", "forward",
- "from", "full", "goto", "grant",
- "group", "having", "holdlock", "identified",
- "if", "in", "index", "index_lparen",
- "inner", "inout", "insensitive", "insert",
- "inserting", "install", "instead", "int",
- "integer", "integrated", "intersect", "into",
- "iq", "is", "isolation", "join",
- "key", "lateral", "left", "like",
- "lock", "login", "long", "match",
- "membership", "message", "mode", "modify",
- "natural", "new", "no", "noholdlock",
- "not", "notify", "null", "numeric",
- "of", "off", "on", "open",
- "option", "options", "or", "order",
- "others", "out", "outer", "over",
- "passthrough", "precision", "prepare", "primary",
- "print", "privileges", "proc", "procedure",
- "publication", "raiserror", "readtext", "real",
- "reference", "references", "release", "remote",
- "remove", "rename", "reorganize", "resource",
- "restore", "restrict", "return", "revoke",
- "right", "rollback", "rollup", "save",
- "savepoint", "scroll", "select", "sensitive",
- "session", "set", "setuser", "share",
- "smallint", "some", "sqlcode", "sqlstate",
- "start", "stop", "subtrans", "subtransaction",
- "synchronize", "syntax_error", "table", "temporary",
- "then", "time", "timestamp", "tinyint",
- "to", "top", "tran", "trigger",
- "truncate", "tsequal", "unbounded", "union",
- "unique", "unknown", "unsigned", "update",
- "updating", "user", "using", "validate",
- "values", "varbinary", "varchar", "variable",
- "varying", "view", "wait", "waitfor",
- "when", "where", "while", "window",
- "with", "with_cube", "with_lparen", "with_rollup",
- "within", "work", "writetext",
- ])
-
-ischema = MetaData()
-
-tables = Table("SYSTABLE", ischema,
- Column("table_id", Integer, primary_key=True),
- Column("file_id", SMALLINT),
- Column("table_name", CHAR(128)),
- Column("table_type", CHAR(10)),
- Column("creator", Integer),
- #schema="information_schema"
- )
-
-domains = Table("SYSDOMAIN", ischema,
- Column("domain_id", Integer, primary_key=True),
- Column("domain_name", CHAR(128)),
- Column("type_id", SMALLINT),
- Column("precision", SMALLINT, quote=True),
- #schema="information_schema"
- )
-
-columns = Table("SYSCOLUMN", ischema,
- Column("column_id", Integer, primary_key=True),
- Column("table_id", Integer, ForeignKey(tables.c.table_id)),
- Column("pkey", CHAR(1)),
- Column("column_name", CHAR(128)),
- Column("nulls", CHAR(1)),
- Column("width", SMALLINT),
- Column("domain_id", SMALLINT, ForeignKey(domains.c.domain_id)),
- # FIXME: should be mx.BIGINT
- Column("max_identity", Integer),
- # FIXME: should be mx.ODBC.Windows.LONGVARCHAR
- Column("default", String),
- Column("scale", Integer),
- #schema="information_schema"
- )
-
-foreignkeys = Table("SYSFOREIGNKEY", ischema,
- Column("foreign_table_id", Integer, ForeignKey(tables.c.table_id), primary_key=True),
- Column("foreign_key_id", SMALLINT, primary_key=True),
- Column("primary_table_id", Integer, ForeignKey(tables.c.table_id)),
- #schema="information_schema"
- )
-fkcols = Table("SYSFKCOL", ischema,
- Column("foreign_table_id", Integer, ForeignKey(columns.c.table_id), primary_key=True),
- Column("foreign_key_id", SMALLINT, ForeignKey(foreignkeys.c.foreign_key_id), primary_key=True),
- Column("foreign_column_id", Integer, ForeignKey(columns.c.column_id), primary_key=True),
- Column("primary_column_id", Integer),
- #schema="information_schema"
- )
-
-class SybaseTypeError(sqltypes.TypeEngine):
- def result_processor(self, dialect):
- return None
-
- def bind_processor(self, dialect):
- def process(value):
- raise exc.InvalidRequestError("Data type not supported", [value])
- return process
-
- def get_col_spec(self):
- raise exc.CompileError("Data type not supported")
-
-class SybaseNumeric(sqltypes.Numeric):
- def get_col_spec(self):
- if self.scale is None:
- if self.precision is None:
- return "NUMERIC"
- else:
- return "NUMERIC(%(precision)s)" % {'precision' : self.precision}
- else:
- return "NUMERIC(%(precision)s, %(scale)s)" % {'precision': self.precision, 'scale' : self.scale}
-
-class SybaseFloat(sqltypes.FLOAT, SybaseNumeric):
- def __init__(self, precision = 10, asdecimal = False, scale = 2, **kwargs):
- super(sqltypes.FLOAT, self).__init__(precision, asdecimal, **kwargs)
- self.scale = scale
-
- def get_col_spec(self):
- # if asdecimal is True, handle same way as SybaseNumeric
- if self.asdecimal:
- return SybaseNumeric.get_col_spec(self)
- if self.precision is None:
- return "FLOAT"
- else:
- return "FLOAT(%(precision)s)" % {'precision': self.precision}
-
- def result_processor(self, dialect):
- def process(value):
- if value is None:
- return None
- return float(value)
- if self.asdecimal:
- return SybaseNumeric.result_processor(self, dialect)
- return process
-
-class SybaseInteger(sqltypes.Integer):
- def get_col_spec(self):
- return "INTEGER"
-
-class SybaseBigInteger(SybaseInteger):
- def get_col_spec(self):
- return "BIGINT"
-
-class SybaseTinyInteger(SybaseInteger):
- def get_col_spec(self):
- return "TINYINT"
-
-class SybaseSmallInteger(SybaseInteger):
- def get_col_spec(self):
- return "SMALLINT"
-
-class SybaseDateTime_mxodbc(sqltypes.DateTime):
- def __init__(self, *a, **kw):
- super(SybaseDateTime_mxodbc, self).__init__(False)
-
- def get_col_spec(self):
- return "DATETIME"
-
-class SybaseDateTime_pyodbc(sqltypes.DateTime):
- def __init__(self, *a, **kw):
- super(SybaseDateTime_pyodbc, self).__init__(False)
-
- def get_col_spec(self):
- return "DATETIME"
-
- def result_processor(self, dialect):
- def process(value):
- if value is None:
- return None
- # Convert the datetime.datetime back to datetime.time
- return value
- return process
-
- def bind_processor(self, dialect):
- def process(value):
- if value is None:
- return None
- return value
- return process
-
-class SybaseDate_mxodbc(sqltypes.Date):
- def __init__(self, *a, **kw):
- super(SybaseDate_mxodbc, self).__init__(False)
-
- def get_col_spec(self):
- return "DATE"
-
-class SybaseDate_pyodbc(sqltypes.Date):
- def __init__(self, *a, **kw):
- super(SybaseDate_pyodbc, self).__init__(False)
-
- def get_col_spec(self):
- return "DATE"
-
-class SybaseTime_mxodbc(sqltypes.Time):
- def __init__(self, *a, **kw):
- super(SybaseTime_mxodbc, self).__init__(False)
-
- def get_col_spec(self):
- return "DATETIME"
-
- def result_processor(self, dialect):
- def process(value):
- if value is None:
- return None
- # Convert the datetime.datetime back to datetime.time
- return datetime.time(value.hour, value.minute, value.second, value.microsecond)
- return process
-
-class SybaseTime_pyodbc(sqltypes.Time):
- def __init__(self, *a, **kw):
- super(SybaseTime_pyodbc, self).__init__(False)
-
- def get_col_spec(self):
- return "DATETIME"
-
- def result_processor(self, dialect):
- def process(value):
- if value is None:
- return None
- # Convert the datetime.datetime back to datetime.time
- return datetime.time(value.hour, value.minute, value.second, value.microsecond)
- return process
-
- def bind_processor(self, dialect):
- def process(value):
- if value is None:
- return None
- return datetime.datetime(1970, 1, 1, value.hour, value.minute, value.second, value.microsecond)
- return process
-
-class SybaseText(sqltypes.Text):
- def get_col_spec(self):
- return "TEXT"
-
-class SybaseString(sqltypes.String):
- def get_col_spec(self):
- return "VARCHAR(%(length)s)" % {'length' : self.length}
-
-class SybaseChar(sqltypes.CHAR):
- def get_col_spec(self):
- return "CHAR(%(length)s)" % {'length' : self.length}
-
-class SybaseBinary(sqltypes.Binary):
- def get_col_spec(self):
- return "IMAGE"
-
-class SybaseBoolean(sqltypes.Boolean):
- def get_col_spec(self):
- return "BIT"
-
- def result_processor(self, dialect):
- def process(value):
- if value is None:
- return None
- return value and True or False
- return process
-
- def bind_processor(self, dialect):
- def process(value):
- if value is True:
- return 1
- elif value is False:
- return 0
- elif value is None:
- return None
- else:
- return value and True or False
- return process
-
-class SybaseTimeStamp(sqltypes.TIMESTAMP):
- def get_col_spec(self):
- return "TIMESTAMP"
-
-class SybaseMoney(sqltypes.TypeEngine):
- def get_col_spec(self):
- return "MONEY"
-
-class SybaseSmallMoney(SybaseMoney):
- def get_col_spec(self):
- return "SMALLMONEY"
-
-class SybaseUniqueIdentifier(sqltypes.TypeEngine):
- def get_col_spec(self):
- return "UNIQUEIDENTIFIER"
-
-class SybaseSQLExecutionContext(default.DefaultExecutionContext):
- pass
-
-class SybaseSQLExecutionContext_mxodbc(SybaseSQLExecutionContext):
-
- def __init__(self, dialect, connection, compiled=None, statement=None, parameters=None):
- super(SybaseSQLExecutionContext_mxodbc, self).__init__(dialect, connection, compiled, statement, parameters)
-
- def pre_exec(self):
- super(SybaseSQLExecutionContext_mxodbc, self).pre_exec()
-
- def post_exec(self):
- if self.compiled.isinsert:
- table = self.compiled.statement.table
- # get the inserted values of the primary key
-
- # get any sequence IDs first (using @@identity)
- self.cursor.execute("SELECT @@identity AS lastrowid")
- row = self.cursor.fetchone()
- lastrowid = int(row[0])
- if lastrowid > 0:
- # an IDENTITY was inserted, fetch it
- # FIXME: always insert in front ? This only works if the IDENTITY is the first column, no ?!
- if not hasattr(self, '_last_inserted_ids') or self._last_inserted_ids is None:
- self._last_inserted_ids = [lastrowid]
- else:
- self._last_inserted_ids = [lastrowid] + self._last_inserted_ids[1:]
- super(SybaseSQLExecutionContext_mxodbc, self).post_exec()
-
-class SybaseSQLExecutionContext_pyodbc(SybaseSQLExecutionContext):
- def __init__(self, dialect, connection, compiled=None, statement=None, parameters=None):
- super(SybaseSQLExecutionContext_pyodbc, self).__init__(dialect, connection, compiled, statement, parameters)
-
- def pre_exec(self):
- super(SybaseSQLExecutionContext_pyodbc, self).pre_exec()
-
- def post_exec(self):
- if self.compiled.isinsert:
- table = self.compiled.statement.table
- # get the inserted values of the primary key
-
- # get any sequence IDs first (using @@identity)
- self.cursor.execute("SELECT @@identity AS lastrowid")
- row = self.cursor.fetchone()
- lastrowid = int(row[0])
- if lastrowid > 0:
- # an IDENTITY was inserted, fetch it
- # FIXME: always insert in front ? This only works if the IDENTITY is the first column, no ?!
- if not hasattr(self, '_last_inserted_ids') or self._last_inserted_ids is None:
- self._last_inserted_ids = [lastrowid]
- else:
- self._last_inserted_ids = [lastrowid] + self._last_inserted_ids[1:]
- super(SybaseSQLExecutionContext_pyodbc, self).post_exec()
-
-class SybaseSQLDialect(default.DefaultDialect):
- colspecs = {
- # FIXME: unicode support
- #sqltypes.Unicode : SybaseUnicode,
- sqltypes.Integer : SybaseInteger,
- sqltypes.SmallInteger : SybaseSmallInteger,
- sqltypes.Numeric : SybaseNumeric,
- sqltypes.Float : SybaseFloat,
- sqltypes.String : SybaseString,
- sqltypes.Binary : SybaseBinary,
- sqltypes.Boolean : SybaseBoolean,
- sqltypes.Text : SybaseText,
- sqltypes.CHAR : SybaseChar,
- sqltypes.TIMESTAMP : SybaseTimeStamp,
- sqltypes.FLOAT : SybaseFloat,
- }
-
- ischema_names = {
- 'integer' : SybaseInteger,
- 'unsigned int' : SybaseInteger,
- 'unsigned smallint' : SybaseInteger,
- 'unsigned bigint' : SybaseInteger,
- 'bigint': SybaseBigInteger,
- 'smallint' : SybaseSmallInteger,
- 'tinyint' : SybaseTinyInteger,
- 'varchar' : SybaseString,
- 'long varchar' : SybaseText,
- 'char' : SybaseChar,
- 'decimal' : SybaseNumeric,
- 'numeric' : SybaseNumeric,
- 'float' : SybaseFloat,
- 'double' : SybaseFloat,
- 'binary' : SybaseBinary,
- 'long binary' : SybaseBinary,
- 'varbinary' : SybaseBinary,
- 'bit': SybaseBoolean,
- 'image' : SybaseBinary,
- 'timestamp': SybaseTimeStamp,
- 'money': SybaseMoney,
- 'smallmoney': SybaseSmallMoney,
- 'uniqueidentifier': SybaseUniqueIdentifier,
-
- 'java.lang.Object' : SybaseTypeError,
- 'java serialization' : SybaseTypeError,
- }
-
- name = 'sybase'
- # Sybase backend peculiarities
- supports_unicode_statements = False
- supports_sane_rowcount = False
- supports_sane_multi_rowcount = False
- execution_ctx_cls = SybaseSQLExecutionContext
-
- def __new__(cls, dbapi=None, *args, **kwargs):
- if cls != SybaseSQLDialect:
- return super(SybaseSQLDialect, cls).__new__(cls, *args, **kwargs)
- if dbapi:
- print dbapi.__name__
- dialect = dialect_mapping.get(dbapi.__name__)
- return dialect(*args, **kwargs)
- else:
- return object.__new__(cls, *args, **kwargs)
-
- def __init__(self, **params):
- super(SybaseSQLDialect, self).__init__(**params)
- self.text_as_varchar = False
- # FIXME: what is the default schema for sybase connections (DBA?) ?
- self.set_default_schema_name("dba")
-
- def dbapi(cls, module_name=None):
- if module_name:
- try:
- dialect_cls = dialect_mapping[module_name]
- return dialect_cls.import_dbapi()
- except KeyError:
- raise exc.InvalidRequestError("Unsupported SybaseSQL module '%s' requested (must be " + " or ".join([x for x in dialect_mapping.keys()]) + ")" % module_name)
- else:
- for dialect_cls in dialect_mapping.values():
- try:
- return dialect_cls.import_dbapi()
- except ImportError, e:
- pass
- else:
- raise ImportError('No DBAPI module detected for SybaseSQL - please install mxodbc')
- dbapi = classmethod(dbapi)
-
- def type_descriptor(self, typeobj):
- newobj = sqltypes.adapt_type(typeobj, self.colspecs)
- return newobj
-
- def last_inserted_ids(self):
- return self.context.last_inserted_ids
-
- def get_default_schema_name(self, connection):
- return self.schema_name
-
- def set_default_schema_name(self, schema_name):
- self.schema_name = schema_name
-
- def do_execute(self, cursor, statement, params, **kwargs):
- params = tuple(params)
- super(SybaseSQLDialect, self).do_execute(cursor, statement, params, **kwargs)
-
- # FIXME: remove ?
- def _execute(self, c, statement, parameters):
- try:
- if parameters == {}:
- parameters = ()
- c.execute(statement, parameters)
- self.context.rowcount = c.rowcount
- c.DBPROP_COMMITPRESERVE = "Y"
- except Exception, e:
- raise exc.DBAPIError.instance(statement, parameters, e)
-
- def table_names(self, connection, schema):
- """Ignore the schema and the charset for now."""
- s = sql.select([tables.c.table_name],
- sql.not_(tables.c.table_name.like("SYS%")) and
- tables.c.creator >= 100
- )
- rp = connection.execute(s)
- return [row[0] for row in rp.fetchall()]
-
- def has_table(self, connection, tablename, schema=None):
- # FIXME: ignore schemas for sybase
- s = sql.select([tables.c.table_name], tables.c.table_name == tablename)
-
- c = connection.execute(s)
- row = c.fetchone()
- print "has_table: " + tablename + ": " + str(bool(row is not None))
- return row is not None
-
- def reflecttable(self, connection, table, include_columns):
- # Get base columns
- if table.schema is not None:
- current_schema = table.schema
- else:
- current_schema = self.get_default_schema_name(connection)
-
- s = sql.select([columns, domains], tables.c.table_name==table.name, from_obj=[columns.join(tables).join(domains)], order_by=[columns.c.column_id])
-
- c = connection.execute(s)
- found_table = False
- # makes sure we append the columns in the correct order
- while True:
- row = c.fetchone()
- if row is None:
- break
- found_table = True
- (name, type, nullable, charlen, numericprec, numericscale, default, primary_key, max_identity, table_id, column_id) = (
- row[columns.c.column_name],
- row[domains.c.domain_name],
- row[columns.c.nulls] == 'Y',
- row[columns.c.width],
- row[domains.c.precision],
- row[columns.c.scale],
- row[columns.c.default],
- row[columns.c.pkey] == 'Y',
- row[columns.c.max_identity],
- row[tables.c.table_id],
- row[columns.c.column_id],
- )
- if include_columns and name not in include_columns:
- continue
-
- # FIXME: else problems with SybaseBinary(size)
- if numericscale == 0:
- numericscale = None
-
- args = []
- for a in (charlen, numericprec, numericscale):
- if a is not None:
- args.append(a)
- coltype = self.ischema_names.get(type, None)
- if coltype == SybaseString and charlen == -1:
- coltype = SybaseText()
- else:
- if coltype is None:
- util.warn("Did not recognize type '%s' of column '%s'" %
- (type, name))
- coltype = sqltypes.NULLTYPE
- coltype = coltype(*args)
- colargs = []
- if default is not None:
- colargs.append(schema.DefaultClause(sql.text(default)))
-
- # any sequences ?
- col = schema.Column(name, coltype, nullable=nullable, primary_key=primary_key, *colargs)
- if int(max_identity) > 0:
- col.sequence = schema.Sequence(name + '_identity')
- col.sequence.start = int(max_identity)
- col.sequence.increment = 1
-
- # append the column
- table.append_column(col)
-
- # any foreign key constraint for this table ?
- # note: no multi-column foreign keys are considered
- s = "select st1.table_name, sc1.column_name, st2.table_name, sc2.column_name from systable as st1 join sysfkcol on st1.table_id=sysfkcol.foreign_table_id join sysforeignkey join systable as st2 on sysforeignkey.primary_table_id = st2.table_id join syscolumn as sc1 on sysfkcol.foreign_column_id=sc1.column_id and sc1.table_id=st1.table_id join syscolumn as sc2 on sysfkcol.primary_column_id=sc2.column_id and sc2.table_id=st2.table_id where st1.table_name='%(table_name)s';" % { 'table_name' : table.name }
- c = connection.execute(s)
- foreignKeys = {}
- while True:
- row = c.fetchone()
- if row is None:
- break
- (foreign_table, foreign_column, primary_table, primary_column) = (
- row[0], row[1], row[2], row[3],
- )
- if not primary_table in foreignKeys.keys():
- foreignKeys[primary_table] = [['%s' % (foreign_column)], ['%s.%s'%(primary_table, primary_column)]]
- else:
- foreignKeys[primary_table][0].append('%s'%(foreign_column))
- foreignKeys[primary_table][1].append('%s.%s'%(primary_table, primary_column))
- for primary_table in foreignKeys.keys():
- #table.append_constraint(schema.ForeignKeyConstraint(['%s.%s'%(foreign_table, foreign_column)], ['%s.%s'%(primary_table,primary_column)]))
- table.append_constraint(schema.ForeignKeyConstraint(foreignKeys[primary_table][0], foreignKeys[primary_table][1], link_to_name=True))
-
- if not found_table:
- raise exc.NoSuchTableError(table.name)
-
-
-class SybaseSQLDialect_mxodbc(SybaseSQLDialect):
- execution_ctx_cls = SybaseSQLExecutionContext_mxodbc
-
- def __init__(self, **params):
- super(SybaseSQLDialect_mxodbc, self).__init__(**params)
-
- self.dbapi_type_map = {'getdate' : SybaseDate_mxodbc()}
-
- def import_dbapi(cls):
- #import mx.ODBC.Windows as module
- import mxODBC as module
- return module
- import_dbapi = classmethod(import_dbapi)
-
- colspecs = SybaseSQLDialect.colspecs.copy()
- colspecs[sqltypes.Time] = SybaseTime_mxodbc
- colspecs[sqltypes.Date] = SybaseDate_mxodbc
- colspecs[sqltypes.DateTime] = SybaseDateTime_mxodbc
-
- ischema_names = SybaseSQLDialect.ischema_names.copy()
- ischema_names['time'] = SybaseTime_mxodbc
- ischema_names['date'] = SybaseDate_mxodbc
- ischema_names['datetime'] = SybaseDateTime_mxodbc
- ischema_names['smalldatetime'] = SybaseDateTime_mxodbc
-
- def is_disconnect(self, e):
- # FIXME: optimize
- #return isinstance(e, self.dbapi.Error) and '[08S01]' in str(e)
- #return True
- return False
-
- def do_execute(self, cursor, statement, parameters, context=None, **kwargs):
- super(SybaseSQLDialect_mxodbc, self).do_execute(cursor, statement, parameters, context=context, **kwargs)
-
- def create_connect_args(self, url):
- '''Return a tuple of *args,**kwargs'''
- # FIXME: handle mx.odbc.Windows proprietary args
- opts = url.translate_connect_args(username='user')
- opts.update(url.query)
- argsDict = {}
- argsDict['user'] = opts['user']
- argsDict['password'] = opts['password']
- connArgs = [[opts['dsn']], argsDict]
- return connArgs
-
-
-class SybaseSQLDialect_pyodbc(SybaseSQLDialect):
- execution_ctx_cls = SybaseSQLExecutionContext_pyodbc
-
- def __init__(self, **params):
- super(SybaseSQLDialect_pyodbc, self).__init__(**params)
- self.dbapi_type_map = {'getdate' : SybaseDate_pyodbc()}
-
- def import_dbapi(cls):
- import mypyodbc as module
- return module
- import_dbapi = classmethod(import_dbapi)
-
- colspecs = SybaseSQLDialect.colspecs.copy()
- colspecs[sqltypes.Time] = SybaseTime_pyodbc
- colspecs[sqltypes.Date] = SybaseDate_pyodbc
- colspecs[sqltypes.DateTime] = SybaseDateTime_pyodbc
-
- ischema_names = SybaseSQLDialect.ischema_names.copy()
- ischema_names['time'] = SybaseTime_pyodbc
- ischema_names['date'] = SybaseDate_pyodbc
- ischema_names['datetime'] = SybaseDateTime_pyodbc
- ischema_names['smalldatetime'] = SybaseDateTime_pyodbc
-
- def is_disconnect(self, e):
- # FIXME: optimize
- #return isinstance(e, self.dbapi.Error) and '[08S01]' in str(e)
- #return True
- return False
-
- def do_execute(self, cursor, statement, parameters, context=None, **kwargs):
- super(SybaseSQLDialect_pyodbc, self).do_execute(cursor, statement, parameters, context=context, **kwargs)
-
- def create_connect_args(self, url):
- '''Return a tuple of *args,**kwargs'''
- # FIXME: handle pyodbc proprietary args
- opts = url.translate_connect_args(username='user')
- opts.update(url.query)
-
- self.autocommit = False
- if 'autocommit' in opts:
- self.autocommit = bool(int(opts.pop('autocommit')))
-
- argsDict = {}
- argsDict['UID'] = opts['user']
- argsDict['PWD'] = opts['password']
- argsDict['DSN'] = opts['dsn']
- connArgs = [[';'.join(["%s=%s"%(key, argsDict[key]) for key in argsDict])], {'autocommit' : self.autocommit}]
- return connArgs
-
-
-dialect_mapping = {
- 'sqlalchemy.databases.mxODBC' : SybaseSQLDialect_mxodbc,
-# 'pyodbc' : SybaseSQLDialect_pyodbc,
- }
-
-
-class SybaseSQLCompiler(compiler.DefaultCompiler):
- operators = compiler.DefaultCompiler.operators.copy()
- operators.update({
- sql_operators.mod: lambda x, y: "MOD(%s, %s)" % (x, y),
- })
-
- extract_map = compiler.DefaultCompiler.extract_map.copy()
- extract_map.update ({
- 'doy': 'dayofyear',
- 'dow': 'weekday',
- 'milliseconds': 'millisecond'
- })
-
-
- def bindparam_string(self, name):
- res = super(SybaseSQLCompiler, self).bindparam_string(name)
- if name.lower().startswith('literal'):
- res = 'STRING(%s)' % res
- return res
-
- def get_select_precolumns(self, select):
- s = select._distinct and "DISTINCT " or ""
- if select._limit:
- #if select._limit == 1:
- #s += "FIRST "
- #else:
- #s += "TOP %s " % (select._limit,)
- s += "TOP %s " % (select._limit,)
- if select._offset:
- if not select._limit:
- # FIXME: sybase doesn't allow an offset without a limit
- # so use a huge value for TOP here
- s += "TOP 1000000 "
- s += "START AT %s " % (select._offset+1,)
- return s
-
- def limit_clause(self, select):
- # Limit in sybase is after the select keyword
- return ""
-
- def visit_binary(self, binary):
- """Move bind parameters to the right-hand side of an operator, where possible."""
- if isinstance(binary.left, expression._BindParamClause) and binary.operator == operator.eq:
- return self.process(expression._BinaryExpression(binary.right, binary.left, binary.operator))
- else:
- return super(SybaseSQLCompiler, self).visit_binary(binary)
-
- def label_select_column(self, select, column, asfrom):
- if isinstance(column, expression.Function):
- return column.label(None)
- else:
- return super(SybaseSQLCompiler, self).label_select_column(select, column, asfrom)
-
- function_rewrites = {'current_date': 'getdate',
- }
- def visit_function(self, func):
- func.name = self.function_rewrites.get(func.name, func.name)
- res = super(SybaseSQLCompiler, self).visit_function(func)
- if func.name.lower() == 'getdate':
- # apply CAST operator
- # FIXME: what about _pyodbc ?
- cast = expression._Cast(func, SybaseDate_mxodbc)
- # infinite recursion
- # res = self.visit_cast(cast)
- res = "CAST(%s AS %s)" % (res, self.process(cast.typeclause))
- return res
-
- def visit_extract(self, extract):
- field = self.extract_map.get(extract.field, extract.field)
- return 'DATEPART("%s", %s)' % (field, self.process(extract.expr))
-
- def for_update_clause(self, select):
- # "FOR UPDATE" is only allowed on "DECLARE CURSOR" which SQLAlchemy doesn't use
- return ''
-
- def order_by_clause(self, select):
- order_by = self.process(select._order_by_clause)
-
- # SybaseSQL only allows ORDER BY in subqueries if there is a LIMIT
- if order_by and (not self.is_subquery() or select._limit):
- return " ORDER BY " + order_by
- else:
- return ""
-
-
-class SybaseSQLSchemaGenerator(compiler.SchemaGenerator):
- def get_column_specification(self, column, **kwargs):
-
- colspec = self.preparer.format_column(column)
-
- if (not getattr(column.table, 'has_sequence', False)) and column.primary_key and \
- column.autoincrement and isinstance(column.type, sqltypes.Integer):
- if column.default is None or (isinstance(column.default, schema.Sequence) and column.default.optional):
- column.sequence = schema.Sequence(column.name + '_seq')
-
- if hasattr(column, 'sequence'):
- column.table.has_sequence = column
- #colspec += " numeric(30,0) IDENTITY"
- colspec += " Integer IDENTITY"
- else:
- colspec += " " + column.type.dialect_impl(self.dialect).get_col_spec()
-
- if not column.nullable:
- colspec += " NOT NULL"
-
- default = self.get_column_default_string(column)
- if default is not None:
- colspec += " DEFAULT " + default
-
- return colspec
-
-
-class SybaseSQLSchemaDropper(compiler.SchemaDropper):
- def visit_index(self, index):
- self.append("\nDROP INDEX %s.%s" % (
- self.preparer.quote_identifier(index.table.name),
- self.preparer.quote(self._validate_identifier(index.name, False), index.quote)
- ))
- self.execute()
-
-
-class SybaseSQLDefaultRunner(base.DefaultRunner):
- pass
-
-
-class SybaseSQLIdentifierPreparer(compiler.IdentifierPreparer):
- reserved_words = RESERVED_WORDS
-
- def __init__(self, dialect):
- super(SybaseSQLIdentifierPreparer, self).__init__(dialect)
-
- def _escape_identifier(self, value):
- #TODO: determin SybaseSQL's escapeing rules
- return value
-
- def _fold_identifier_case(self, value):
- #TODO: determin SybaseSQL's case folding rules
- return value
-
-
-dialect = SybaseSQLDialect
-dialect.statement_compiler = SybaseSQLCompiler
-dialect.schemagenerator = SybaseSQLSchemaGenerator
-dialect.schemadropper = SybaseSQLSchemaDropper
-dialect.preparer = SybaseSQLIdentifierPreparer
-dialect.defaultrunner = SybaseSQLDefaultRunner