--- /Users/classic/dev/sqlalchemy/lib/sqlalchemy/databases/sybase.py	2009-02-09 20:20:09.000000000 -0500
+++ /Users/classic/Desktop/sybase.py	2009-02-09 20:20:03.000000000 -0500
@@ -8,18 +8,11 @@
 """
 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)
+ * Current support is against python-sybase: http://python-sybase.sourceforge.net/
+ * mxODBC support is untested in current releases.   Original implementation
+   was against mx.ODBC driver from egenix version 2.1.0.
+ * pyodbc support planned for SQLA 0.6.
+ 
 """
 
 import datetime, operator
@@ -107,51 +100,12 @@
 
 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"
+objects = Table("sysobjects", ischema,
+    Column("id", Integer, primary_key=True),
+    Column("name", String),
+    Column("uid", Integer),
+    Column("type", String),
+    Column("loginname", String),
     )
 
 class SybaseTypeError(sqltypes.TypeEngine):
@@ -351,16 +305,6 @@
         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
@@ -377,32 +321,13 @@
                     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)
 
+class Sybase_pythonsybaseExecutionContext(SybaseSQLExecutionContext):
     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()
+        self.parameters = [
+            dict(('@' + key, value) for key, value in p.iteritems()) for p in self.parameters
+        ]
 
 class SybaseSQLDialect(default.DefaultDialect):
     colspecs = {
@@ -451,7 +376,7 @@
     }
 
     name = 'sybase'
-    # Sybase backend peculiarities
+
     supports_unicode_statements = False
     supports_sane_rowcount = False
     supports_sane_multi_rowcount = False
@@ -461,18 +386,16 @@
         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")
+    @base.connection_memoize(('dialect', 'default_schema_name'))
+    def get_default_schema_name(self, connection):
+        return connection.scalar("SELECT user_name() as user_name")
 
+    @classmethod
     def dbapi(cls, module_name=None):
         if module_name:
             try:
@@ -488,7 +411,6 @@
                     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)
@@ -497,47 +419,16 @@
     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()]
+        s = sql.select([objects.c.name]).where(objects.c.type=='U')
+        return [row[0] for row in connection.execute(s).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
+        
+        s = sql.select([objects.c.name]).where(objects.c.name==name).where(objects.c.type=='U')
+        return bool(connection.scalar(s))
 
     def reflecttable(self, connection, table, include_columns):
-        # Get base columns
         if table.schema is not None:
             current_schema = table.schema
         else:
@@ -624,20 +515,36 @@
         if not found_table:
             raise exc.NoSuchTableError(table.name)
 
+class SybaseSQLDialect_pythonsybase(SybaseSQLDialect):
+
+    execution_ctx_cls = Sybase_pythonsybaseExecutionContext
+    
+    @classmethod
+    def import_dbapi(cls):
+        import Sybase
+        return Sybase
 
+    def create_connect_args(self, url):
+        kw = {}
+        if url.database:
+            kw['database'] = url.database
+        kw.update(url.query)
+        
+        return [url.host, url.username, url.password], kw
+    
+    
 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()}
 
+    @classmethod
     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
@@ -671,59 +578,9 @@
         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,
+    'Sybase':SybaseSQLDialect_pythonsybase
     }
 
 
@@ -734,10 +591,7 @@
     })
 
     def bindparam_string(self, name):
-        res = super(SybaseSQLCompiler, self).bindparam_string(name)
-        if name.lower().startswith('literal'):
-            res = 'STRING(%s)' % res
-        return res
+        return "@%s" % name
 
     def get_select_precolumns(self, select):
         s = select._distinct and "DISTINCT " or ""
