Learn more  » Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Bower components Debian packages RPM packages NuGet packages

aroundthecode / SQLAlchemy   python

Repository URL to install this package:

Version: 1.2.10 

/ dialects / sybase / base.py

# sybase/base.py
# Copyright (C) 2010-2018 the SQLAlchemy authors and contributors
# <see AUTHORS file>
# get_select_precolumns(), limit_clause() implementation
# copyright (C) 2007 Fisch Asset Management
# AG http://www.fam.ch, with coding by 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

"""

.. dialect:: sybase
    :name: Sybase

.. note::

    The Sybase dialect functions on current SQLAlchemy versions
    but is not regularly tested, and may have many issues and
    caveats not currently handled.

"""
import operator
import re

from sqlalchemy.sql import compiler, expression, text, bindparam
from sqlalchemy.engine import default, base, reflection
from sqlalchemy import types as sqltypes
from sqlalchemy.sql import operators as sql_operators
from sqlalchemy import schema as sa_schema
from sqlalchemy import util, sql, exc

from sqlalchemy.types import CHAR, VARCHAR, TIME, NCHAR, NVARCHAR,\
    TEXT, DATE, DATETIME, FLOAT, NUMERIC,\
    BIGINT, INT, INTEGER, SMALLINT, BINARY,\
    VARBINARY, DECIMAL, TIMESTAMP, Unicode,\
    UnicodeText, REAL

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",
])


class _SybaseUnitypeMixin(object):
    """these types appear to return a buffer object."""

    def result_processor(self, dialect, coltype):
        def process(value):
            if value is not None:
                return str(value)  # decode("ucs-2")
            else:
                return None
        return process


class UNICHAR(_SybaseUnitypeMixin, sqltypes.Unicode):
    __visit_name__ = 'UNICHAR'


class UNIVARCHAR(_SybaseUnitypeMixin, sqltypes.Unicode):
    __visit_name__ = 'UNIVARCHAR'


class UNITEXT(_SybaseUnitypeMixin, sqltypes.UnicodeText):
    __visit_name__ = 'UNITEXT'


class TINYINT(sqltypes.Integer):
    __visit_name__ = 'TINYINT'


class BIT(sqltypes.TypeEngine):
    __visit_name__ = 'BIT'


class MONEY(sqltypes.TypeEngine):
    __visit_name__ = "MONEY"


class SMALLMONEY(sqltypes.TypeEngine):
    __visit_name__ = "SMALLMONEY"


class UNIQUEIDENTIFIER(sqltypes.TypeEngine):
    __visit_name__ = "UNIQUEIDENTIFIER"


class IMAGE(sqltypes.LargeBinary):
    __visit_name__ = 'IMAGE'


class SybaseTypeCompiler(compiler.GenericTypeCompiler):
    def visit_large_binary(self, type_, **kw):
        return self.visit_IMAGE(type_)

    def visit_boolean(self, type_, **kw):
        return self.visit_BIT(type_)

    def visit_unicode(self, type_, **kw):
        return self.visit_NVARCHAR(type_)

    def visit_UNICHAR(self, type_, **kw):
        return "UNICHAR(%d)" % type_.length

    def visit_UNIVARCHAR(self, type_, **kw):
        return "UNIVARCHAR(%d)" % type_.length

    def visit_UNITEXT(self, type_, **kw):
        return "UNITEXT"

    def visit_TINYINT(self, type_, **kw):
        return "TINYINT"

    def visit_IMAGE(self, type_, **kw):
        return "IMAGE"

    def visit_BIT(self, type_, **kw):
        return "BIT"

    def visit_MONEY(self, type_, **kw):
        return "MONEY"

    def visit_SMALLMONEY(self, type_, **kw):
        return "SMALLMONEY"

    def visit_UNIQUEIDENTIFIER(self, type_, **kw):
        return "UNIQUEIDENTIFIER"

