diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2008-12-06 18:27:04 +0000 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2008-12-06 18:27:04 +0000 |
| commit | 994ab27aa38dfd3dc627083338509519247b7e20 (patch) | |
| tree | a40d7755146c9f102fa05143ed7793c862aed028 /lib/sqlalchemy | |
| parent | de4ed96ec01d5c5da064001691357f987a6e8892 (diff) | |
| download | sqlalchemy-994ab27aa38dfd3dc627083338509519247b7e20.tar.gz | |
- postgres docstring
- insert/update/delete are documented generatively
- values({}) is no longer deprecated, thus enabling
unicode/Columns as keys
Diffstat (limited to 'lib/sqlalchemy')
| -rw-r--r-- | lib/sqlalchemy/databases/oracle.py | 43 | ||||
| -rw-r--r-- | lib/sqlalchemy/databases/postgres.py | 82 | ||||
| -rw-r--r-- | lib/sqlalchemy/sql/expression.py | 73 |
3 files changed, 148 insertions, 50 deletions
diff --git a/lib/sqlalchemy/databases/oracle.py b/lib/sqlalchemy/databases/oracle.py index d71b129d1..72a0bb265 100644 --- a/lib/sqlalchemy/databases/oracle.py +++ b/lib/sqlalchemy/databases/oracle.py @@ -8,39 +8,44 @@ Oracle version 8 through current (11g at the time of this writing) are supported. Driver +------ The Oracle dialect uses the cx_oracle driver, available at -http://python.net/crew/atuining/cx_Oracle/ . The dialect has several behaviors +http://cx-oracle.sourceforge.net/ . The dialect has several behaviors which are specifically tailored towards compatibility with this module. Connecting +---------- Connecting with create_engine() uses the standard URL approach of -oracle://user:pass@host:port/dbname[?key=value&key=value...]. If dbname is present, the +``oracle://user:pass@host:port/dbname[?key=value&key=value...]``. If dbname is present, the host, port, and dbname tokens are converted to a TNS name using the cx_oracle -makedsn() function. Otherwise, the host token is taken directly as a TNS name. +:func:`makedsn()` function. Otherwise, the host token is taken directly as a TNS name. Additional arguments which may be specified either as query string arguments on the -URL, or as keyword arguments to create_engine() include: +URL, or as keyword arguments to :func:`~sqlalchemy.create_engine()` are: - mode - This is given the string value of SYSDBA or SYSOPER, or alternatively an - integer value. This value is only available as a URL query string argument. +* *allow_twophase* - enable two-phase transactions. Defaults to ``True``. - allow_twophase - enable two-phase transactions. This feature is not yet supported. +* *auto_convert_lobs* - defaults to True, see the section on LOB objects. - threaded - defaults to True with SQLAlchemy, enable multithreaded access to - cx_oracle connections. +* *auto_setinputsizes* - the cx_oracle.setinputsizes() call is issued for all bind parameters. + This is required for LOB datatypes but can be disabled to reduce overhead. Defaults + to ``True``. - use_ansi - defaults to True, use ANSI JOIN constructs (see the section on Oracle 8). +* *mode* - This is given the string value of SYSDBA or SYSOPER, or alternatively an + integer value. This value is only available as a URL query string argument. - auto_convert_lobs - defaults to True, see the section on LOB objects. +* *threaded* - enable multithreaded access to cx_oracle connections. Defaults + to ``True``. Note that this is the opposite default of cx_oracle itself. - auto_setinputsizes - the cx_oracle.setinputsizes() call is issued for all bind parameters. - This is required for LOB datatypes but can be disabled to reduce overhead. +* *use_ansi* - Use ANSI JOIN constructs (see the section on Oracle 8). Defaults + to ``True``. If ``False``, Oracle-8 compatible constructs are used for joins. - optimize_limits - defaults to False, see the section on LIMIT/OFFSET. +* *optimize_limits* - defaults to ``False``. see the section on LIMIT/OFFSET. Auto Increment Behavior +----------------------- SQLAlchemy Table objects which include integer primary keys are usually assumed to have "autoincrementing" behavior, meaning they can generate their own primary key values upon @@ -63,6 +68,7 @@ This step is also required when using table reflection, i.e. autoload=True:: ) LOB Objects +----------- cx_oracle presents some challenges when fetching LOB objects. A LOB object in a result set is presented by cx_oracle as a cx_oracle.LOB object which has a read() method. By default, @@ -84,6 +90,7 @@ without raising cursor errors. The conversion of LOB in all cases, as well as t of LOB objects, can be disabled using auto_convert_lobs=False. LIMIT/OFFSET Support +-------------------- Oracle has no support for the LIMIT or OFFSET keywords. Whereas previous versions of SQLAlchemy used the "ROW NUMBER OVER..." construct to simulate LIMIT/OFFSET, SQLAlchemy 0.5 now uses @@ -94,18 +101,20 @@ this was stepping into the bounds of optimization that is better left on the DBA prefix can be added by enabling the optimize_limits=True flag on create_engine(). Two Phase Transaction Support +----------------------------- -Two Phase transactions are partially implemented using XA transactions but at the time of this -writing have not been successfully tested. The author of cx_oracle also stated that he's never -seen them work so this may be a cx_oracle issue. +Two Phase transactions are implemented using XA transactions. Success has been reported of them +working successfully but this should be regarded as an experimental feature. Oracle 8 Compatibility +---------------------- When using Oracle 8, a "use_ansi=False" flag is available which converts all JOIN phrases into the WHERE clause, and in the case of LEFT OUTER JOIN makes use of Oracle's (+) operator. Synonym/DBLINK Reflection +------------------------- When using reflection with Table objects, the dialect can optionally search for tables indicated by synonyms that reference DBLINK-ed tables by passing the flag diff --git a/lib/sqlalchemy/databases/postgres.py b/lib/sqlalchemy/databases/postgres.py index 57620c007..320c749bc 100644 --- a/lib/sqlalchemy/databases/postgres.py +++ b/lib/sqlalchemy/databases/postgres.py @@ -6,17 +6,87 @@ """Support for the PostgreSQL database. -PostgreSQL supports partial indexes. To create them pass a posgres_where +Driver +------ + +The psycopg2 driver is supported, available at http://pypi.python.org/pypi/psycopg2/ . +The dialect has several behaviors which are specifically tailored towards compatibility +with this module. + +Note that psycopg1 is **not** supported. + +Connecting +---------- + +URLs are of the form `postgres://user@password@host:port/dbname[?key=value&key=value...]`. + +Postgres-specific keyword arguments which are accepted by :func:`~sqlalchemy.create_engine()` are: + +* *server_side_cursors* - Enable the usage of "server side cursors" for SQL statements which support + this feature. What this essentially means from a psycopg2 point of view is that the cursor is + created using a name, e.g. `connection.cursor('some name')`, which has the effect that result rows + are not immediately pre-fetched and buffered after statement execution, but are instead left + on the server and only retrieved as needed. SQLAlchemy's :class:`~sqlalchemy.engine.base.ResultProxy` + uses special row-buffering behavior when this feature is enabled, such that groups of 100 rows + at a time are fetched over the wire to reduce conversational overhead. + +Sequences/SERIAL +---------------- + +Postgres supports sequences, and SQLAlchemy uses these as the default means of creating +new primary key values for integer-based primary key columns. When creating tables, +SQLAlchemy will issue the ``SERIAL`` datatype for integer-based primary key columns, +which generates a sequence corresponding to the column and associated with it based on +a naming convention. + +To specify a specific named sequence to be used for primary key generation, use the +:func:`~sqlalchemy.schema.Sequence` construct:: + + Table('sometable', metadata, + Column('id', Integer, Sequence('some_id_seq'), primary_key=True) + ) + +Currently, when SQLAlchemy issues a single insert statement, to fulfill the contract of +having the "last insert identifier" available, the sequence is executed independently +beforehand and the new value is retrieved, to be used in the subsequent insert. Note +that when an :func:`~sqlalchemy.sql.expression.insert()` construct is executed using +"executemany" semantics, the sequence is not pre-executed and normal PG SERIAL behavior +is used. + +Postgres 8.3 supports an ``INSERT...RETURNING`` syntax which SQLAlchemy supports +as well. A future release of SQLA will use this feature by default in lieu of +sequence pre-execution in order to retrieve new primary key values, when available. + +INSERT/UPDATE...RETURNING +------------------------- + +The dialect supports PG 8.3's ``INSERT..RETURNING`` and ``UPDATE..RETURNING`` syntaxes, +but must be explicitly enabled on a per-statement basis:: + + # INSERT..RETURNING + result = table.insert(postgres_returning=[table.c.col1, table.c.col2]).\\ + values(name='foo') + print result.fetchall() + + # UPDATE..RETURNING + result = table.update(postgres_returning=[table.c.col1, table.c.col2]).\\ + where(table.c.name=='foo').values(name='bar') + print result.fetchall() + +Indexes +------- + +PostgreSQL supports partial indexes. To create them pass a postgres_where option to the Index constructor:: Index('my_index', my_table.c.id, postgres_where=tbl.c.value > 10) -PostgreSQL 8.2+ supports returning a result set from inserts and updates. -To use this pass the column/expression list to the postgres_returning -parameter when creating the queries:: +Transactions +------------ + +The Postgres dialect fully supports SAVEPOINT and two-phase commit operations. + - raises = tbl.update(empl.c.sales > 100, values=dict(salary=empl.c.salary * 1.1), - postgres_returning=[empl.c.id, empl.c.salary]).execute().fetchall() """ import decimal, random, re, string diff --git a/lib/sqlalchemy/sql/expression.py b/lib/sqlalchemy/sql/expression.py index 4a1fab166..8d2e7f811 100644 --- a/lib/sqlalchemy/sql/expression.py +++ b/lib/sqlalchemy/sql/expression.py @@ -268,23 +268,21 @@ def insert(table, values=None, inline=False, **kwargs): Similar functionality is available via the ``insert()`` method on :class:`~sqlalchemy.schema.Table`. - table - The table to be inserted into. + :param table: The table to be inserted into. - values - A dictionary which specifies the column specifications of the + :param values: A dictionary which specifies the column specifications of the ``INSERT``, and is optional. If left as None, the column specifications are determined from the bind parameters used during the compile phase of the ``INSERT`` statement. If the bind parameters also are None during the compile phase, then the column specifications will be generated from the full list of - table columns. + table columns. Note that the :meth:`~Insert.values()` generative method + may also be used for this. - prefixes - A list of modifier keywords to be inserted between INSERT and INTO, - see ``Insert.prefix_with``. + :param prefixes: A list of modifier keywords to be inserted between INSERT and INTO. + Alternatively, the :meth:`~Insert.prefix_with` generative method may be used. - inline + :param inline: if True, SQL defaults will be compiled 'inline' into the statement and not pre-executed. @@ -312,27 +310,26 @@ def update(table, whereclause=None, values=None, inline=False, **kwargs): Similar functionality is available via the ``update()`` method on :class:`~sqlalchemy.schema.Table`. - table - The table to be updated. + :param table: The table to be updated. - whereclause - A ``ClauseElement`` describing the ``WHERE`` condition of the - ``UPDATE`` statement. + :param whereclause: A ``ClauseElement`` describing the ``WHERE`` condition of the + ``UPDATE`` statement. Note that the :meth:`~Update.where()` generative + method may also be used for this. - values + :param values: A dictionary which specifies the ``SET`` conditions of the ``UPDATE``, and is optional. If left as None, the ``SET`` conditions are determined from the bind parameters used during the compile phase of the ``UPDATE`` statement. If the bind parameters also are None during the compile phase, then the ``SET`` conditions will be generated from the full list of table - columns. + columns. Note that the :meth:`~Update.values()` generative method may + also be used for this. - inline + :param inline: if True, SQL defaults will be compiled 'inline' into the statement and not pre-executed. - If both `values` and compile-time bind parameters are present, the compile-time bind parameters override the information specified within `values` on a per-key basis. @@ -357,12 +354,11 @@ def delete(table, whereclause = None, **kwargs): Similar functionality is available via the ``delete()`` method on :class:`~sqlalchemy.schema.Table`. - table - The table to be updated. + :param table: The table to be updated. - whereclause - A ``ClauseElement`` describing the ``WHERE`` condition of the - ``UPDATE`` statement. + :param whereclause: A :class:`ClauseElement` describing the ``WHERE`` condition of the + ``UPDATE`` statement. Note that the :meth:`~Delete.where()` generative method + may be used instead. """ return Delete(table, whereclause, **kwargs) @@ -522,15 +518,15 @@ def exists(*args, **kwargs): Calling styles are of the following forms:: # use on an existing select() - s = select([<columns>]).where(<criterion>) + s = select([table.c.col1]).where(table.c.col2==5) s = exists(s) # construct a select() at once - exists(['*'], **select_arguments).where(<criterion>) + exists(['*'], **select_arguments).where(criterion) # columns argument is optional, generates "EXISTS (SELECT *)" # by default. - exists().where(<criterion>) + exists().where(table.c.col2==5) """ return _Exists(*args, **kwargs) @@ -2841,12 +2837,18 @@ class TableClause(_Immutable, FromClause): return select([func.count(col).label('tbl_row_count')], whereclause, from_obj=[self], **params) def insert(self, values=None, inline=False, **kwargs): + """Genrate an :func:`insert()` construct.""" + return insert(self, values=values, inline=inline, **kwargs) def update(self, whereclause=None, values=None, inline=False, **kwargs): + """Genrate an :func:`update()` construct.""" + return update(self, whereclause=whereclause, values=values, inline=inline, **kwargs) def delete(self, whereclause=None, **kwargs): + """Genrate a :func:`delete()` construct.""" + return delete(self, whereclause, **kwargs) @property @@ -3487,7 +3489,8 @@ class _ValuesBase(_UpdateBase): key=<somevalue> arguments \*args - deprecated. A single dictionary can be sent as the first positional argument. + A single dictionary can be sent as the first positional argument. This allows + non-string based keys, such as Column objects, to be used. """ if args: @@ -3504,6 +3507,11 @@ class _ValuesBase(_UpdateBase): self.parameters.update(kwargs) class Insert(_ValuesBase): + """Represent an INSERT construct. + + The ``Insert`` object is created using the :func:`insert()` function. + + """ def __init__(self, table, values=None, inline=False, bind=None, prefixes=None, **kwargs): _ValuesBase.__init__(self, table, values) self._bind = bind @@ -3537,6 +3545,11 @@ class Insert(_ValuesBase): self._prefixes = self._prefixes + [clause] class Update(_ValuesBase): + """Represent an Update construct. + + The ``Update`` object is created using the :func:`update()` function. + + """ def __init__(self, table, whereclause, values=None, inline=False, bind=None, **kwargs): _ValuesBase.__init__(self, table, values) self._bind = bind @@ -3570,6 +3583,12 @@ class Update(_ValuesBase): class Delete(_UpdateBase): + """Represent a DELETE construct. + + The ``Delete`` object is created using the :func:`delete()` function. + + """ + def __init__(self, table, whereclause, bind=None, **kwargs): self._bind = bind self.table = table |
