Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
base.py5008 linesDownload Raw Back to postgresql
1# dialects/postgresql/base.py
2# Copyright (C) 2005-2024 the SQLAlchemy authors and contributors
3# <see AUTHORS file>
4#
5# This module is part of SQLAlchemy and is released under
6# the MIT License: https://www.opensource.org/licenses/mit-license.php
7# mypy: ignore-errors
8
9r"""
10.. dialect:: postgresql
11    :name: PostgreSQL
12    :full_support: 12, 13, 14, 15
13    :normal_support: 9.6+
14    :best_effort: 9+
15
16.. _postgresql_sequences:
17
18Sequences/SERIAL/IDENTITY
19-------------------------
20
21PostgreSQL supports sequences, and SQLAlchemy uses these as the default means
22of creating new primary key values for integer-based primary key columns. When
23creating tables, SQLAlchemy will issue the ``SERIAL`` datatype for
24integer-based primary key columns, which generates a sequence and server side
25default corresponding to the column.
26
27To specify a specific named sequence to be used for primary key generation,
28use the :func:`~sqlalchemy.schema.Sequence` construct::
29
30    Table(
31        "sometable",
32        metadata,
33        Column(
34            "id", Integer, Sequence("some_id_seq", start=1), primary_key=True
35        )
36    )
37
38When SQLAlchemy issues a single INSERT statement, to fulfill the contract of
39having the "last insert identifier" available, a RETURNING clause is added to
40the INSERT statement which specifies the primary key columns should be
41returned after the statement completes. The RETURNING functionality only takes
42place if PostgreSQL 8.2 or later is in use. As a fallback approach, the
43sequence, whether specified explicitly or implicitly via ``SERIAL``, is
44executed independently beforehand, the returned value to be used in the
45subsequent insert. Note that when an
46:func:`~sqlalchemy.sql.expression.insert()` construct is executed using
47"executemany" semantics, the "last inserted identifier" functionality does not
48apply; no RETURNING clause is emitted nor is the sequence pre-executed in this
49case.
50
51
52PostgreSQL 10 and above IDENTITY columns
53^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
54
55PostgreSQL 10 and above have a new IDENTITY feature that supersedes the use
56of SERIAL. The :class:`_schema.Identity` construct in a
57:class:`_schema.Column` can be used to control its behavior::
58
59    from sqlalchemy import Table, Column, MetaData, Integer, Computed
60
61    metadata = MetaData()
62
63    data = Table(
64        "data",
65        metadata,
66        Column(
67            'id', Integer, Identity(start=42, cycle=True), primary_key=True
68        ),
69        Column('data', String)
70    )
71
72The CREATE TABLE for the above :class:`_schema.Table` object would be:
73
74.. sourcecode:: sql
75
76    CREATE TABLE data (
77        id INTEGER GENERATED BY DEFAULT AS IDENTITY (START WITH 42 CYCLE),
78        data VARCHAR,
79        PRIMARY KEY (id)
80    )
81
82.. versionchanged::  1.4   Added :class:`_schema.Identity` construct
83   in a :class:`_schema.Column` to specify the option of an autoincrementing
84   column.
85
86.. note::
87
88   Previous versions of SQLAlchemy did not have built-in support for rendering
89   of IDENTITY, and could use the following compilation hook to replace
90   occurrences of SERIAL with IDENTITY::
91
92       from sqlalchemy.schema import CreateColumn
93       from sqlalchemy.ext.compiler import compiles
94
95
96       @compiles(CreateColumn, 'postgresql')
97       def use_identity(element, compiler, **kw):
98           text = compiler.visit_create_column(element, **kw)
99           text = text.replace(
100               "SERIAL", "INT GENERATED BY DEFAULT AS IDENTITY"
101            )
102           return text
103
104   Using the above, a table such as::
105
106       t = Table(
107           't', m,
108           Column('id', Integer, primary_key=True),
109           Column('data', String)
110       )
111
112   Will generate on the backing database as::
113
114       CREATE TABLE t (
115           id INT GENERATED BY DEFAULT AS IDENTITY,
116           data VARCHAR,
117           PRIMARY KEY (id)
118       )
119
120.. _postgresql_ss_cursors:
121
122Server Side Cursors
123-------------------
124
125Server-side cursor support is available for the psycopg2, asyncpg
126dialects and may also be available in others.
127
128Server side cursors are enabled on a per-statement basis by using the
129:paramref:`.Connection.execution_options.stream_results` connection execution
130option::
131
132    with engine.connect() as conn:
133        result = conn.execution_options(stream_results=True).execute(text("select * from table"))
134
135Note that some kinds of SQL statements may not be supported with
136server side cursors; generally, only SQL statements that return rows should be
137used with this option.
138
139.. deprecated:: 1.4  The dialect-level server_side_cursors flag is deprecated
140   and will be removed in a future release.  Please use the
141   :paramref:`_engine.Connection.stream_results` execution option for
142   unbuffered cursor support.
143
144.. seealso::
145
146    :ref:`engine_stream_results`
147
148.. _postgresql_isolation_level:
149
150Transaction Isolation Level
151---------------------------
152
153Most SQLAlchemy dialects support setting of transaction isolation level
154using the :paramref:`_sa.create_engine.isolation_level` parameter
155at the :func:`_sa.create_engine` level, and at the :class:`_engine.Connection`
156level via the :paramref:`.Connection.execution_options.isolation_level`
157parameter.
158
159For PostgreSQL dialects, this feature works either by making use of the
160DBAPI-specific features, such as psycopg2's isolation level flags which will
161embed the isolation level setting inline with the ``"BEGIN"`` statement, or for
162DBAPIs with no direct support by emitting ``SET SESSION CHARACTERISTICS AS
163TRANSACTION ISOLATION LEVEL <level>`` ahead of the ``"BEGIN"`` statement
164emitted by the DBAPI.   For the special AUTOCOMMIT isolation level,
165DBAPI-specific techniques are used which is typically an ``.autocommit``
166flag on the DBAPI connection object.
167
168To set isolation level using :func:`_sa.create_engine`::
169
170    engine = create_engine(
171        "postgresql+pg8000://scott:tiger@localhost/test",
172        isolation_level = "REPEATABLE READ"
173    )
174
175To set using per-connection execution options::
176
177    with engine.connect() as conn:
178        conn = conn.execution_options(
179            isolation_level="REPEATABLE READ"
180        )
181        with conn.begin():
182            # ... work with transaction
183
184There are also more options for isolation level configurations, such as
185"sub-engine" objects linked to a main :class:`_engine.Engine` which each apply
186different isolation level settings.  See the discussion at
187:ref:`dbapi_autocommit` for background.
188
189Valid values for ``isolation_level`` on most PostgreSQL dialects include:
190
191* ``READ COMMITTED``
192* ``READ UNCOMMITTED``
193* ``REPEATABLE READ``
194* ``SERIALIZABLE``
195* ``AUTOCOMMIT``
196
197.. seealso::
198
199    :ref:`dbapi_autocommit`
200
201    :ref:`postgresql_readonly_deferrable`
202
203    :ref:`psycopg2_isolation_level`
204
205    :ref:`pg8000_isolation_level`
206
207.. _postgresql_readonly_deferrable:
208
209Setting READ ONLY / DEFERRABLE
210------------------------------
211
212Most PostgreSQL dialects support setting the "READ ONLY" and "DEFERRABLE"
213characteristics of the transaction, which is in addition to the isolation level
214setting. These two attributes can be established either in conjunction with or
215independently of the isolation level by passing the ``postgresql_readonly`` and
216``postgresql_deferrable`` flags with
217:meth:`_engine.Connection.execution_options`.  The example below illustrates
218passing the ``"SERIALIZABLE"`` isolation level at the same time as setting
219"READ ONLY" and "DEFERRABLE"::
220
221    with engine.connect() as conn:
222        conn = conn.execution_options(
223            isolation_level="SERIALIZABLE",
224            postgresql_readonly=True,
225            postgresql_deferrable=True
226        )
227        with conn.begin():
228            #  ... work with transaction
229
230Note that some DBAPIs such as asyncpg only support "readonly" with
231SERIALIZABLE isolation.
232
233.. versionadded:: 1.4 added support for the ``postgresql_readonly``
234   and ``postgresql_deferrable`` execution options.
235
236.. _postgresql_reset_on_return:
237
238Temporary Table / Resource Reset for Connection Pooling
239-------------------------------------------------------
240
241The :class:`.QueuePool` connection pool implementation used
242by the SQLAlchemy :class:`.Engine` object includes
243:ref:`reset on return <pool_reset_on_return>` behavior that will invoke
244the DBAPI ``.rollback()`` method when connections are returned to the pool.
245While this rollback will clear out the immediate state used by the previous
246transaction, it does not cover a wider range of session-level state, including
247temporary tables as well as other server state such as prepared statement
248handles and statement caches.   The PostgreSQL database includes a variety
249of commands which may be used to reset this state, including
250``DISCARD``, ``RESET``, ``DEALLOCATE``, and ``UNLISTEN``.
251
252
253To install
254one or more of these commands as the means of performing reset-on-return,
255the :meth:`.PoolEvents.reset` event hook may be used, as demonstrated
256in the example below. The implementation
257will end transactions in progress as well as discard temporary tables
258using the ``CLOSE``, ``RESET`` and ``DISCARD`` commands; see the PostgreSQL
259documentation for background on what each of these statements do.
260
261The :paramref:`_sa.create_engine.pool_reset_on_return` parameter
262is set to ``None`` so that the custom scheme can replace the default behavior
263completely.   The custom hook implementation calls ``.rollback()`` in any case,
264as it's usually important that the DBAPI's own tracking of commit/rollback
265will remain consistent with the state of the transaction::
266
267
268    from sqlalchemy import create_engine
269    from sqlalchemy import event
270
271    postgresql_engine = create_engine(
272        "postgresql+pyscopg2://scott:tiger@hostname/dbname",
273
274        # disable default reset-on-return scheme
275        pool_reset_on_return=None,
276    )
277
278
279    @event.listens_for(postgresql_engine, "reset")
280    def _reset_postgresql(dbapi_connection, connection_record, reset_state):
281        if not reset_state.terminate_only:
282            dbapi_connection.execute("CLOSE ALL")
283            dbapi_connection.execute("RESET ALL")
284            dbapi_connection.execute("DISCARD TEMP")
285
286        # so that the DBAPI itself knows that the connection has been
287        # reset
288        dbapi_connection.rollback()
289
290.. versionchanged:: 2.0.0b3  Added additional state arguments to
291   the :meth:`.PoolEvents.reset` event and additionally ensured the event
292   is invoked for all "reset" occurrences, so that it's appropriate
293   as a place for custom "reset" handlers.   Previous schemes which
294   use the :meth:`.PoolEvents.checkin` handler remain usable as well.
295
296.. seealso::
297
298    :ref:`pool_reset_on_return` - in the :ref:`pooling_toplevel` documentation
299
300.. _postgresql_alternate_search_path:
301
302Setting Alternate Search Paths on Connect
303------------------------------------------
304
305The PostgreSQL ``search_path`` variable refers to the list of schema names
306that will be implicitly referenced when a particular table or other
307object is referenced in a SQL statement.  As detailed in the next section
308:ref:`postgresql_schema_reflection`, SQLAlchemy is generally organized around
309the concept of keeping this variable at its default value of ``public``,
310however, in order to have it set to any arbitrary name or names when connections
311are used automatically, the "SET SESSION search_path" command may be invoked
312for all connections in a pool using the following event handler, as discussed
313at :ref:`schema_set_default_connections`::
314
315    from sqlalchemy import event
316    from sqlalchemy import create_engine
317
318    engine = create_engine("postgresql+psycopg2://scott:tiger@host/dbname")
319
320    @event.listens_for(engine, "connect", insert=True)
321    def set_search_path(dbapi_connection, connection_record):
322        existing_autocommit = dbapi_connection.autocommit
323        dbapi_connection.autocommit = True
324        cursor = dbapi_connection.cursor()
325        cursor.execute("SET SESSION search_path='%s'" % schema_name)
326        cursor.close()
327        dbapi_connection.autocommit = existing_autocommit
328
329The reason the recipe is complicated by use of the ``.autocommit`` DBAPI
330attribute is so that when the ``SET SESSION search_path`` directive is invoked,
331it is invoked outside of the scope of any transaction and therefore will not
332be reverted when the DBAPI connection has a rollback.
333
334.. seealso::
335
336  :ref:`schema_set_default_connections` - in the :ref:`metadata_toplevel` documentation
337
338
339
340
341.. _postgresql_schema_reflection:
342
343Remote-Schema Table Introspection and PostgreSQL search_path
344------------------------------------------------------------
345
346.. admonition:: Section Best Practices Summarized
347
348    keep the ``search_path`` variable set to its default of ``public``, without
349    any other schema names. Ensure the username used to connect **does not**
350    match remote schemas, or ensure the ``"$user"`` token is **removed** from
351    ``search_path``.  For other schema names, name these explicitly
352    within :class:`_schema.Table` definitions. Alternatively, the
353    ``postgresql_ignore_search_path`` option will cause all reflected
354    :class:`_schema.Table` objects to have a :attr:`_schema.Table.schema`
355    attribute set up.
356
357The PostgreSQL dialect can reflect tables from any schema, as outlined in
358:ref:`metadata_reflection_schemas`.
359
360In all cases, the first thing SQLAlchemy does when reflecting tables is
361to **determine the default schema for the current database connection**.
362It does this using the PostgreSQL ``current_schema()``
363function, illustated below using a PostgreSQL client session (i.e. using
364the ``psql`` tool)::
365
366    test=> select current_schema();
367    current_schema
368    ----------------
369    public
370    (1 row)
371
372Above we see that on a plain install of PostgreSQL, the default schema name
373is the name ``public``.
374
375However, if your database username **matches the name of a schema**, PostgreSQL's
376default is to then **use that name as the default schema**.  Below, we log in
377using the username ``scott``.  When we create a schema named ``scott``, **it
378implicitly changes the default schema**::
379
380    test=> select current_schema();
381    current_schema
382    ----------------
383    public
384    (1 row)
385
386    test=> create schema scott;
387    CREATE SCHEMA
388    test=> select current_schema();
389    current_schema
390    ----------------
391    scott
392    (1 row)
393
394The behavior of ``current_schema()`` is derived from the
395`PostgreSQL search path
396<https://www.postgresql.org/docs/current/static/ddl-schemas.html#DDL-SCHEMAS-PATH>`_
397variable ``search_path``, which in modern PostgreSQL versions defaults to this::
398
399    test=> show search_path;
400    search_path
401    -----------------
402    "$user", public
403    (1 row)
404
405Where above, the ``"$user"`` variable will inject the current username as the
406default schema, if one exists.   Otherwise, ``public`` is used.
407
408When a :class:`_schema.Table` object is reflected, if it is present in the
409schema indicated by the ``current_schema()`` function, **the schema name assigned
410to the ".schema" attribute of the Table is the Python "None" value**.  Otherwise, the
411".schema" attribute will be assigned the string name of that schema.
412
413With regards to tables which these :class:`_schema.Table`
414objects refer to via foreign key constraint, a decision must be made as to how
415the ``.schema`` is represented in those remote tables, in the case where that
416remote schema name is also a member of the current ``search_path``.
417
418By default, the PostgreSQL dialect mimics the behavior encouraged by
419PostgreSQL's own ``pg_get_constraintdef()`` builtin procedure.  This function
420returns a sample definition for a particular foreign key constraint,
421omitting the referenced schema name from that definition when the name is
422also in the PostgreSQL schema search path.  The interaction below
423illustrates this behavior::
424
425    test=> CREATE TABLE test_schema.referred(id INTEGER PRIMARY KEY);
426    CREATE TABLE
427    test=> CREATE TABLE referring(
428    test(>         id INTEGER PRIMARY KEY,
429    test(>         referred_id INTEGER REFERENCES test_schema.referred(id));
430    CREATE TABLE
431    test=> SET search_path TO public, test_schema;
432    test=> SELECT pg_catalog.pg_get_constraintdef(r.oid, true) FROM
433    test-> pg_catalog.pg_class c JOIN pg_catalog.pg_namespace n
434    test-> ON n.oid = c.relnamespace
435    test-> JOIN pg_catalog.pg_constraint r  ON c.oid = r.conrelid
436    test-> WHERE c.relname='referring' AND r.contype = 'f'
437    test-> ;
438                   pg_get_constraintdef
439    ---------------------------------------------------
440     FOREIGN KEY (referred_id) REFERENCES referred(id)
441    (1 row)
442
443Above, we created a table ``referred`` as a member of the remote schema
444``test_schema``, however when we added ``test_schema`` to the
445PG ``search_path`` and then asked ``pg_get_constraintdef()`` for the
446``FOREIGN KEY`` syntax, ``test_schema`` was not included in the output of
447the function.
448
449On the other hand, if we set the search path back to the typical default
450of ``public``::
451
452    test=> SET search_path TO public;
453    SET
454
455The same query against ``pg_get_constraintdef()`` now returns the fully
456schema-qualified name for us::
457
458    test=> SELECT pg_catalog.pg_get_constraintdef(r.oid, true) FROM
459    test-> pg_catalog.pg_class c JOIN pg_catalog.pg_namespace n
460    test-> ON n.oid = c.relnamespace
461    test-> JOIN pg_catalog.pg_constraint r  ON c.oid = r.conrelid
462    test-> WHERE c.relname='referring' AND r.contype = 'f';
463                         pg_get_constraintdef
464    ---------------------------------------------------------------
465     FOREIGN KEY (referred_id) REFERENCES test_schema.referred(id)
466    (1 row)
467
468SQLAlchemy will by default use the return value of ``pg_get_constraintdef()``
469in order to determine the remote schema name.  That is, if our ``search_path``
470were set to include ``test_schema``, and we invoked a table
471reflection process as follows::
472
473    >>> from sqlalchemy import Table, MetaData, create_engine, text
474    >>> engine = create_engine("postgresql+psycopg2://scott:tiger@localhost/test")
475    >>> with engine.connect() as conn:
476    ...     conn.execute(text("SET search_path TO test_schema, public"))
477    ...     metadata_obj = MetaData()
478    ...     referring = Table('referring', metadata_obj,
479    ...                       autoload_with=conn)
480    ...
481    <sqlalchemy.engine.result.CursorResult object at 0x101612ed0>
482
483The above process would deliver to the :attr:`_schema.MetaData.tables`
484collection
485``referred`` table named **without** the schema::
486
487    >>> metadata_obj.tables['referred'].schema is None
488    True
489
490To alter the behavior of reflection such that the referred schema is
491maintained regardless of the ``search_path`` setting, use the
492``postgresql_ignore_search_path`` option, which can be specified as a
493dialect-specific argument to both :class:`_schema.Table` as well as
494:meth:`_schema.MetaData.reflect`::
495
496    >>> with engine.connect() as conn:
497    ...     conn.execute(text("SET search_path TO test_schema, public"))
498    ...     metadata_obj = MetaData()
499    ...     referring = Table('referring', metadata_obj,
500    ...                       autoload_with=conn,
501    ...                       postgresql_ignore_search_path=True)
502    ...
503    <sqlalchemy.engine.result.CursorResult object at 0x1016126d0>
504
505We will now have ``test_schema.referred`` stored as schema-qualified::
506
507    >>> metadata_obj.tables['test_schema.referred'].schema
508    'test_schema'
509
510.. sidebar:: Best Practices for PostgreSQL Schema reflection
511
512    The description of PostgreSQL schema reflection behavior is complex, and
513    is the product of many years of dealing with widely varied use cases and
514    user preferences. But in fact, there's no need to understand any of it if
515    you just stick to the simplest use pattern: leave the ``search_path`` set
516    to its default of ``public`` only, never refer to the name ``public`` as
517    an explicit schema name otherwise, and refer to all other schema names
518    explicitly when building up a :class:`_schema.Table` object.  The options
519    described here are only for those users who can't, or prefer not to, stay
520    within these guidelines.
521
522.. seealso::
523
524    :ref:`reflection_schema_qualified_interaction` - discussion of the issue
525    from a backend-agnostic perspective
526
527    `The Schema Search Path
528    <https://www.postgresql.org/docs/current/static/ddl-schemas.html#DDL-SCHEMAS-PATH>`_
529    - on the PostgreSQL website.
530
531INSERT/UPDATE...RETURNING
532-------------------------
533
534The dialect supports PG 8.2's ``INSERT..RETURNING``, ``UPDATE..RETURNING`` and
535``DELETE..RETURNING`` syntaxes.   ``INSERT..RETURNING`` is used by default
536for single-row INSERT statements in order to fetch newly generated
537primary key identifiers.   To specify an explicit ``RETURNING`` clause,
538use the :meth:`._UpdateBase.returning` method on a per-statement basis::
539
540    # INSERT..RETURNING
541    result = table.insert().returning(table.c.col1, table.c.col2).\
542        values(name='foo')
543    print(result.fetchall())
544
545    # UPDATE..RETURNING
546    result = table.update().returning(table.c.col1, table.c.col2).\
547        where(table.c.name=='foo').values(name='bar')
548    print(result.fetchall())
549
550    # DELETE..RETURNING
551    result = table.delete().returning(table.c.col1, table.c.col2).\
552        where(table.c.name=='foo')
553    print(result.fetchall())
554
555.. _postgresql_insert_on_conflict:
556
557INSERT...ON CONFLICT (Upsert)
558------------------------------
559
560Starting with version 9.5, PostgreSQL allows "upserts" (update or insert) of
561rows into a table via the ``ON CONFLICT`` clause of the ``INSERT`` statement. A
562candidate row will only be inserted if that row does not violate any unique
563constraints.  In the case of a unique constraint violation, a secondary action
564can occur which can be either "DO UPDATE", indicating that the data in the
565target row should be updated, or "DO NOTHING", which indicates to silently skip
566this row.
567
568Conflicts are determined using existing unique constraints and indexes.  These
569constraints may be identified either using their name as stated in DDL,
570or they may be inferred by stating the columns and conditions that comprise
571the indexes.
572
573SQLAlchemy provides ``ON CONFLICT`` support via the PostgreSQL-specific
574:func:`_postgresql.insert()` function, which provides
575the generative methods :meth:`_postgresql.Insert.on_conflict_do_update`
576and :meth:`~.postgresql.Insert.on_conflict_do_nothing`:
577
578.. sourcecode:: pycon+sql
579
580    >>> from sqlalchemy.dialects.postgresql import insert
581    >>> insert_stmt = insert(my_table).values(
582    ...     id='some_existing_id',
583    ...     data='inserted value')
584    >>> do_nothing_stmt = insert_stmt.on_conflict_do_nothing(
585    ...     index_elements=['id']
586    ... )
587    >>> print(do_nothing_stmt)
588    {printsql}INSERT INTO my_table (id, data) VALUES (%(id)s, %(data)s)
589    ON CONFLICT (id) DO NOTHING
590    {stop}
591
592    >>> do_update_stmt = insert_stmt.on_conflict_do_update(
593    ...     constraint='pk_my_table',
594    ...     set_=dict(data='updated value')
595    ... )
596    >>> print(do_update_stmt)
597    {printsql}INSERT INTO my_table (id, data) VALUES (%(id)s, %(data)s)
598    ON CONFLICT ON CONSTRAINT pk_my_table DO UPDATE SET data = %(param_1)s
599
600.. seealso::
601
602    `INSERT .. ON CONFLICT
603    <https://www.postgresql.org/docs/current/static/sql-insert.html#SQL-ON-CONFLICT>`_
604    - in the PostgreSQL documentation.
605
606Specifying the Target
607^^^^^^^^^^^^^^^^^^^^^
608
609Both methods supply the "target" of the conflict using either the
610named constraint or by column inference:
611
612* The :paramref:`_postgresql.Insert.on_conflict_do_update.index_elements` argument
613  specifies a sequence containing string column names, :class:`_schema.Column`
614  objects, and/or SQL expression elements, which would identify a unique
615  index:
616
617  .. sourcecode:: pycon+sql
618
619    >>> do_update_stmt = insert_stmt.on_conflict_do_update(
620    ...     index_elements=['id'],
621    ...     set_=dict(data='updated value')
622    ... )
623    >>> print(do_update_stmt)
624    {printsql}INSERT INTO my_table (id, data) VALUES (%(id)s, %(data)s)
625    ON CONFLICT (id) DO UPDATE SET data = %(param_1)s
626    {stop}
627
628    >>> do_update_stmt = insert_stmt.on_conflict_do_update(
629    ...     index_elements=[my_table.c.id],
630    ...     set_=dict(data='updated value')
631    ... )
632    >>> print(do_update_stmt)
633    {printsql}INSERT INTO my_table (id, data) VALUES (%(id)s, %(data)s)
634    ON CONFLICT (id) DO UPDATE SET data = %(param_1)s
635
636* When using :paramref:`_postgresql.Insert.on_conflict_do_update.index_elements` to
637  infer an index, a partial index can be inferred by also specifying the
638  use the :paramref:`_postgresql.Insert.on_conflict_do_update.index_where` parameter:
639
640  .. sourcecode:: pycon+sql
641
642    >>> stmt = insert(my_table).values(user_email='a@b.com', data='inserted data')
643    >>> stmt = stmt.on_conflict_do_update(
644    ...     index_elements=[my_table.c.user_email],
645    ...     index_where=my_table.c.user_email.like('%@gmail.com'),
646    ...     set_=dict(data=stmt.excluded.data)
647    ... )
648    >>> print(stmt)
649    {printsql}INSERT INTO my_table (data, user_email)
650    VALUES (%(data)s, %(user_email)s) ON CONFLICT (user_email)
651    WHERE user_email LIKE %(user_email_1)s DO UPDATE SET data = excluded.data
652
653* The :paramref:`_postgresql.Insert.on_conflict_do_update.constraint` argument is
654  used to specify an index directly rather than inferring it.  This can be
655  the name of a UNIQUE constraint, a PRIMARY KEY constraint, or an INDEX:
656
657  .. sourcecode:: pycon+sql
658
659    >>> do_update_stmt = insert_stmt.on_conflict_do_update(
660    ...     constraint='my_table_idx_1',
661    ...     set_=dict(data='updated value')
662    ... )
663    >>> print(do_update_stmt)
664    {printsql}INSERT INTO my_table (id, data) VALUES (%(id)s, %(data)s)
665    ON CONFLICT ON CONSTRAINT my_table_idx_1 DO UPDATE SET data = %(param_1)s
666    {stop}
667
668    >>> do_update_stmt = insert_stmt.on_conflict_do_update(
669    ...     constraint='my_table_pk',
670    ...     set_=dict(data='updated value')
671    ... )
672    >>> print(do_update_stmt)
673    {printsql}INSERT INTO my_table (id, data) VALUES (%(id)s, %(data)s)
674    ON CONFLICT ON CONSTRAINT my_table_pk DO UPDATE SET data = %(param_1)s
675    {stop}
676
677* The :paramref:`_postgresql.Insert.on_conflict_do_update.constraint` argument may
678  also refer to a SQLAlchemy construct representing a constraint,
679  e.g. :class:`.UniqueConstraint`, :class:`.PrimaryKeyConstraint`,
680  :class:`.Index`, or :class:`.ExcludeConstraint`.   In this use,
681  if the constraint has a name, it is used directly.  Otherwise, if the
682  constraint is unnamed, then inference will be used, where the expressions
683  and optional WHERE clause of the constraint will be spelled out in the
684  construct.  This use is especially convenient
685  to refer to the named or unnamed primary key of a :class:`_schema.Table`
686  using the
687  :attr:`_schema.Table.primary_key` attribute:
688
689  .. sourcecode:: pycon+sql
690
691    >>> do_update_stmt = insert_stmt.on_conflict_do_update(
692    ...     constraint=my_table.primary_key,
693    ...     set_=dict(data='updated value')
694    ... )
695    >>> print(do_update_stmt)
696    {printsql}INSERT INTO my_table (id, data) VALUES (%(id)s, %(data)s)
697    ON CONFLICT (id) DO UPDATE SET data = %(param_1)s
698
699The SET Clause
700^^^^^^^^^^^^^^^
701
702``ON CONFLICT...DO UPDATE`` is used to perform an update of the already
703existing row, using any combination of new values as well as values
704from the proposed insertion.   These values are specified using the
705:paramref:`_postgresql.Insert.on_conflict_do_update.set_` parameter.  This
706parameter accepts a dictionary which consists of direct values
707for UPDATE:
708
709.. sourcecode:: pycon+sql
710
711    >>> stmt = insert(my_table).values(id='some_id', data='inserted value')
712    >>> do_update_stmt = stmt.on_conflict_do_update(
713    ...     index_elements=['id'],
714    ...     set_=dict(data='updated value')
715    ... )
716    >>> print(do_update_stmt)
717    {printsql}INSERT INTO my_table (id, data) VALUES (%(id)s, %(data)s)
718    ON CONFLICT (id) DO UPDATE SET data = %(param_1)s
719
720.. warning::
721
722    The :meth:`_expression.Insert.on_conflict_do_update`
723    method does **not** take into
724    account Python-side default UPDATE values or generation functions, e.g.
725    those specified using :paramref:`_schema.Column.onupdate`.
726    These values will not be exercised for an ON CONFLICT style of UPDATE,
727    unless they are manually specified in the
728    :paramref:`_postgresql.Insert.on_conflict_do_update.set_` dictionary.
729
730Updating using the Excluded INSERT Values
731^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
732
733In order to refer to the proposed insertion row, the special alias
734:attr:`~.postgresql.Insert.excluded` is available as an attribute on
735the :class:`_postgresql.Insert` object; this object is a
736:class:`_expression.ColumnCollection`
737which alias contains all columns of the target
738table:
739
740.. sourcecode:: pycon+sql
741
742    >>> stmt = insert(my_table).values(
743    ...     id='some_id',
744    ...     data='inserted value',
745    ...     author='jlh'
746    ... )
747    >>> do_update_stmt = stmt.on_conflict_do_update(
748    ...     index_elements=['id'],
749    ...     set_=dict(data='updated value', author=stmt.excluded.author)
750    ... )
751    >>> print(do_update_stmt)
752    {printsql}INSERT INTO my_table (id, data, author)
753    VALUES (%(id)s, %(data)s, %(author)s)
754    ON CONFLICT (id) DO UPDATE SET data = %(param_1)s, author = excluded.author
755
756Additional WHERE Criteria
757^^^^^^^^^^^^^^^^^^^^^^^^^
758
759The :meth:`_expression.Insert.on_conflict_do_update` method also accepts
760a WHERE clause using the :paramref:`_postgresql.Insert.on_conflict_do_update.where`
761parameter, which will limit those rows which receive an UPDATE:
762
763.. sourcecode:: pycon+sql
764
765    >>> stmt = insert(my_table).values(
766    ...     id='some_id',
767    ...     data='inserted value',
768    ...     author='jlh'
769    ... )
770    >>> on_update_stmt = stmt.on_conflict_do_update(
771    ...     index_elements=['id'],
772    ...     set_=dict(data='updated value', author=stmt.excluded.author),
773    ...     where=(my_table.c.status == 2)
774    ... )
775    >>> print(on_update_stmt)
776    {printsql}INSERT INTO my_table (id, data, author)
777    VALUES (%(id)s, %(data)s, %(author)s)
778    ON CONFLICT (id) DO UPDATE SET data = %(param_1)s, author = excluded.author
779    WHERE my_table.status = %(status_1)s
780
781Skipping Rows with DO NOTHING
782^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
783
784``ON CONFLICT`` may be used to skip inserting a row entirely
785if any conflict with a unique or exclusion constraint occurs; below
786this is illustrated using the
787:meth:`~.postgresql.Insert.on_conflict_do_nothing` method:
788
789.. sourcecode:: pycon+sql
790
791    >>> stmt = insert(my_table).values(id='some_id', data='inserted value')
792    >>> stmt = stmt.on_conflict_do_nothing(index_elements=['id'])
793    >>> print(stmt)
794    {printsql}INSERT INTO my_table (id, data) VALUES (%(id)s, %(data)s)
795    ON CONFLICT (id) DO NOTHING
796
797If ``DO NOTHING`` is used without specifying any columns or constraint,
798it has the effect of skipping the INSERT for any unique or exclusion
799constraint violation which occurs:
800
801.. sourcecode:: pycon+sql
802
803    >>> stmt = insert(my_table).values(id='some_id', data='inserted value')
804    >>> stmt = stmt.on_conflict_do_nothing()
805    >>> print(stmt)
806    {printsql}INSERT INTO my_table (id, data) VALUES (%(id)s, %(data)s)
807    ON CONFLICT DO NOTHING
808
809.. _postgresql_match:
810
811Full Text Search
812----------------
813
814PostgreSQL's full text search system is available through the use of the
815:data:`.func` namespace, combined with the use of custom operators
816via the :meth:`.Operators.bool_op` method.    For simple cases with some
817degree of cross-backend compatibility, the :meth:`.Operators.match` operator
818may also be used.
819
820.. _postgresql_simple_match:
821
822Simple plain text matching with ``match()``
823^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
824
825The :meth:`.Operators.match` operator provides for cross-compatible simple
826text matching.   For the PostgreSQL backend, it's hardcoded to generate
827an expression using the ``@@`` operator in conjunction with the
828``plainto_tsquery()`` PostgreSQL function.
829
830On the PostgreSQL dialect, an expression like the following::
831
832    select(sometable.c.text.match("search string"))
833
834would emit to the database::
835
836    SELECT text @@ plainto_tsquery('search string') FROM table
837
838Above, passing a plain string to :meth:`.Operators.match` will automatically
839make use of ``plainto_tsquery()`` to specify the type of tsquery.  This
840establishes basic database cross-compatibility for :meth:`.Operators.match`
841with other backends.
842
843.. versionchanged:: 2.0 The default tsquery generation function used by the
844   PostgreSQL dialect with :meth:`.Operators.match` is ``plainto_tsquery()``.
845
846   To render exactly what was rendered in 1.4, use the following form::
847
848        from sqlalchemy import func
849
850        select(
851            sometable.c.text.bool_op("@@")(func.to_tsquery("search string"))
852        )
853
854   Which would emit::
855
856        SELECT text @@ to_tsquery('search string') FROM table
857
858Using PostgreSQL full text functions and operators directly
859^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
860
861Text search operations beyond the simple use of :meth:`.Operators.match`
862may make use of the :data:`.func` namespace to generate PostgreSQL full-text
863functions, in combination with :meth:`.Operators.bool_op` to generate
864any boolean operator.
865
866For example, the query::
867
868    select(
869        func.to_tsquery('cat').bool_op("@>")(func.to_tsquery('cat & rat'))
870    )
871
872would generate:
873
874.. sourcecode:: sql
875
876    SELECT to_tsquery('cat') @> to_tsquery('cat & rat')
877
878
879The :class:`_postgresql.TSVECTOR` type can provide for explicit CAST::
880
881    from sqlalchemy.dialects.postgresql import TSVECTOR
882    from sqlalchemy import select, cast
883    select(cast("some text", TSVECTOR))
884
885produces a statement equivalent to::
886
887    SELECT CAST('some text' AS TSVECTOR) AS anon_1
888
889The ``func`` namespace is augmented by the PostgreSQL dialect to set up
890correct argument and return types for most full text search functions.
891These functions are used automatically by the :attr:`_sql.func` namespace
892assuming the ``sqlalchemy.dialects.postgresql`` package has been imported,
893or :func:`_sa.create_engine` has been invoked using a ``postgresql``
894dialect.  These functions are documented at:
895
896* :class:`_postgresql.to_tsvector`
897* :class:`_postgresql.to_tsquery`
898* :class:`_postgresql.plainto_tsquery`
899* :class:`_postgresql.phraseto_tsquery`
900* :class:`_postgresql.websearch_to_tsquery`
901* :class:`_postgresql.ts_headline`
902
903Specifying the "regconfig" with ``match()`` or custom operators
904^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
905
906PostgreSQL's ``plainto_tsquery()`` function accepts an optional
907"regconfig" argument that is used to instruct PostgreSQL to use a
908particular pre-computed GIN or GiST index in order to perform the search.
909When using :meth:`.Operators.match`, this additional parameter may be
910specified using the ``postgresql_regconfig`` parameter, such as::
911
912    select(mytable.c.id).where(
913        mytable.c.title.match('somestring', postgresql_regconfig='english')
914    )
915
916Which would emit::
917
918    SELECT mytable.id FROM mytable
919    WHERE mytable.title @@ plainto_tsquery('english', 'somestring')
920
921When using other PostgreSQL search functions with :data:`.func`, the
922"regconfig" parameter may be passed directly as the initial argument::
923
924    select(mytable.c.id).where(
925        func.to_tsvector("english", mytable.c.title).bool_op("@@")(
926            func.to_tsquery("english", "somestring")
927        )
928    )
929
930produces a statement equivalent to::
931
932    SELECT mytable.id FROM mytable
933    WHERE to_tsvector('english', mytable.title) @@
934        to_tsquery('english', 'somestring')
935
936It is recommended that you use the ``EXPLAIN ANALYZE...`` tool from
937PostgreSQL to ensure that you are generating queries with SQLAlchemy that
938take full advantage of any indexes you may have created for full text search.
939
940.. seealso::
941
942    `Full Text Search <https://www.postgresql.org/docs/current/textsearch-controls.html>`_ - in the PostgreSQL documentation
943
944
945FROM ONLY ...
946-------------
947
948The dialect supports PostgreSQL's ONLY keyword for targeting only a particular
949table in an inheritance hierarchy. This can be used to produce the
950``SELECT ... FROM ONLY``, ``UPDATE ONLY ...``, and ``DELETE FROM ONLY ...``
951syntaxes. It uses SQLAlchemy's hints mechanism::
952
953    # SELECT ... FROM ONLY ...
954    result = table.select().with_hint(table, 'ONLY', 'postgresql')
955    print(result.fetchall())
956
957    # UPDATE ONLY ...
958    table.update(values=dict(foo='bar')).with_hint('ONLY',
959                                                   dialect_name='postgresql')
960
961    # DELETE FROM ONLY ...
962    table.delete().with_hint('ONLY', dialect_name='postgresql')
963
964
965.. _postgresql_indexes:
966
967PostgreSQL-Specific Index Options
968---------------------------------
969
970Several extensions to the :class:`.Index` construct are available, specific
971to the PostgreSQL dialect.
972
973Covering Indexes
974^^^^^^^^^^^^^^^^
975
976The ``postgresql_include`` option renders INCLUDE(colname) for the given
977string names::
978
979    Index("my_index", table.c.x, postgresql_include=['y'])
980
981would render the index as ``CREATE INDEX my_index ON table (x) INCLUDE (y)``
982
983Note that this feature requires PostgreSQL 11 or later.
984
985.. versionadded:: 1.4
986
987.. _postgresql_partial_indexes:
988
989Partial Indexes
990^^^^^^^^^^^^^^^
991
992Partial indexes add criterion to the index definition so that the index is
993applied to a subset of rows.   These can be specified on :class:`.Index`
994using the ``postgresql_where`` keyword argument::
995
996  Index('my_index', my_table.c.id, postgresql_where=my_table.c.value > 10)
997
998.. _postgresql_operator_classes:
999
1000Operator Classes
1001^^^^^^^^^^^^^^^^
1002
1003PostgreSQL allows the specification of an *operator class* for each column of
1004an index (see
1005https://www.postgresql.org/docs/current/interactive/indexes-opclass.html).
1006The :class:`.Index` construct allows these to be specified via the
1007``postgresql_ops`` keyword argument::
1008
1009    Index(
1010        'my_index', my_table.c.id, my_table.c.data,
1011        postgresql_ops={
1012            'data': 'text_pattern_ops',
1013            'id': 'int4_ops'
1014        })
1015
1016Note that the keys in the ``postgresql_ops`` dictionaries are the
1017"key" name of the :class:`_schema.Column`, i.e. the name used to access it from
1018the ``.c`` collection of :class:`_schema.Table`, which can be configured to be
1019different than the actual name of the column as expressed in the database.
1020
1021If ``postgresql_ops`` is to be used against a complex SQL expression such
1022as a function call, then to apply to the column it must be given a label
1023that is identified in the dictionary by name, e.g.::
1024
1025    Index(
1026        'my_index', my_table.c.id,
1027        func.lower(my_table.c.data).label('data_lower'),
1028        postgresql_ops={
1029            'data_lower': 'text_pattern_ops',
1030            'id': 'int4_ops'
1031        })
1032
1033Operator classes are also supported by the
1034:class:`_postgresql.ExcludeConstraint` construct using the
1035:paramref:`_postgresql.ExcludeConstraint.ops` parameter. See that parameter for
1036details.
1037
1038.. versionadded:: 1.3.21 added support for operator classes with
1039   :class:`_postgresql.ExcludeConstraint`.
1040
1041
1042Index Types
1043^^^^^^^^^^^
1044
1045PostgreSQL provides several index types: B-Tree, Hash, GiST, and GIN, as well
1046as the ability for users to create their own (see
1047https://www.postgresql.org/docs/current/static/indexes-types.html). These can be
1048specified on :class:`.Index` using the ``postgresql_using`` keyword argument::
1049
1050    Index('my_index', my_table.c.data, postgresql_using='gin')
1051
1052The value passed to the keyword argument will be simply passed through to the
1053underlying CREATE INDEX command, so it *must* be a valid index type for your
1054version of PostgreSQL.
1055
1056.. _postgresql_index_storage:
1057
1058Index Storage Parameters
1059^^^^^^^^^^^^^^^^^^^^^^^^
1060
1061PostgreSQL allows storage parameters to be set on indexes. The storage
1062parameters available depend on the index method used by the index. Storage
1063parameters can be specified on :class:`.Index` using the ``postgresql_with``
1064keyword argument::
1065
1066    Index('my_index', my_table.c.data, postgresql_with={"fillfactor": 50})
1067
1068PostgreSQL allows to define the tablespace in which to create the index.
1069The tablespace can be specified on :class:`.Index` using the
1070``postgresql_tablespace`` keyword argument::
1071
1072    Index('my_index', my_table.c.data, postgresql_tablespace='my_tablespace')
1073
1074Note that the same option is available on :class:`_schema.Table` as well.
1075
1076.. _postgresql_index_concurrently:
1077
1078Indexes with CONCURRENTLY
1079^^^^^^^^^^^^^^^^^^^^^^^^^
1080
1081The PostgreSQL index option CONCURRENTLY is supported by passing the
1082flag ``postgresql_concurrently`` to the :class:`.Index` construct::
1083
1084    tbl = Table('testtbl', m, Column('data', Integer))
1085
1086    idx1 = Index('test_idx1', tbl.c.data, postgresql_concurrently=True)
1087
1088The above index construct will render DDL for CREATE INDEX, assuming
1089PostgreSQL 8.2 or higher is detected or for a connection-less dialect, as::
1090
1091    CREATE INDEX CONCURRENTLY test_idx1 ON testtbl (data)
1092
1093For DROP INDEX, assuming PostgreSQL 9.2 or higher is detected or for
1094a connection-less dialect, it will emit::
1095
1096    DROP INDEX CONCURRENTLY test_idx1
1097
1098When using CONCURRENTLY, the PostgreSQL database requires that the statement
1099be invoked outside of a transaction block.   The Python DBAPI enforces that
1100even for a single statement, a transaction is present, so to use this
1101construct, the DBAPI's "autocommit" mode must be used::
1102
1103    metadata = MetaData()
1104    table = Table(
1105        "foo", metadata,
1106        Column("id", String))
1107    index = Index(
1108        "foo_idx", table.c.id, postgresql_concurrently=True)
1109
1110    with engine.connect() as conn:
1111        with conn.execution_options(isolation_level='AUTOCOMMIT'):
1112            table.create(conn)
1113
1114.. seealso::
1115
1116    :ref:`postgresql_isolation_level`
1117
1118.. _postgresql_index_reflection:
1119
1120PostgreSQL Index Reflection
1121---------------------------
1122
1123The PostgreSQL database creates a UNIQUE INDEX implicitly whenever the
1124UNIQUE CONSTRAINT construct is used.   When inspecting a table using
1125:class:`_reflection.Inspector`, the :meth:`_reflection.Inspector.get_indexes`
1126and the :meth:`_reflection.Inspector.get_unique_constraints`
1127will report on these
1128two constructs distinctly; in the case of the index, the key
1129``duplicates_constraint`` will be present in the index entry if it is
1130detected as mirroring a constraint.   When performing reflection using
1131``Table(..., autoload_with=engine)``, the UNIQUE INDEX is **not** returned
1132in :attr:`_schema.Table.indexes` when it is detected as mirroring a
1133:class:`.UniqueConstraint` in the :attr:`_schema.Table.constraints` collection
1134.
1135
1136Special Reflection Options
1137--------------------------
1138
1139The :class:`_reflection.Inspector`
1140used for the PostgreSQL backend is an instance
1141of :class:`.PGInspector`, which offers additional methods::
1142
1143    from sqlalchemy import create_engine, inspect
1144
1145    engine = create_engine("postgresql+psycopg2://localhost/test")
1146    insp = inspect(engine)  # will be a PGInspector
1147
1148    print(insp.get_enums())
1149
1150.. autoclass:: PGInspector
1151    :members:
1152
1153.. _postgresql_table_options:
1154
1155PostgreSQL Table Options
1156------------------------
1157
1158Several options for CREATE TABLE are supported directly by the PostgreSQL
1159dialect in conjunction with the :class:`_schema.Table` construct:
1160
1161* ``INHERITS``::
1162
1163    Table("some_table", metadata, ..., postgresql_inherits="some_supertable")
1164
1165    Table("some_table", metadata, ..., postgresql_inherits=("t1", "t2", ...))
1166
1167* ``ON COMMIT``::
1168
1169    Table("some_table", metadata, ..., postgresql_on_commit='PRESERVE ROWS')
1170
1171* ``PARTITION BY``::
1172
1173    Table("some_table", metadata, ...,
1174          postgresql_partition_by='LIST (part_column)')
1175
1176    .. versionadded:: 1.2.6
1177
1178* ``TABLESPACE``::
1179
1180    Table("some_table", metadata, ..., postgresql_tablespace='some_tablespace')
1181
1182  The above option is also available on the :class:`.Index` construct.
1183
1184* ``USING``::
1185
1186    Table("some_table", metadata, ..., postgresql_using='heap')
1187
1188    .. versionadded:: 2.0.26
1189
1190* ``WITH OIDS``::
1191
1192    Table("some_table", metadata, ..., postgresql_with_oids=True)
1193
1194* ``WITHOUT OIDS``::
1195
1196    Table("some_table", metadata, ..., postgresql_with_oids=False)
1197
1198.. seealso::
1199
1200    `PostgreSQL CREATE TABLE options

Showing the first 1,200 of 5008 lines. Download the file for the rest.

codekingpro/portable-devtools · Team Ai