ischema_names = {
    'bigint': BIGINT,
    'int': INTEGER,
    'integer': INTEGER,
    'smallint': SMALLINT,
    'tinyint': TINYINT,
    'unsigned bigint': BIGINT,  # TODO: unsigned flags
    'unsigned int': INTEGER,  # TODO: unsigned flags
    'unsigned smallint': SMALLINT,  # TODO: unsigned flags
    'numeric': NUMERIC,
    'decimal': DECIMAL,
    'dec': DECIMAL,
    'float': FLOAT,
    'double': NUMERIC,  # TODO
    'double precision': NUMERIC,  # TODO
    'real': REAL,
    'smallmoney': SMALLMONEY,
    'money': MONEY,
    'smalldatetime': DATETIME,
    'datetime': DATETIME,
    'date': DATE,
    'time': TIME,
    'char': CHAR,
    'character': CHAR,
    'varchar': VARCHAR,
    'character varying': VARCHAR,
    'char varying': VARCHAR,
    'unichar': UNICHAR,
    'unicode character': UNIVARCHAR,
    'nchar': NCHAR,
    'national char': NCHAR,
    'national character': NCHAR,
    'nvarchar': NVARCHAR,
    'nchar varying': NVARCHAR,
    'national char varying': NVARCHAR,
    'national character varying': NVARCHAR,
    'text': TEXT,
    'unitext': UNITEXT,
    'binary': BINARY,
    'varbinary': VARBINARY,
    'image': IMAGE,
    'bit': BIT,

    # not in documentation for ASE 15.7
    'long varchar': TEXT,  # TODO
    'timestamp': TIMESTAMP,
    'uniqueidentifier': UNIQUEIDENTIFIER,

}


class SybaseInspector(reflection.Inspector):

    def __init__(self, conn):
        reflection.Inspector.__init__(self, conn)

    def get_table_id(self, table_name, schema=None):
        """Return the table id from `table_name` and `schema`."""

        return self.dialect.get_table_id(self.bind, table_name, schema,
                                         info_cache=self.info_cache)


class SybaseExecutionContext(default.DefaultExecutionContext):
    _enable_identity_insert = False

    def set_ddl_autocommit(self, connection, value):
        """Must be implemented by subclasses to accommodate DDL executions.

        "connection" is the raw unwrapped DBAPI connection.   "value"
        is True or False.  when True, the connection should be configured
        such that a DDL can take place subsequently.  when False,
        a DDL has taken place and the connection should be resumed
        into non-autocommit mode.

        """
        raise NotImplementedError()

    def pre_exec(self):
        if self.isinsert:
            tbl = self.compiled.statement.table
            seq_column = tbl._autoincrement_column
            insert_has_sequence = seq_column is not None

            if insert_has_sequence:
                self._enable_identity_insert = \
                    seq_column.key in self.compiled_parameters[0]
            else:
                self._enable_identity_insert = False

            if self._enable_identity_insert:
                self.cursor.execute(
                    "SET IDENTITY_INSERT %s ON" %
                    self.dialect.identifier_preparer.format_table(tbl))

        if self.isddl:
            # TODO: to enhance this, we can detect "ddl in tran" on the
            # database settings.  this error message should be improved to
            # include a note about that.
            if not self.should_autocommit:
                raise exc.InvalidRequestError(
                    "The Sybase dialect only supports "
                    "DDL in 'autocommit' mode at this time.")

            self.root_connection.engine.logger.info(
                "AUTOCOMMIT (Assuming no Sybase 'ddl in tran')")

            self.set_ddl_autocommit(
                self.root_connection.connection.connection,
                True)

    def post_exec(self):
        if self.isddl:
            self.set_ddl_autocommit(self.root_connection, False)

        if self._enable_identity_insert:
            self.cursor.execute(
                "SET IDENTITY_INSERT %s OFF" %
                self.dialect.identifier_preparer.
                format_table(self.compiled.statement.table)
            )

    def get_lastrowid(self):
        cursor = self.create_cursor()
        cursor.execute("SELECT @@identity AS lastrowid")
        lastrowid = cursor.fetchone()[0]
        cursor.close()
        return lastrowid


class SybaseSQLCompiler(compiler.SQLCompiler):
    ansi_bind_rules = True

    extract_map = util.update_copy(
        compiler.SQLCompiler.extract_map,
        {
            'doy': 'dayofyear',
            'dow': 'weekday',
            'milliseconds': 'millisecond'
        })

    def get_select_precolumns(self, select, **kw):
        s = select._distinct and "DISTINCT " or ""
        # TODO: don't think Sybase supports
        # bind params for FIRST / TOP
        limit = select._limit
        if limit:
            # if select._limit == 1:
                # s += "FIRST "
            # else:
                # s += "TOP %s " % (select._limit,)
            s += "TOP %s " % (limit,)
        offset = select._offset
        if offset:
            raise NotImplementedError("Sybase ASE does not support OFFSET")
        return s

    def get_from_hint_text(self, table, text):
        return text

    def limit_clause(self, select, **kw):
Loading ...