From d2a99b2043e976fd673f7ce4119bfe776a4310a9 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Mon, 12 Nov 2012 16:07:04 -0500 Subject: [PATCH] add docs regarding fetchedvalue with primary keys, [ticket:2598] --- doc/build/core/schema.rst | 34 +++++++++++++++++++++++++++++++++- lib/sqlalchemy/schema.py | 4 ++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/doc/build/core/schema.rst b/doc/build/core/schema.rst index 4daf0a9626..310da23a6b 100644 --- a/doc/build/core/schema.rst +++ b/doc/build/core/schema.rst @@ -698,11 +698,13 @@ have a way to "postfetch" the ID, and the statement is not "inlined", the SQL expression is pre-executed; otherwise, SQLAlchemy lets the default fire off on the database side normally. +.. _triggered_columns: + Triggered Columns ------------------ Columns with values set by a database trigger or other external process may be -called out with a marker:: +called out using :class:`.FetchedValue` as a marker:: t = Table('test', meta, Column('abc', String(20), server_default=FetchedValue()), @@ -714,6 +716,36 @@ however they do set the same internal flags as a static ``server_default`` clause, providing hints to higher-level tools that a "post-fetch" of these rows should be performed after an insert or update. +.. note:: + + It's generally not appropriate to use :class:`.FetchedValue` in + conjunction with a primary key column, particularly when using the + ORM or any other scenario where the :attr:`.ResultProxy.inserted_primary_key` + attribute is required. This is becaue the "post-fetch" operation requires + that the primary key value already be available, so that the + row can be selected on its primary key. + + For a server-generated primary key value, all databases provide special + accessors or other techniques in order to acquire the "last inserted + primary key" column of a table. These mechanisms aren't affected by the presence + of :class:`.FetchedValue`. For special situations where triggers are + used to generate primary key values, and the database in use does not + support the ``RETURNING`` clause, it may be necessary to forego the usage + of the trigger and instead apply the SQL expression or function as a + "pre execute" expression:: + + t = Table('test', meta, + Column('abc', MyType, default=func.generate_new_value(), primary_key=True) + ) + + Where above, when :meth:`.Table.insert` is used, + the ``func.generate_new_value()`` expression will be pre-executed + in the context of a scalar ``SELECT`` statement, and the new value will + be applied to the subsequent ``INSERT``, while at the same time being + made available to the :attr:`.ResultProxy.inserted_primary_key` + attribute. + + Defining Sequences ------------------- diff --git a/lib/sqlalchemy/schema.py b/lib/sqlalchemy/schema.py index 6380cd86be..0b1fac1e78 100644 --- a/lib/sqlalchemy/schema.py +++ b/lib/sqlalchemy/schema.py @@ -1821,6 +1821,10 @@ class FetchedValue(_NotAColumnExpr, events.SchemaEventTarget): will create a new value for the ``foo`` column during an INSERT. + .. seealso:: + + :ref:`triggered_columns` + """ is_server_default = True reflected = False -- 2.47.3