root/galaxy-central/eggs/SQLAlchemy-0.5.6_dev_r6498-py2.6.egg/sqlalchemy/engine/base.py @ 3

リビジョン 3, 63.7 KB (コミッタ: kohda, 14 年 前)

Install Unix tools  http://hannonlab.cshl.edu/galaxy_unix_tools/galaxy.html

行番号 
1# engine/base.py
2# Copyright (C) 2005, 2006, 2007, 2008, 2009 Michael Bayer mike_mp@zzzcomputing.com
3#
4# This module is part of SQLAlchemy and is released under
5# the MIT License: http://www.opensource.org/licenses/mit-license.php
6
7
8"""Basic components for SQL execution and interfacing with DB-API.
9
10Defines the basic components used to interface DB-API modules with
11higher-level statement-construction, connection-management, execution
12and result contexts.
13
14"""
15
16__all__ = ['BufferedColumnResultProxy', 'BufferedColumnRow', 'BufferedRowResultProxy', 'Compiled', 'Connectable',
17        'Connection', 'DefaultRunner', 'Dialect', 'Engine', 'ExecutionContext', 'NestedTransaction', 'ResultProxy',
18        'RootTransaction', 'RowProxy', 'SchemaIterator', 'StringIO', 'Transaction', 'TwoPhaseTransaction', 'connection_memoize']
19
20import inspect, StringIO
21from sqlalchemy import exc, schema, util, types, log
22from sqlalchemy.sql import expression
23
24class Dialect(object):
25    """Define the behavior of a specific database and DB-API combination.
26
27    Any aspect of metadata definition, SQL query generation,
28    execution, result-set handling, or anything else which varies
29    between databases is defined under the general category of the
30    Dialect.  The Dialect acts as a factory for other
31    database-specific object implementations including
32    ExecutionContext, Compiled, DefaultGenerator, and TypeEngine.
33
34    All Dialects implement the following attributes:
35   
36    name
37      identifying name for the dialect (i.e. 'sqlite')
38     
39    positional
40      True if the paramstyle for this Dialect is positional.
41
42    paramstyle
43      the paramstyle to be used (some DB-APIs support multiple
44      paramstyles).
45
46    convert_unicode
47      True if Unicode conversion should be applied to all ``str``
48      types.
49
50    encoding
51      type of encoding to use for unicode, usually defaults to
52      'utf-8'.
53
54    schemagenerator
55      a :class:`~sqlalchemy.schema.SchemaVisitor` class which generates
56      schemas.
57
58    schemadropper
59      a :class:`~sqlalchemy.schema.SchemaVisitor` class which drops schemas.
60
61    defaultrunner
62      a :class:`~sqlalchemy.schema.SchemaVisitor` class which executes
63      defaults.
64
65    statement_compiler
66      a :class:`~sqlalchemy.engine.base.Compiled` class used to compile SQL
67      statements
68
69    preparer
70      a :class:`~sqlalchemy.sql.compiler.IdentifierPreparer` class used to
71      quote identifiers.
72
73    supports_alter
74      ``True`` if the database supports ``ALTER TABLE``.
75
76    max_identifier_length
77      The maximum length of identifier names.
78
79    supports_unicode_statements
80      Indicate whether the DB-API can receive SQL statements as Python unicode strings
81
82    supports_sane_rowcount
83      Indicate whether the dialect properly implements rowcount for ``UPDATE`` and ``DELETE`` statements.
84
85    supports_sane_multi_rowcount
86      Indicate whether the dialect properly implements rowcount for ``UPDATE`` and ``DELETE`` statements
87      when executed via executemany.
88
89    preexecute_pk_sequences
90      Indicate if the dialect should pre-execute sequences on primary key
91      columns during an INSERT, if it's desired that the new row's primary key
92      be available after execution.
93
94    supports_pk_autoincrement
95      Indicates if the dialect should allow the database to passively assign
96      a primary key column value.
97
98    dbapi_type_map
99      A mapping of DB-API type objects present in this Dialect's
100      DB-API implmentation mapped to TypeEngine implementations used
101      by the dialect.
102
103      This is used to apply types to result sets based on the DB-API
104      types present in cursor.description; it only takes effect for
105      result sets against textual statements where no explicit
106      typemap was present.
107
108    supports_default_values
109      Indicates if the construct ``INSERT INTO tablename DEFAULT VALUES`` is supported
110
111    description_encoding
112      type of encoding to use for unicode when working with metadata
113      descriptions. If set to ``None`` no encoding will be done.
114      This usually defaults to 'utf-8'.
115    """
116
117    def create_connect_args(self, url):
118        """Build DB-API compatible connection arguments.
119
120        Given a :class:`~sqlalchemy.engine.url.URL` object, returns a tuple
121        consisting of a `*args`/`**kwargs` suitable to send directly
122        to the dbapi's connect function.
123        """
124
125        raise NotImplementedError()
126
127
128    def type_descriptor(self, typeobj):
129        """Transform a generic type to a database-specific type.
130
131        Transforms the given :class:`~sqlalchemy.types.TypeEngine` instance
132        from generic to database-specific.
133
134        Subclasses will usually use the
135        :func:`~sqlalchemy.types.adapt_type` method in the types module to
136        make this job easy.
137        """
138
139        raise NotImplementedError()
140
141
142    def server_version_info(self, connection):
143        """Return a tuple of the database's version number."""
144
145        raise NotImplementedError()
146
147    def reflecttable(self, connection, table, include_columns=None):
148        """Load table description from the database.
149
150        Given a :class:`~sqlalchemy.engine.Connection` and a
151        :class:`~sqlalchemy.schema.Table` object, reflect its columns and
152        properties from the database.  If include_columns (a list or
153        set) is specified, limit the autoload to the given column
154        names.
155        """
156
157        raise NotImplementedError()
158
159    def has_table(self, connection, table_name, schema=None):
160        """Check the existence of a particular table in the database.
161
162        Given a :class:`~sqlalchemy.engine.Connection` object and a string
163        `table_name`, return True if the given table (possibly within
164        the specified `schema`) exists in the database, False
165        otherwise.
166        """
167
168        raise NotImplementedError()
169
170    def has_sequence(self, connection, sequence_name, schema=None):
171        """Check the existence of a particular sequence in the database.
172
173        Given a :class:`~sqlalchemy.engine.Connection` object and a string
174        `sequence_name`, return True if the given sequence exists in
175        the database, False otherwise.
176        """
177
178        raise NotImplementedError()
179
180    def get_default_schema_name(self, connection):
181        """Return the string name of the currently selected schema given a :class:`~sqlalchemy.engine.Connection`."""
182
183        raise NotImplementedError()
184
185    def do_begin(self, connection):
186        """Provide an implementation of *connection.begin()*, given a DB-API connection."""
187
188        raise NotImplementedError()
189
190    def do_rollback(self, connection):
191        """Provide an implementation of *connection.rollback()*, given a DB-API connection."""
192
193        raise NotImplementedError()
194
195    def create_xid(self):
196        """Create a two-phase transaction ID.
197
198        This id will be passed to do_begin_twophase(),
199        do_rollback_twophase(), do_commit_twophase().  Its format is
200        unspecified.
201        """
202
203        raise NotImplementedError()
204
205    def do_commit(self, connection):
206        """Provide an implementation of *connection.commit()*, given a DB-API connection."""
207
208        raise NotImplementedError()
209
210    def do_savepoint(self, connection, name):
211        """Create a savepoint with the given name on a SQLAlchemy connection."""
212
213        raise NotImplementedError()
214
215    def do_rollback_to_savepoint(self, connection, name):
216        """Rollback a SQL Alchemy connection to the named savepoint."""
217
218        raise NotImplementedError()
219
220    def do_release_savepoint(self, connection, name):
221        """Release the named savepoint on a SQL Alchemy connection."""
222
223        raise NotImplementedError()
224
225    def do_begin_twophase(self, connection, xid):
226        """Begin a two phase transaction on the given connection."""
227
228        raise NotImplementedError()
229
230    def do_prepare_twophase(self, connection, xid):
231        """Prepare a two phase transaction on the given connection."""
232
233        raise NotImplementedError()
234
235    def do_rollback_twophase(self, connection, xid, is_prepared=True, recover=False):
236        """Rollback a two phase transaction on the given connection."""
237
238        raise NotImplementedError()
239
240    def do_commit_twophase(self, connection, xid, is_prepared=True, recover=False):
241        """Commit a two phase transaction on the given connection."""
242
243        raise NotImplementedError()
244
245    def do_recover_twophase(self, connection):
246        """Recover list of uncommited prepared two phase transaction identifiers on the given connection."""
247
248        raise NotImplementedError()
249
250    def do_executemany(self, cursor, statement, parameters, context=None):
251        """Provide an implementation of *cursor.executemany(statement, parameters)*."""
252
253        raise NotImplementedError()
254
255    def do_execute(self, cursor, statement, parameters, context=None):
256        """Provide an implementation of *cursor.execute(statement, parameters)*."""
257
258        raise NotImplementedError()
259
260    def is_disconnect(self, e):
261        """Return True if the given DB-API error indicates an invalid connection"""
262
263        raise NotImplementedError()
264
265
266class ExecutionContext(object):
267    """A messenger object for a Dialect that corresponds to a single execution.
268
269    ExecutionContext should have these datamembers:
270
271    connection
272      Connection object which can be freely used by default value
273      generators to execute SQL.  This Connection should reference the
274      same underlying connection/transactional resources of
275      root_connection.
276
277    root_connection
278      Connection object which is the source of this ExecutionContext.  This
279      Connection may have close_with_result=True set, in which case it can
280      only be used once.
281
282    dialect
283      dialect which created this ExecutionContext.
284
285    cursor
286      DB-API cursor procured from the connection,
287
288    compiled
289      if passed to constructor, sqlalchemy.engine.base.Compiled object
290      being executed,
291
292    statement
293      string version of the statement to be executed.  Is either
294      passed to the constructor, or must be created from the
295      sql.Compiled object by the time pre_exec() has completed.
296
297    parameters
298      bind parameters passed to the execute() method.  For compiled
299      statements, this is a dictionary or list of dictionaries.  For
300      textual statements, it should be in a format suitable for the
301      dialect's paramstyle (i.e. dict or list of dicts for non
302      positional, list or list of lists/tuples for positional).
303
304    isinsert
305      True if the statement is an INSERT.
306
307    isupdate
308      True if the statement is an UPDATE.
309
310    should_autocommit
311      True if the statement is a "committable" statement
312
313    postfetch_cols
314     a list of Column objects for which a server-side default
315     or inline SQL expression value was fired off.  applies to inserts and updates.
316
317
318    """
319
320    def create_cursor(self):
321        """Return a new cursor generated from this ExecutionContext's connection.
322
323        Some dialects may wish to change the behavior of
324        connection.cursor(), such as postgres which may return a PG
325        "server side" cursor.
326        """
327
328        raise NotImplementedError()
329
330    def pre_exec(self):
331        """Called before an execution of a compiled statement.
332
333        If a compiled statement was passed to this ExecutionContext,
334        the `statement` and `parameters` datamembers must be
335        initialized after this statement is complete.
336        """
337
338        raise NotImplementedError()
339
340    def post_exec(self):
341        """Called after the execution of a compiled statement.
342
343        If a compiled statement was passed to this ExecutionContext,
344        the `last_insert_ids`, `last_inserted_params`, etc.
345        datamembers should be available after this method completes.
346        """
347
348        raise NotImplementedError()
349
350    def result(self):
351        """Return a result object corresponding to this ExecutionContext.
352
353        Returns a ResultProxy.
354        """
355
356        raise NotImplementedError()
357
358    def handle_dbapi_exception(self, e):
359        """Receive a DBAPI exception which occured upon execute, result fetch, etc."""
360       
361        raise NotImplementedError()
362       
363    def should_autocommit_text(self, statement):
364        """Parse the given textual statement and return True if it refers to a "committable" statement"""
365
366        raise NotImplementedError()
367
368    def last_inserted_ids(self):
369        """Return the list of the primary key values for the last insert statement executed.
370
371        This does not apply to straight textual clauses; only to
372        ``sql.Insert`` objects compiled against a ``schema.Table``
373        object.  The order of items in the list is the same as that of
374        the Table's 'primary_key' attribute.
375        """
376
377        raise NotImplementedError()
378
379    def last_inserted_params(self):
380        """Return a dictionary of the full parameter dictionary for the last compiled INSERT statement.
381
382        Includes any ColumnDefaults or Sequences that were pre-executed.
383        """
384
385        raise NotImplementedError()
386
387    def last_updated_params(self):
388        """Return a dictionary of the full parameter dictionary for the last compiled UPDATE statement.
389
390        Includes any ColumnDefaults that were pre-executed.
391        """
392
393        raise NotImplementedError()
394
395    def lastrow_has_defaults(self):
396        """Return True if the last INSERT or UPDATE row contained
397        inlined or database-side defaults.
398        """
399
400        raise NotImplementedError()
401
402
403class Compiled(object):
404    """Represent a compiled SQL expression.
405
406    The ``__str__`` method of the ``Compiled`` object should produce
407    the actual text of the statement.  ``Compiled`` objects are
408    specific to their underlying database dialect, and also may
409    or may not be specific to the columns referenced within a
410    particular set of bind parameters.  In no case should the
411    ``Compiled`` object be dependent on the actual values of those
412    bind parameters, even though it may reference those values as
413    defaults.
414    """
415
416    def __init__(self, dialect, statement, column_keys=None, bind=None):
417        """Construct a new ``Compiled`` object.
418
419        dialect
420          ``Dialect`` to compile against.
421
422        statement
423          ``ClauseElement`` to be compiled.
424
425        column_keys
426          a list of column names to be compiled into an INSERT or UPDATE
427          statement.
428
429        bind
430          Optional Engine or Connection to compile this statement against.
431         
432        """
433        self.dialect = dialect
434        self.statement = statement
435        self.column_keys = column_keys
436        self.bind = bind
437        self.can_execute = statement.supports_execution
438
439    def compile(self):
440        """Produce the internal string representation of this element."""
441
442        raise NotImplementedError()
443
444    def __str__(self):
445        """Return the string text of the generated SQL statement."""
446
447        raise NotImplementedError()
448
449    @util.deprecated('Deprecated. Use construct_params(). '
450                     '(supports Unicode key names.)')
451    def get_params(self, **params):
452        return self.construct_params(params)
453
454    def construct_params(self, params):
455        """Return the bind params for this compiled object.
456
457        `params` is a dict of string/object pairs whos
458        values will override bind values compiled in
459        to the statement.
460        """
461        raise NotImplementedError()
462
463    def execute(self, *multiparams, **params):
464        """Execute this compiled object."""
465
466        e = self.bind
467        if e is None:
468            raise exc.UnboundExecutionError("This Compiled object is not bound to any Engine or Connection.")
469        return e._execute_compiled(self, multiparams, params)
470
471    def scalar(self, *multiparams, **params):
472        """Execute this compiled object and return the result's scalar value."""
473
474        return self.execute(*multiparams, **params).scalar()
475
476
477class Connectable(object):
478    """Interface for an object which supports execution of SQL constructs.
479   
480    The two implementations of ``Connectable`` are :class:`Connection` and
481    :class:`Engine`.
482   
483    """
484
485    def contextual_connect(self):
486        """Return a Connection object which may be part of an ongoing context."""
487
488        raise NotImplementedError()
489
490    def create(self, entity, **kwargs):
491        """Create a table or index given an appropriate schema object."""
492
493        raise NotImplementedError()
494
495    def drop(self, entity, **kwargs):
496        """Drop a table or index given an appropriate schema object."""
497
498        raise NotImplementedError()
499
500    def execute(self, object, *multiparams, **params):
501        raise NotImplementedError()
502
503    def _execute_clauseelement(self, elem, multiparams=None, params=None):
504        raise NotImplementedError()
505
506class Connection(Connectable):
507    """Provides high-level functionality for a wrapped DB-API connection.
508
509    Provides execution support for string-based SQL statements as well
510    as ClauseElement, Compiled and DefaultGenerator objects.  Provides
511    a begin method to return Transaction objects.
512
513    The Connection object is **not** thread-safe.
514
515    .. index::
516      single: thread safety; Connection
517
518    """
519
520    def __init__(self, engine, connection=None, close_with_result=False,
521                 _branch=False):
522        """Construct a new Connection.
523
524        Connection objects are typically constructed by an
525        :class:`~sqlalchemy.engine.Engine`, see the ``connect()`` and
526        ``contextual_connect()`` methods of Engine.
527       
528        """
529
530        self.engine = engine
531        self.__connection = connection or engine.raw_connection()
532        self.__transaction = None
533        self.__close_with_result = close_with_result
534        self.__savepoint_seq = 0
535        self.__branch = _branch
536        self.__invalid = False
537       
538    def _branch(self):
539        """Return a new Connection which references this Connection's
540        engine and connection; but does not have close_with_result enabled,
541        and also whose close() method does nothing.
542
543        This is used to execute "sub" statements within a single execution,
544        usually an INSERT statement.
545       
546        """
547        return self.engine.Connection(self.engine, self.__connection, _branch=True)
548
549    @property
550    def dialect(self):
551        "Dialect used by this Connection."
552
553        return self.engine.dialect
554
555    @property
556    def closed(self):
557        """return True if this connection is closed."""
558
559        return not self.__invalid and '_Connection__connection' not in self.__dict__
560
561    @property
562    def invalidated(self):
563        """return True if this connection was invalidated."""
564
565        return self.__invalid
566
567    @property
568    def connection(self):
569        "The underlying DB-API connection managed by this Connection."
570
571        try:
572            return self.__connection
573        except AttributeError:
574            if self.__invalid:
575                if self.__transaction is not None:
576                    raise exc.InvalidRequestError("Can't reconnect until invalid transaction is rolled back")
577                self.__connection = self.engine.raw_connection()
578                self.__invalid = False
579                return self.__connection
580            raise exc.InvalidRequestError("This Connection is closed")
581
582    @property
583    def should_close_with_result(self):
584        """Indicates if this Connection should be closed when a corresponding
585        ResultProxy is closed; this is essentially an auto-release mode.
586       
587        """
588        return self.__close_with_result
589
590    @property
591    def info(self):
592        """A collection of per-DB-API connection instance properties."""
593        return self.connection.info
594
595    def connect(self):
596        """Returns self.
597
598        This ``Connectable`` interface method returns self, allowing
599        Connections to be used interchangably with Engines in most
600        situations that require a bind.
601
602        """
603        return self
604
605    def contextual_connect(self, **kwargs):
606        """Returns self.
607
608        This ``Connectable`` interface method returns self, allowing
609        Connections to be used interchangably with Engines in most
610        situations that require a bind.
611
612        """
613        return self
614
615    def invalidate(self, exception=None):
616        """Invalidate the underlying DBAPI connection associated with this Connection.
617
618        The underlying DB-API connection is literally closed (if
619        possible), and is discarded.  Its source connection pool will
620        typically lazily create a new connection to replace it.
621
622        Upon the next usage, this Connection will attempt to reconnect
623        to the pool with a new connection.
624
625        Transactions in progress remain in an "opened" state (even though
626        the actual transaction is gone); these must be explicitly
627        rolled back before a reconnect on this Connection can proceed.  This
628        is to prevent applications from accidentally continuing their transactional
629        operations in a non-transactional state.
630
631        """
632        if self.closed:
633            raise exc.InvalidRequestError("This Connection is closed")
634
635        if self.__connection.is_valid:
636            self.__connection.invalidate(exception)
637        del self.__connection
638        self.__invalid = True
639
640    def detach(self):
641        """Detach the underlying DB-API connection from its connection pool.
642
643        This Connection instance will remain useable.  When closed,
644        the DB-API connection will be literally closed and not
645        returned to its pool.  The pool will typically lazily create a
646        new connection to replace the detached connection.
647
648        This method can be used to insulate the rest of an application
649        from a modified state on a connection (such as a transaction
650        isolation level or similar).  Also see
651        :class:`~sqlalchemy.interfaces.PoolListener` for a mechanism to modify
652        connection state when connections leave and return to their
653        connection pool.
654
655        """
656        self.__connection.detach()
657
658    def begin(self):
659        """Begin a transaction and return a Transaction handle.
660
661        Repeated calls to ``begin`` on the same Connection will create
662        a lightweight, emulated nested transaction.  Only the
663        outermost transaction may ``commit``.  Calls to ``commit`` on
664        inner transactions are ignored.  Any transaction in the
665        hierarchy may ``rollback``, however.
666
667        """
668        if self.__transaction is None:
669            self.__transaction = RootTransaction(self)
670        else:
671            return Transaction(self, self.__transaction)
672        return self.__transaction
673
674    def begin_nested(self):
675        """Begin a nested transaction and return a Transaction handle.
676
677        Nested transactions require SAVEPOINT support in the
678        underlying database.  Any transaction in the hierarchy may
679        ``commit`` and ``rollback``, however the outermost transaction
680        still controls the overall ``commit`` or ``rollback`` of the
681        transaction of a whole.
682        """
683
684        if self.__transaction is None:
685            self.__transaction = RootTransaction(self)
686        else:
687            self.__transaction = NestedTransaction(self, self.__transaction)
688        return self.__transaction
689
690    def begin_twophase(self, xid=None):
691        """Begin a two-phase or XA transaction and return a Transaction handle.
692
693        xid
694          the two phase transaction id.  If not supplied, a random id
695          will be generated.
696        """
697
698        if self.__transaction is not None:
699            raise exc.InvalidRequestError(
700                "Cannot start a two phase transaction when a transaction "
701                "is already in progress.")
702        if xid is None:
703            xid = self.engine.dialect.create_xid();
704        self.__transaction = TwoPhaseTransaction(self, xid)
705        return self.__transaction
706
707    def recover_twophase(self):
708        return self.engine.dialect.do_recover_twophase(self)
709
710    def rollback_prepared(self, xid, recover=False):
711        self.engine.dialect.do_rollback_twophase(self, xid, recover=recover)
712
713    def commit_prepared(self, xid, recover=False):
714        self.engine.dialect.do_commit_twophase(self, xid, recover=recover)
715
716    def in_transaction(self):
717        """Return True if a transaction is in progress."""
718
719        return self.__transaction is not None
720
721    def _begin_impl(self):
722        if self.engine._should_log_info:
723            self.engine.logger.info("BEGIN")
724        try:
725            self.engine.dialect.do_begin(self.connection)
726        except Exception, e:
727            self._handle_dbapi_exception(e, None, None, None, None)
728            raise
729
730    def _rollback_impl(self):
731        if not self.closed and not self.invalidated and self.__connection.is_valid:
732            if self.engine._should_log_info:
733                self.engine.logger.info("ROLLBACK")
734            try:
735                self.engine.dialect.do_rollback(self.connection)
736                self.__transaction = None
737            except Exception, e:
738                self._handle_dbapi_exception(e, None, None, None, None)
739                raise
740        else:
741            self.__transaction = None
742
743    def _commit_impl(self):
744        if self.engine._should_log_info:
745            self.engine.logger.info("COMMIT")
746        try:
747            self.engine.dialect.do_commit(self.connection)
748            self.__transaction = None
749        except Exception, e:
750            self._handle_dbapi_exception(e, None, None, None, None)
751            raise
752
753    def _savepoint_impl(self, name=None):
754        if name is None:
755            self.__savepoint_seq += 1
756            name = 'sa_savepoint_%s' % self.__savepoint_seq
757        if self.__connection.is_valid:
758            self.engine.dialect.do_savepoint(self, name)
759            return name
760
761    def _rollback_to_savepoint_impl(self, name, context):
762        if self.__connection.is_valid:
763            self.engine.dialect.do_rollback_to_savepoint(self, name)
764        self.__transaction = context
765
766    def _release_savepoint_impl(self, name, context):
767        if self.__connection.is_valid:
768            self.engine.dialect.do_release_savepoint(self, name)
769        self.__transaction = context
770
771    def _begin_twophase_impl(self, xid):
772        if self.__connection.is_valid:
773            self.engine.dialect.do_begin_twophase(self, xid)
774
775    def _prepare_twophase_impl(self, xid):
776        if self.__connection.is_valid:
777            assert isinstance(self.__transaction, TwoPhaseTransaction)
778            self.engine.dialect.do_prepare_twophase(self, xid)
779
780    def _rollback_twophase_impl(self, xid, is_prepared):
781        if self.__connection.is_valid:
782            assert isinstance(self.__transaction, TwoPhaseTransaction)
783            self.engine.dialect.do_rollback_twophase(self, xid, is_prepared)
784        self.__transaction = None
785
786    def _commit_twophase_impl(self, xid, is_prepared):
787        if self.__connection.is_valid:
788            assert isinstance(self.__transaction, TwoPhaseTransaction)
789            self.engine.dialect.do_commit_twophase(self, xid, is_prepared)
790        self.__transaction = None
791
792    def _autorollback(self):
793        if not self.in_transaction():
794            self._rollback_impl()
795
796    def close(self):
797        """Close this Connection."""
798
799        try:
800            conn = self.__connection
801        except AttributeError:
802            return
803        if not self.__branch:
804            conn.close()
805        self.__invalid = False
806        del self.__connection
807
808    def scalar(self, object, *multiparams, **params):
809        """Executes and returns the first column of the first row.
810
811        The underlying result/cursor is closed after execution.
812        """
813
814        return self.execute(object, *multiparams, **params).scalar()
815
816    def statement_compiler(self, statement, **kwargs):
817        return self.dialect.statement_compiler(self.dialect, statement, bind=self, **kwargs)
818
819    def execute(self, object, *multiparams, **params):
820        """Executes and returns a ResultProxy."""
821
822        for c in type(object).__mro__:
823            if c in Connection.executors:
824                return Connection.executors[c](self, object, multiparams, params)
825        else:
826            raise exc.InvalidRequestError("Unexecutable object type: " + str(type(object)))
827
828    def __distill_params(self, multiparams, params):
829        """given arguments from the calling form *multiparams, **params, return a list
830        of bind parameter structures, usually a list of dictionaries.
831
832        in the case of 'raw' execution which accepts positional parameters,
833        it may be a list of tuples or lists."""
834
835        if not multiparams:
836            if params:
837                return [params]
838            else:
839                return []
840        elif len(multiparams) == 1:
841            zero = multiparams[0]
842            if isinstance(zero, (list, tuple)):
843                if not zero or hasattr(zero[0], '__iter__'):
844                    return zero
845                else:
846                    return [zero]
847            elif hasattr(zero, 'keys'):
848                return [zero]
849            else:
850                return [[zero]]
851        else:
852            if hasattr(multiparams[0], '__iter__'):
853                return multiparams
854            else:
855                return [multiparams]
856
857    def _execute_function(self, func, multiparams, params):
858        return self._execute_clauseelement(func.select(), multiparams, params)
859
860    def _execute_default(self, default, multiparams, params):
861        return self.engine.dialect.defaultrunner(self.__create_execution_context()).traverse_single(default)
862
863    def _execute_clauseelement(self, elem, multiparams, params):
864        params = self.__distill_params(multiparams, params)
865        if params:
866            keys = params[0].keys()
867        else:
868            keys = []
869
870        context = self.__create_execution_context(
871                        compiled=elem.compile(dialect=self.dialect, column_keys=keys, inline=len(params) > 1),
872                        parameters=params
873                    )
874        return self.__execute_context(context)
875
876    def _execute_compiled(self, compiled, multiparams, params):
877        """Execute a sql.Compiled object."""
878
879        context = self.__create_execution_context(
880                    compiled=compiled,
881                    parameters=self.__distill_params(multiparams, params)
882                )
883        return self.__execute_context(context)
884
885    def _execute_text(self, statement, multiparams, params):
886        parameters = self.__distill_params(multiparams, params)
887        context = self.__create_execution_context(statement=statement, parameters=parameters)
888        return self.__execute_context(context)
889   
890    def __execute_context(self, context):
891        if context.compiled:
892            context.pre_exec()
893        if context.executemany:
894            self._cursor_executemany(context.cursor, context.statement, context.parameters, context=context)
895        else:
896            self._cursor_execute(context.cursor, context.statement, context.parameters[0], context=context)
897        if context.compiled:
898            context.post_exec()
899        if context.should_autocommit and not self.in_transaction():
900            self._commit_impl()
901        return context.get_result_proxy()
902       
903    def _execute_ddl(self, ddl, params, multiparams):
904        if params:
905            schema_item, params = params[0], params[1:]
906        else:
907            schema_item = None
908        return ddl(None, schema_item, self, *params, **multiparams)
909
910    def _handle_dbapi_exception(self, e, statement, parameters, cursor, context):
911        if getattr(self, '_reentrant_error', False):
912            raise exc.DBAPIError.instance(None, None, e)
913        self._reentrant_error = True
914        try:
915            if not isinstance(e, self.dialect.dbapi.Error):
916                return
917               
918            if context:
919                context.handle_dbapi_exception(e)
920               
921            is_disconnect = self.dialect.is_disconnect(e)
922            if is_disconnect:
923                self.invalidate(e)
924                self.engine.dispose()
925            else:
926                if cursor:
927                    cursor.close()
928                self._autorollback()
929                if self.__close_with_result:
930                    self.close()
931            raise exc.DBAPIError.instance(statement, parameters, e, connection_invalidated=is_disconnect)
932        finally:
933            del self._reentrant_error
934
935    def __create_execution_context(self, **kwargs):
936        try:
937            dialect = self.engine.dialect
938            return dialect.execution_ctx_cls(dialect, connection=self, **kwargs)
939        except Exception, e:
940            self._handle_dbapi_exception(e, kwargs.get('statement', None), kwargs.get('parameters', None), None, None)
941            raise
942
943    def _cursor_execute(self, cursor, statement, parameters, context=None):
944        if self.engine._should_log_info:
945            self.engine.logger.info(statement)
946            self.engine.logger.info(repr(parameters))
947        try:
948            self.dialect.do_execute(cursor, statement, parameters, context=context)
949        except Exception, e:
950            self._handle_dbapi_exception(e, statement, parameters, cursor, context)
951            raise
952
953    def _cursor_executemany(self, cursor, statement, parameters, context=None):
954        if self.engine._should_log_info:
955            self.engine.logger.info(statement)
956            self.engine.logger.info(repr(parameters))
957        try:
958            self.dialect.do_executemany(cursor, statement, parameters, context=context)
959        except Exception, e:
960            self._handle_dbapi_exception(e, statement, parameters, cursor, context)
961            raise
962
963    # poor man's multimethod/generic function thingy
964    executors = {
965        expression.Function: _execute_function,
966        expression.ClauseElement: _execute_clauseelement,
967        Compiled: _execute_compiled,
968        schema.SchemaItem: _execute_default,
969        schema.DDL: _execute_ddl,
970        basestring: _execute_text
971    }
972
973    def create(self, entity, **kwargs):
974        """Create a Table or Index given an appropriate Schema object."""
975
976        return self.engine.create(entity, connection=self, **kwargs)
977
978    def drop(self, entity, **kwargs):
979        """Drop a Table or Index given an appropriate Schema object."""
980
981        return self.engine.drop(entity, connection=self, **kwargs)
982
983    def reflecttable(self, table, include_columns=None):
984        """Reflect the columns in the given string table name from the database."""
985
986        return self.engine.reflecttable(table, self, include_columns)
987
988    def default_schema_name(self):
989        return self.engine.dialect.get_default_schema_name(self)
990
991    def run_callable(self, callable_):
992        return callable_(self)
993
994class Transaction(object):
995    """Represent a Transaction in progress.
996
997    The Transaction object is **not** threadsafe.
998
999    .. index::
1000      single: thread safety; Transaction
1001
1002    """
1003
1004    def __init__(self, connection, parent):
1005        self.connection = connection
1006        self._parent = parent or self
1007        self.is_active = True
1008   
1009    def close(self):
1010        """Close this transaction.
1011
1012        If this transaction is the base transaction in a begin/commit
1013        nesting, the transaction will rollback().  Otherwise, the
1014        method returns.
1015
1016        This is used to cancel a Transaction without affecting the scope of
1017        an enclosing transaction.
1018        """
1019        if not self._parent.is_active:
1020            return
1021        if self._parent is self:
1022            self.rollback()
1023
1024    def rollback(self):
1025        if not self._parent.is_active:
1026            return
1027        self.is_active = False
1028        self._do_rollback()
1029
1030    def _do_rollback(self):
1031        self._parent.rollback()
1032
1033    def commit(self):
1034        if not self._parent.is_active:
1035            raise exc.InvalidRequestError("This transaction is inactive")
1036        self._do_commit()
1037        self.is_active = False
1038
1039    def _do_commit(self):
1040        pass
1041
1042    def __enter__(self):
1043        return self
1044
1045    def __exit__(self, type, value, traceback):
1046        if type is None and self.is_active:
1047            self.commit()
1048        else:
1049            self.rollback()
1050
1051class RootTransaction(Transaction):
1052    def __init__(self, connection):
1053        super(RootTransaction, self).__init__(connection, None)
1054        self.connection._begin_impl()
1055
1056    def _do_rollback(self):
1057        self.connection._rollback_impl()
1058
1059    def _do_commit(self):
1060        self.connection._commit_impl()
1061
1062class NestedTransaction(Transaction):
1063    def __init__(self, connection, parent):
1064        super(NestedTransaction, self).__init__(connection, parent)
1065        self._savepoint = self.connection._savepoint_impl()
1066
1067    def _do_rollback(self):
1068        self.connection._rollback_to_savepoint_impl(self._savepoint, self._parent)
1069
1070    def _do_commit(self):
1071        self.connection._release_savepoint_impl(self._savepoint, self._parent)
1072
1073class TwoPhaseTransaction(Transaction):
1074    def __init__(self, connection, xid):
1075        super(TwoPhaseTransaction, self).__init__(connection, None)
1076        self._is_prepared = False
1077        self.xid = xid
1078        self.connection._begin_twophase_impl(self.xid)
1079
1080    def prepare(self):
1081        if not self._parent.is_active:
1082            raise exc.InvalidRequestError("This transaction is inactive")
1083        self.connection._prepare_twophase_impl(self.xid)
1084        self._is_prepared = True
1085
1086    def _do_rollback(self):
1087        self.connection._rollback_twophase_impl(self.xid, self._is_prepared)
1088
1089    def _do_commit(self):
1090        self.connection._commit_twophase_impl(self.xid, self._is_prepared)
1091
1092class Engine(Connectable):
1093    """
1094    Connects a :class:`~sqlalchemy.pool.Pool` and :class:`~sqlalchemy.engine.base.Dialect`
1095    together to provide a source of database connectivity and behavior.
1096
1097    """
1098
1099    def __init__(self, pool, dialect, url, echo=None, proxy=None):
1100        self.pool = pool
1101        self.url = url
1102        self.dialect = dialect
1103        self.echo = echo
1104        self.engine = self
1105        self.logger = log.instance_logger(self, echoflag=echo)
1106        if proxy:
1107            self.Connection = _proxy_connection_cls(Connection, proxy)
1108        else:
1109            self.Connection = Connection
1110
1111    @property
1112    def name(self):
1113        "String name of the :class:`~sqlalchemy.engine.Dialect` in use by this ``Engine``."
1114       
1115        return self.dialect.name
1116
1117    echo = log.echo_property()
1118
1119    def __repr__(self):
1120        return 'Engine(%s)' % str(self.url)
1121
1122    def dispose(self):
1123        self.pool.dispose()
1124        self.pool = self.pool.recreate()
1125
1126    def create(self, entity, connection=None, **kwargs):
1127        """Create a table or index within this engine's database connection given a schema.Table object."""
1128
1129        self._run_visitor(self.dialect.schemagenerator, entity, connection=connection, **kwargs)
1130
1131    def drop(self, entity, connection=None, **kwargs):
1132        """Drop a table or index within this engine's database connection given a schema.Table object."""
1133
1134        self._run_visitor(self.dialect.schemadropper, entity, connection=connection, **kwargs)
1135
1136    def _execute_default(self, default):
1137        connection = self.contextual_connect()
1138        try:
1139            return connection._execute_default(default, (), {})
1140        finally:
1141            connection.close()
1142
1143    @property
1144    def func(self):
1145        return expression._FunctionGenerator(bind=self)
1146
1147    def text(self, text, *args, **kwargs):
1148        """Return a sql.text() object for performing literal queries."""
1149
1150        return expression.text(text, bind=self, *args, **kwargs)
1151
1152    def _run_visitor(self, visitorcallable, element, connection=None, **kwargs):
1153        if connection is None:
1154            conn = self.contextual_connect(close_with_result=False)
1155        else:
1156            conn = connection
1157        try:
1158            visitorcallable(self.dialect, conn, **kwargs).traverse(element)
1159        finally:
1160            if connection is None:
1161                conn.close()
1162
1163    def transaction(self, callable_, connection=None, *args, **kwargs):
1164        """Execute the given function within a transaction boundary.
1165
1166        This is a shortcut for explicitly calling `begin()` and `commit()`
1167        and optionally `rollback()` when exceptions are raised.  The
1168        given `*args` and `**kwargs` will be passed to the function, as
1169        well as the Connection used in the transaction.
1170        """
1171
1172        if connection is None:
1173            conn = self.contextual_connect()
1174        else:
1175            conn = connection
1176        try:
1177            trans = conn.begin()
1178            try:
1179                ret = callable_(conn, *args, **kwargs)
1180                trans.commit()
1181                return ret
1182            except:
1183                trans.rollback()
1184                raise
1185        finally:
1186            if connection is None:
1187                conn.close()
1188
1189    def run_callable(self, callable_, connection=None, *args, **kwargs):
1190        if connection is None:
1191            conn = self.contextual_connect()
1192        else:
1193            conn = connection
1194        try:
1195            return callable_(conn, *args, **kwargs)
1196        finally:
1197            if connection is None:
1198                conn.close()
1199
1200    def execute(self, statement, *multiparams, **params):
1201        connection = self.contextual_connect(close_with_result=True)
1202        return connection.execute(statement, *multiparams, **params)
1203
1204    def scalar(self, statement, *multiparams, **params):
1205        return self.execute(statement, *multiparams, **params).scalar()
1206
1207    def _execute_clauseelement(self, elem, multiparams=None, params=None):
1208        connection = self.contextual_connect(close_with_result=True)
1209        return connection._execute_clauseelement(elem, multiparams, params)
1210
1211    def _execute_compiled(self, compiled, multiparams, params):
1212        connection = self.contextual_connect(close_with_result=True)
1213        return connection._execute_compiled(compiled, multiparams, params)
1214
1215    def statement_compiler(self, statement, **kwargs):
1216        return self.dialect.statement_compiler(self.dialect, statement, bind=self, **kwargs)
1217
1218    def connect(self, **kwargs):
1219        """Return a newly allocated Connection object."""
1220
1221        return self.Connection(self, **kwargs)
1222
1223    def contextual_connect(self, close_with_result=False, **kwargs):
1224        """Return a Connection object which may be newly allocated, or may be part of some ongoing context.
1225
1226        This Connection is meant to be used by the various "auto-connecting" operations.
1227        """
1228
1229        return self.Connection(self, self.pool.connect(), close_with_result=close_with_result, **kwargs)
1230
1231    def table_names(self, schema=None, connection=None):
1232        """Return a list of all table names available in the database.
1233
1234        schema:
1235          Optional, retrieve names from a non-default schema.
1236
1237        connection:
1238          Optional, use a specified connection.  Default is the
1239          ``contextual_connect`` for this ``Engine``.
1240        """
1241
1242        if connection is None:
1243            conn = self.contextual_connect()
1244        else:
1245            conn = connection
1246        if not schema:
1247            try:
1248                schema =  self.dialect.get_default_schema_name(conn)
1249            except NotImplementedError:
1250                pass
1251        try:
1252            return self.dialect.table_names(conn, schema)
1253        finally:
1254            if connection is None:
1255                conn.close()
1256
1257    def reflecttable(self, table, connection=None, include_columns=None):
1258        """Given a Table object, reflects its columns and properties from the database."""
1259
1260        if connection is None:
1261            conn = self.contextual_connect()
1262        else:
1263            conn = connection
1264        try:
1265            self.dialect.reflecttable(conn, table, include_columns)
1266        finally:
1267            if connection is None:
1268                conn.close()
1269
1270    def has_table(self, table_name, schema=None):
1271        return self.run_callable(lambda c: self.dialect.has_table(c, table_name, schema=schema))
1272
1273    def raw_connection(self):
1274        """Return a DB-API connection."""
1275
1276        return self.pool.unique_connection()
1277
1278def _proxy_connection_cls(cls, proxy):
1279    class ProxyConnection(cls):
1280        def execute(self, object, *multiparams, **params):
1281            return proxy.execute(self, super(ProxyConnection, self).execute, object, *multiparams, **params)
1282 
1283        def _execute_clauseelement(self, elem, multiparams=None, params=None):
1284            return proxy.execute(self, super(ProxyConnection, self).execute, elem, *(multiparams or []), **(params or {}))
1285           
1286        def _cursor_execute(self, cursor, statement, parameters, context=None):
1287            return proxy.cursor_execute(super(ProxyConnection, self)._cursor_execute, cursor, statement, parameters, context, False)
1288 
1289        def _cursor_executemany(self, cursor, statement, parameters, context=None):
1290            return proxy.cursor_execute(super(ProxyConnection, self)._cursor_executemany, cursor, statement, parameters, context, True)
1291
1292    return ProxyConnection
1293
1294class RowProxy(object):
1295    """Proxy a single cursor row for a parent ResultProxy.
1296
1297    Mostly follows "ordered dictionary" behavior, mapping result
1298    values to the string-based column name, the integer position of
1299    the result in the row, as well as Column instances which can be
1300    mapped to the original Columns that produced this result set (for
1301    results that correspond to constructed SQL expressions).
1302    """
1303
1304    __slots__ = ['__parent', '__row']
1305   
1306    def __init__(self, parent, row):
1307        """RowProxy objects are constructed by ResultProxy objects."""
1308
1309        self.__parent = parent
1310        self.__row = row
1311        if self.__parent._echo:
1312            self.__parent.context.engine.logger.debug("Row " + repr(row))
1313
1314    def close(self):
1315        """Close the parent ResultProxy."""
1316
1317        self.__parent.close()
1318
1319    def __contains__(self, key):
1320        return self.__parent._has_key(self.__row, key)
1321
1322    def __len__(self):
1323        return len(self.__row)
1324
1325    def __iter__(self):
1326        for i in xrange(len(self.__row)):
1327            yield self.__parent._get_col(self.__row, i)
1328
1329    __hash__ = None
1330   
1331    def __eq__(self, other):
1332        return ((other is self) or
1333                (other == tuple(self.__parent._get_col(self.__row, key)
1334                                for key in xrange(len(self.__row)))))
1335
1336    def __ne__(self, other):
1337        return not self.__eq__(other)
1338
1339    def __repr__(self):
1340        return repr(tuple(self))
1341
1342    def has_key(self, key):
1343        """Return True if this RowProxy contains the given key."""
1344
1345        return self.__parent._has_key(self.__row, key)
1346
1347    def __getitem__(self, key):
1348        return self.__parent._get_col(self.__row, key)
1349
1350    def __getattr__(self, name):
1351        try:
1352            return self.__parent._get_col(self.__row, name)
1353        except KeyError, e:
1354            raise AttributeError(e.args[0])
1355
1356    def items(self):
1357        """Return a list of tuples, each tuple containing a key/value pair."""
1358
1359        return [(key, getattr(self, key)) for key in self.iterkeys()]
1360
1361    def keys(self):
1362        """Return the list of keys as strings represented by this RowProxy."""
1363
1364        return self.__parent.keys
1365   
1366    def iterkeys(self):
1367        return iter(self.__parent.keys)
1368       
1369    def values(self):
1370        """Return the values represented by this RowProxy as a list."""
1371
1372        return list(self)
1373   
1374    def itervalues(self):
1375        return iter(self)
1376
1377class BufferedColumnRow(RowProxy):
1378    def __init__(self, parent, row):
1379        row = [ResultProxy._get_col(parent, row, i) for i in xrange(len(row))]
1380        super(BufferedColumnRow, self).__init__(parent, row)
1381
1382
1383class ResultProxy(object):
1384    """Wraps a DB-API cursor object to provide easier access to row columns.
1385
1386    Individual columns may be accessed by their integer position,
1387    case-insensitive column name, or by ``schema.Column``
1388    object. e.g.::
1389
1390      row = fetchone()
1391
1392      col1 = row[0]    # access via integer position
1393
1394      col2 = row['col2']   # access via name
1395
1396      col3 = row[mytable.c.mycol] # access via Column object.
1397
1398    ResultProxy also contains a map of TypeEngine objects and will
1399    invoke the appropriate ``result_processor()`` method before
1400    returning columns, as well as the ExecutionContext corresponding
1401    to the statement execution.  It provides several methods for which
1402    to obtain information from the underlying ExecutionContext.
1403    """
1404
1405    _process_row = RowProxy
1406
1407    def __init__(self, context):
1408        """ResultProxy objects are constructed via the execute() method on SQLEngine."""
1409        self.context = context
1410        self.dialect = context.dialect
1411        self.closed = False
1412        self.cursor = context.cursor
1413        self.connection = context.root_connection
1414        self._echo = context.engine._should_log_info
1415        self._init_metadata()
1416   
1417    @property
1418    def rowcount(self):
1419        if self._rowcount is None:
1420            return self.context.get_rowcount()
1421        else:
1422            return self._rowcount
1423
1424    @property
1425    def lastrowid(self):
1426        return self.cursor.lastrowid
1427
1428    @property
1429    def out_parameters(self):
1430        return self.context.out_parameters
1431
1432    def _init_metadata(self):
1433        metadata = self.cursor.description
1434        if metadata is None:
1435            # no results, get rowcount (which requires open cursor on some DB's such as firebird),
1436            # then close
1437            self._rowcount = self.context.get_rowcount()
1438            self.close()
1439            return
1440           
1441        self._rowcount = None
1442        self._props = util.populate_column_dict(None)
1443        self._props.creator = self.__key_fallback()
1444        self.keys = []
1445
1446        typemap = self.dialect.dbapi_type_map
1447
1448        for i, item in enumerate(metadata):
1449            colname = item[0]
1450            if self.dialect.description_encoding:
1451                colname = colname.decode(self.dialect.description_encoding)
1452
1453            if '.' in colname:
1454                # sqlite will in some circumstances prepend table name to colnames, so strip
1455                origname = colname
1456                colname = colname.split('.')[-1]
1457            else:
1458                origname = None
1459
1460            if self.context.result_map:
1461                try:
1462                    (name, obj, type_) = self.context.result_map[colname.lower()]
1463                except KeyError:
1464                    (name, obj, type_) = (colname, None, typemap.get(item[1], types.NULLTYPE))
1465            else:
1466                (name, obj, type_) = (colname, None, typemap.get(item[1], types.NULLTYPE))
1467
1468            rec = (type_, type_.dialect_impl(self.dialect).result_processor(self.dialect), i)
1469
1470            if self._props.setdefault(name.lower(), rec) is not rec:
1471                self._props[name.lower()] = (type_, self.__ambiguous_processor(name), 0)
1472
1473            # store the "origname" if we truncated (sqlite only)
1474            if origname:
1475                if self._props.setdefault(origname.lower(), rec) is not rec:
1476                    self._props[origname.lower()] = (type_, self.__ambiguous_processor(origname), 0)
1477
1478            self.keys.append(colname)
1479            self._props[i] = rec
1480            if obj:
1481                for o in obj:
1482                    self._props[o] = rec
1483
1484        if self._echo:
1485            self.context.engine.logger.debug(
1486                "Col " + repr(tuple(x[0] for x in metadata)))
1487   
1488    def __key_fallback(self):
1489        # create a closure without 'self' to avoid circular references
1490        props = self._props
1491       
1492        def fallback(key):
1493            if isinstance(key, basestring):
1494                key = key.lower()
1495                if key in props:
1496                    return props[key]
1497
1498            # fallback for targeting a ColumnElement to a textual expression
1499            # this is a rare use case which only occurs when matching text()
1500            # constructs to ColumnElements
1501            if isinstance(key, expression.ColumnElement):
1502                if key._label and key._label.lower() in props:
1503                    return props[key._label.lower()]
1504                elif hasattr(key, 'name') and key.name.lower() in props:
1505                    return props[key.name.lower()]
1506
1507            raise exc.NoSuchColumnError("Could not locate column in row for column '%s'" % (str(key)))
1508        return fallback
1509
1510    def __ambiguous_processor(self, colname):
1511        def process(value):
1512            raise exc.InvalidRequestError("Ambiguous column name '%s' in result set! "
1513                        "try 'use_labels' option on select statement." % colname)
1514        return process
1515
1516    def close(self):
1517        """Close this ResultProxy.
1518       
1519        Closes the underlying DBAPI cursor corresponding to the execution.
1520
1521        If this ResultProxy was generated from an implicit execution,
1522        the underlying Connection will also be closed (returns the
1523        underlying DBAPI connection to the connection pool.)
1524
1525        This method is called automatically when:
1526       
1527            * all result rows are exhausted using the fetchXXX() methods.
1528            * cursor.description is None.
1529       
1530        """
1531        if not self.closed:
1532            self.closed = True
1533            self.cursor.close()
1534            if self.connection.should_close_with_result:
1535                self.connection.close()
1536
1537    def _has_key(self, row, key):
1538        try:
1539            # _key_cache uses __missing__ in 2.5, so not much alternative
1540            # to catching KeyError
1541            self._props[key]
1542            return True
1543        except KeyError:
1544            return False
1545
1546    def __iter__(self):
1547        while True:
1548            row = self.fetchone()
1549            if row is None:
1550                raise StopIteration
1551            else:
1552                yield row
1553
1554    def last_inserted_ids(self):
1555        """Return ``last_inserted_ids()`` from the underlying ExecutionContext.
1556
1557        See ExecutionContext for details.
1558
1559        """
1560        return self.context.last_inserted_ids()
1561
1562    def last_updated_params(self):
1563        """Return ``last_updated_params()`` from the underlying ExecutionContext.
1564
1565        See ExecutionContext for details.
1566
1567        """
1568        return self.context.last_updated_params()
1569
1570    def last_inserted_params(self):
1571        """Return ``last_inserted_params()`` from the underlying ExecutionContext.
1572
1573        See ExecutionContext for details.
1574
1575        """
1576        return self.context.last_inserted_params()
1577
1578    def lastrow_has_defaults(self):
1579        """Return ``lastrow_has_defaults()`` from the underlying ExecutionContext.
1580
1581        See ExecutionContext for details.
1582       
1583        """
1584        return self.context.lastrow_has_defaults()
1585
1586    def postfetch_cols(self):
1587        """Return ``postfetch_cols()`` from the underlying ExecutionContext.
1588
1589        See ExecutionContext for details.
1590       
1591        """
1592        return self.context.postfetch_cols
1593   
1594    def prefetch_cols(self):
1595        return self.context.prefetch_cols
1596       
1597    def supports_sane_rowcount(self):
1598        """Return ``supports_sane_rowcount`` from the dialect."""
1599       
1600        return self.dialect.supports_sane_rowcount
1601
1602    def supports_sane_multi_rowcount(self):
1603        """Return ``supports_sane_multi_rowcount`` from the dialect."""
1604
1605        return self.dialect.supports_sane_multi_rowcount
1606
1607    def _get_col(self, row, key):
1608        try:
1609            type_, processor, index = self._props[key]
1610        except TypeError:
1611            # the 'slice' use case is very infrequent,
1612            # so we use an exception catch to reduce conditionals in _get_col
1613            if isinstance(key, slice):
1614                indices = key.indices(len(row))
1615                return tuple(self._get_col(row, i) for i in xrange(*indices))
1616            else:
1617                raise
1618
1619        if processor:
1620            return processor(row[index])
1621        else:
1622            return row[index]
1623
1624    def _fetchone_impl(self):
1625        return self.cursor.fetchone()
1626
1627    def _fetchmany_impl(self, size=None):
1628        return self.cursor.fetchmany(size)
1629
1630    def _fetchall_impl(self):
1631        return self.cursor.fetchall()
1632
1633    def fetchall(self):
1634        """Fetch all rows, just like DB-API ``cursor.fetchall()``."""
1635
1636        try:
1637            process_row = self._process_row
1638            l = [process_row(self, row) for row in self._fetchall_impl()]
1639            self.close()
1640            return l
1641        except Exception, e:
1642            self.connection._handle_dbapi_exception(e, None, None, self.cursor, self.context)
1643            raise
1644
1645    def fetchmany(self, size=None):
1646        """Fetch many rows, just like DB-API ``cursor.fetchmany(size=cursor.arraysize)``."""
1647
1648        try:
1649            process_row = self._process_row
1650            l = [process_row(self, row) for row in self._fetchmany_impl(size)]
1651            if len(l) == 0:
1652                self.close()
1653            return l
1654        except Exception, e:
1655            self.connection._handle_dbapi_exception(e, None, None, self.cursor, self.context)
1656            raise
1657
1658    def fetchone(self):
1659        """Fetch one row, just like DB-API ``cursor.fetchone()``."""
1660        try:
1661            row = self._fetchone_impl()
1662            if row is not None:
1663                return self._process_row(self, row)
1664            else:
1665                self.close()
1666                return None
1667        except Exception, e:
1668            self.connection._handle_dbapi_exception(e, None, None, self.cursor, self.context)
1669            raise
1670
1671    def scalar(self):
1672        """Fetch the first column of the first row, and close the result set."""
1673        try:
1674            row = self._fetchone_impl()
1675        except Exception, e:
1676            self.connection._handle_dbapi_exception(e, None, None, self.cursor, self.context)
1677            raise
1678           
1679        try:
1680            if row is not None:
1681                return self._process_row(self, row)[0]
1682            else:
1683                return None
1684        finally:
1685            self.close()
1686
1687class BufferedRowResultProxy(ResultProxy):
1688    """A ResultProxy with row buffering behavior.
1689
1690    ``ResultProxy`` that buffers the contents of a selection of rows
1691    before ``fetchone()`` is called.  This is to allow the results of
1692    ``cursor.description`` to be available immediately, when
1693    interfacing with a DB-API that requires rows to be consumed before
1694    this information is available (currently psycopg2, when used with
1695    server-side cursors).
1696
1697    The pre-fetching behavior fetches only one row initially, and then
1698    grows its buffer size by a fixed amount with each successive need
1699    for additional rows up to a size of 100.
1700   
1701    """
1702
1703    def _init_metadata(self):
1704        self.__buffer_rows()
1705        super(BufferedRowResultProxy, self)._init_metadata()
1706
1707    # this is a "growth chart" for the buffering of rows.
1708    # each successive __buffer_rows call will use the next
1709    # value in the list for the buffer size until the max
1710    # is reached
1711    size_growth = {
1712        1 : 5,
1713        5 : 10,
1714        10 : 20,
1715        20 : 50,
1716        50 : 100
1717    }
1718
1719    def __buffer_rows(self):
1720        size = getattr(self, '_bufsize', 1)
1721        self.__rowbuffer = self.cursor.fetchmany(size)
1722        self._bufsize = self.size_growth.get(size, size)
1723
1724    def _fetchone_impl(self):
1725        if self.closed:
1726            return None
1727        if len(self.__rowbuffer) == 0:
1728            self.__buffer_rows()
1729            if len(self.__rowbuffer) == 0:
1730                return None
1731        return self.__rowbuffer.pop(0)
1732
1733    def _fetchmany_impl(self, size=None):
1734        result = []
1735        for x in range(0, size):
1736            row = self._fetchone_impl()
1737            if row is None:
1738                break
1739            result.append(row)
1740        return result
1741
1742    def _fetchall_impl(self):
1743        return self.__rowbuffer + list(self.cursor.fetchall())
1744
1745class BufferedColumnResultProxy(ResultProxy):
1746    """A ResultProxy with column buffering behavior.
1747
1748    ``ResultProxy`` that loads all columns into memory each time
1749    fetchone() is called.  If fetchmany() or fetchall() are called,
1750    the full grid of results is fetched.  This is to operate with
1751    databases where result rows contain "live" results that fall out
1752    of scope unless explicitly fetched.  Currently this includes just
1753    cx_Oracle LOB objects, but this behavior is known to exist in
1754    other DB-APIs as well (Pygresql, currently unsupported).
1755   
1756    """
1757
1758    _process_row = BufferedColumnRow
1759
1760    def _get_col(self, row, key):
1761        try:
1762            rec = self._props[key]
1763            return row[rec[2]]
1764        except TypeError:
1765            # the 'slice' use case is very infrequent,
1766            # so we use an exception catch to reduce conditionals in _get_col
1767            if isinstance(key, slice):
1768                indices = key.indices(len(row))
1769                return tuple(self._get_col(row, i) for i in xrange(*indices))
1770            else:
1771                raise
1772
1773    def fetchall(self):
1774        l = []
1775        while True:
1776            row = self.fetchone()
1777            if row is None:
1778                break
1779            l.append(row)
1780        return l
1781
1782    def fetchmany(self, size=None):
1783        if size is None:
1784            return self.fetchall()
1785        l = []
1786        for i in xrange(size):
1787            row = self.fetchone()
1788            if row is None:
1789                break
1790            l.append(row)
1791        return l
1792
1793
1794class SchemaIterator(schema.SchemaVisitor):
1795    """A visitor that can gather text into a buffer and execute the contents of the buffer."""
1796
1797    def __init__(self, connection):
1798        """Construct a new SchemaIterator."""
1799       
1800        self.connection = connection
1801        self.buffer = StringIO.StringIO()
1802
1803    def append(self, s):
1804        """Append content to the SchemaIterator's query buffer."""
1805
1806        self.buffer.write(s)
1807
1808    def execute(self):
1809        """Execute the contents of the SchemaIterator's buffer."""
1810
1811        try:
1812            return self.connection.execute(self.buffer.getvalue())
1813        finally:
1814            self.buffer.truncate(0)
1815
1816class DefaultRunner(schema.SchemaVisitor):
1817    """A visitor which accepts ColumnDefault objects, produces the
1818    dialect-specific SQL corresponding to their execution, and
1819    executes the SQL, returning the result value.
1820
1821    DefaultRunners are used internally by Engines and Dialects.
1822    Specific database modules should provide their own subclasses of
1823    DefaultRunner to allow database-specific behavior.
1824
1825    """
1826
1827    def __init__(self, context):
1828        self.context = context
1829        self.dialect = context.dialect
1830        self.cursor = context.cursor
1831
1832    def get_column_default(self, column):
1833        if column.default is not None:
1834            return self.traverse_single(column.default)
1835        else:
1836            return None
1837
1838    def get_column_onupdate(self, column):
1839        if column.onupdate is not None:
1840            return self.traverse_single(column.onupdate)
1841        else:
1842            return None
1843
1844    def visit_passive_default(self, default):
1845        return None
1846
1847    def visit_sequence(self, seq):
1848        return None
1849
1850    def exec_default_sql(self, default):
1851        conn = self.context.connection
1852        c = expression.select([default.arg]).compile(bind=conn)
1853        return conn._execute_compiled(c, (), {}).scalar()
1854
1855    def execute_string(self, stmt, params=None):
1856        """execute a string statement, using the raw cursor, and return a scalar result."""
1857       
1858        conn = self.context._connection
1859        if isinstance(stmt, unicode) and not self.dialect.supports_unicode_statements:
1860            stmt = stmt.encode(self.dialect.encoding)
1861        conn._cursor_execute(self.cursor, stmt, params)
1862        return self.cursor.fetchone()[0]
1863
1864    def visit_column_onupdate(self, onupdate):
1865        if isinstance(onupdate.arg, expression.ClauseElement):
1866            return self.exec_default_sql(onupdate)
1867        elif util.callable(onupdate.arg):
1868            return onupdate.arg(self.context)
1869        else:
1870            return onupdate.arg
1871
1872    def visit_column_default(self, default):
1873        if isinstance(default.arg, expression.ClauseElement):
1874            return self.exec_default_sql(default)
1875        elif util.callable(default.arg):
1876            return default.arg(self.context)
1877        else:
1878            return default.arg
1879
1880
1881def connection_memoize(key):
1882    """Decorator, memoize a function in a connection.info stash.
1883
1884    Only applicable to functions which take no arguments other than a
1885    connection.  The memo will be stored in ``connection.info[key]``.
1886
1887    """
1888    @util.decorator
1889    def decorated(fn, self, connection):
1890        connection = connection.connect()
1891        try:
1892            return connection.info[key]
1893        except KeyError:
1894            connection.info[key] = val = fn(self, connection)
1895            return val
1896
1897    return decorated
Note: リポジトリブラウザについてのヘルプは TracBrowser を参照してください。