1# sql/crud.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: allow-untyped-defs, allow-untyped-calls
8
9"""Functions used by compiler.py to determine the parameters rendered
10within INSERT and UPDATE statements.
11
12"""
13from __future__ import annotations
14
15import functools
16import operator
17from typing import Any
18from typing import Callable
19from typing import cast
20from typing import Dict
21from typing import Iterable
22from typing import List
23from typing import MutableMapping
24from typing import NamedTuple
25from typing import Optional
26from typing import overload
27from typing import Sequence
28from typing import Set
29from typing import Tuple
30from typing import TYPE_CHECKING
31from typing import Union
32
33from . import coercions
34from . import dml
35from . import elements
36from . import roles
37from .base import _DefaultDescriptionTuple
38from .dml import isinsert as _compile_state_isinsert
39from .elements import ColumnClause
40from .schema import default_is_clause_element
41from .schema import default_is_sequence
42from .selectable import Select
43from .selectable import TableClause
44from .. import exc
45from .. import util
46from ..util.typing import Literal
47
48if TYPE_CHECKING:
49 from .compiler import _BindNameForColProtocol
50 from .compiler import SQLCompiler
51 from .dml import _DMLColumnElement
52 from .dml import DMLState
53 from .dml import ValuesBase
54 from .elements import ColumnElement
55 from .elements import KeyedColumnElement
56 from .schema import _SQLExprDefault
57 from .schema import Column
58
59REQUIRED = util.symbol(
60 "REQUIRED",
61 """
62Placeholder for the value within a :class:`.BindParameter`
63which is required to be present when the statement is passed
64to :meth:`_engine.Connection.execute`.
65
66This symbol is typically used when a :func:`_expression.insert`
67or :func:`_expression.update` statement is compiled without parameter
68values present.
69
70""",
71)
72
73
74def _as_dml_column(c: ColumnElement[Any]) -> ColumnClause[Any]:
75 if not isinstance(c, ColumnClause):
76 raise exc.CompileError(
77 f"Can't create DML statement against column expression {c!r}"
78 )
79 return c
80
81
82_CrudParamElement = Tuple[
83 "ColumnElement[Any]",
84 str, # column name
85 Optional[
86 Union[str, "_SQLExprDefault"]
87 ], # bound parameter string or SQL expression to apply
88 Iterable[str],
89]
90_CrudParamElementStr = Tuple[
91 "KeyedColumnElement[Any]",
92 str, # column name
93 str, # bound parameter string
94 Iterable[str],
95]
96_CrudParamElementSQLExpr = Tuple[
97 "ColumnClause[Any]",
98 str,
99 "_SQLExprDefault", # SQL expression to apply
100 Iterable[str],
101]
102
103_CrudParamSequence = List[_CrudParamElement]
104
105
106class _CrudParams(NamedTuple):
107 single_params: _CrudParamSequence
108 all_multi_params: List[Sequence[_CrudParamElementStr]]
109 is_default_metavalue_only: bool = False
110 use_insertmanyvalues: bool = False
111 use_sentinel_columns: Optional[Sequence[Column[Any]]] = None
112
113
114def _get_crud_params(
115 compiler: SQLCompiler,
116 stmt: ValuesBase,
117 compile_state: DMLState,
118 toplevel: bool,
119 **kw: Any,
120) -> _CrudParams:
121 """create a set of tuples representing column/string pairs for use
122 in an INSERT or UPDATE statement.
123
124 Also generates the Compiled object's postfetch, prefetch, and
125 returning column collections, used for default handling and ultimately
126 populating the CursorResult's prefetch_cols() and postfetch_cols()
127 collections.
128
129 """
130
131 # note: the _get_crud_params() system was written with the notion in mind
132 # that INSERT, UPDATE, DELETE are always the top level statement and
133 # that there is only one of them. With the addition of CTEs that can
134 # make use of DML, this assumption is no longer accurate; the DML
135 # statement is not necessarily the top-level "row returning" thing
136 # and it is also theoretically possible (fortunately nobody has asked yet)
137 # to have a single statement with multiple DMLs inside of it via CTEs.
138
139 # the current _get_crud_params() design doesn't accommodate these cases
140 # right now. It "just works" for a CTE that has a single DML inside of
141 # it, and for a CTE with multiple DML, it's not clear what would happen.
142
143 # overall, the "compiler.XYZ" collections here would need to be in a
144 # per-DML structure of some kind, and DefaultDialect would need to
145 # navigate these collections on a per-statement basis, with additional
146 # emphasis on the "toplevel returning data" statement. However we
147 # still need to run through _get_crud_params() for all DML as we have
148 # Python / SQL generated column defaults that need to be rendered.
149
150 # if there is user need for this kind of thing, it's likely a post 2.0
151 # kind of change as it would require deep changes to DefaultDialect
152 # as well as here.
153
154 compiler.postfetch = []
155 compiler.insert_prefetch = []
156 compiler.update_prefetch = []
157 compiler.implicit_returning = []
158
159 visiting_cte = kw.get("visiting_cte", None)
160 if visiting_cte is not None:
161 # for insert -> CTE -> insert, don't populate an incoming
162 # _crud_accumulate_bind_names collection; the INSERT we process here
163 # will not be inline within the VALUES of the enclosing INSERT as the
164 # CTE is placed on the outside. See issue #9173
165 kw.pop("accumulate_bind_names", None)
166 assert (
167 "accumulate_bind_names" not in kw
168 ), "Don't know how to handle insert within insert without a CTE"
169
170 # getters - these are normally just column.key,
171 # but in the case of mysql multi-table update, the rules for
172 # .key must conditionally take tablename into account
173 (
174 _column_as_key,
175 _getattr_col_key,
176 _col_bind_name,
177 ) = _key_getters_for_crud_column(compiler, stmt, compile_state)
178
179 compiler._get_bind_name_for_col = _col_bind_name
180
181 if stmt._returning and stmt._return_defaults:
182 raise exc.CompileError(
183 "Can't compile statement that includes returning() and "
184 "return_defaults() simultaneously"
185 )
186
187 if compile_state.isdelete:
188 _setup_delete_return_defaults(
189 compiler,
190 stmt,
191 compile_state,
192 (),
193 _getattr_col_key,
194 _column_as_key,
195 _col_bind_name,
196 (),
197 (),
198 toplevel,
199 kw,
200 )
201 return _CrudParams([], [])
202
203 # no parameters in the statement, no parameters in the
204 # compiled params - return binds for all columns
205 if compiler.column_keys is None and compile_state._no_parameters:
206 return _CrudParams(
207 [
208 (
209 c,
210 compiler.preparer.format_column(c),
211 _create_bind_param(compiler, c, None, required=True),
212 (c.key,),
213 )
214 for c in stmt.table.columns
215 if not c._omit_from_statements
216 ],
217 [],
218 )
219
220 stmt_parameter_tuples: Optional[
221 List[Tuple[Union[str, ColumnClause[Any]], Any]]
222 ]
223 spd: Optional[MutableMapping[_DMLColumnElement, Any]]
224
225 if (
226 _compile_state_isinsert(compile_state)
227 and compile_state._has_multi_parameters
228 ):
229 mp = compile_state._multi_parameters
230 assert mp is not None
231 spd = mp[0]
232 stmt_parameter_tuples = list(spd.items())
233 spd_str_key = {_column_as_key(key) for key in spd}
234 elif compile_state._ordered_values:
235 spd = compile_state._dict_parameters
236 stmt_parameter_tuples = compile_state._ordered_values
237 assert spd is not None
238 spd_str_key = {_column_as_key(key) for key in spd}
239 elif compile_state._dict_parameters:
240 spd = compile_state._dict_parameters
241 stmt_parameter_tuples = list(spd.items())
242 spd_str_key = {_column_as_key(key) for key in spd}
243 else:
244 stmt_parameter_tuples = spd = spd_str_key = None
245
246 # if we have statement parameters - set defaults in the
247 # compiled params
248 if compiler.column_keys is None:
249 parameters = {}
250 elif stmt_parameter_tuples:
251 assert spd_str_key is not None
252 parameters = {
253 _column_as_key(key): REQUIRED
254 for key in compiler.column_keys
255 if key not in spd_str_key
256 }
257 else:
258 parameters = {
259 _column_as_key(key): REQUIRED for key in compiler.column_keys
260 }
261
262 # create a list of column assignment clauses as tuples
263 values: List[_CrudParamElement] = []
264
265 if stmt_parameter_tuples is not None:
266 _get_stmt_parameter_tuples_params(
267 compiler,
268 compile_state,
269 parameters,
270 stmt_parameter_tuples,
271 _column_as_key,
272 values,
273 kw,
274 )
275
276 check_columns: Dict[str, ColumnClause[Any]] = {}
277
278 # special logic that only occurs for multi-table UPDATE
279 # statements
280 if dml.isupdate(compile_state) and compile_state.is_multitable:
281 _get_update_multitable_params(
282 compiler,
283 stmt,
284 compile_state,
285 stmt_parameter_tuples,
286 check_columns,
287 _col_bind_name,
288 _getattr_col_key,
289 values,
290 kw,
291 )
292
293 if _compile_state_isinsert(compile_state) and stmt._select_names:
294 # is an insert from select, is not a multiparams
295
296 assert not compile_state._has_multi_parameters
297
298 _scan_insert_from_select_cols(
299 compiler,
300 stmt,
301 compile_state,
302 parameters,
303 _getattr_col_key,
304 _column_as_key,
305 _col_bind_name,
306 check_columns,
307 values,
308 toplevel,
309 kw,
310 )
311 use_insertmanyvalues = False
312 use_sentinel_columns = None
313 else:
314 use_insertmanyvalues, use_sentinel_columns = _scan_cols(
315 compiler,
316 stmt,
317 compile_state,
318 parameters,
319 _getattr_col_key,
320 _column_as_key,
321 _col_bind_name,
322 check_columns,
323 values,
324 toplevel,
325 kw,
326 )
327
328 if parameters and stmt_parameter_tuples:
329 check = (
330 set(parameters)
331 .intersection(_column_as_key(k) for k, v in stmt_parameter_tuples)
332 .difference(check_columns)
333 )
334 if check:
335 raise exc.CompileError(
336 "Unconsumed column names: %s"
337 % (", ".join("%s" % (c,) for c in check))
338 )
339
340 is_default_metavalue_only = False
341
342 if (
343 _compile_state_isinsert(compile_state)
344 and compile_state._has_multi_parameters
345 ):
346 # is a multiparams, is not an insert from a select
347 assert not stmt._select_names
348 multi_extended_values = _extend_values_for_multiparams(
349 compiler,
350 stmt,
351 compile_state,
352 cast(
353 "Sequence[_CrudParamElementStr]",
354 values,
355 ),
356 cast("Callable[..., str]", _column_as_key),
357 kw,
358 )
359 return _CrudParams(values, multi_extended_values)
360 elif (
361 not values
362 and compiler.for_executemany
363 and compiler.dialect.supports_default_metavalue
364 ):
365 # convert an "INSERT DEFAULT VALUES"
366 # into INSERT (firstcol) VALUES (DEFAULT) which can be turned
367 # into an in-place multi values. This supports
368 # insert_executemany_returning mode :)
369 values = [
370 (
371 _as_dml_column(stmt.table.columns[0]),
372 compiler.preparer.format_column(stmt.table.columns[0]),
373 compiler.dialect.default_metavalue_token,
374 (),
375 )
376 ]
377 is_default_metavalue_only = True
378
379 return _CrudParams(
380 values,
381 [],
382 is_default_metavalue_only=is_default_metavalue_only,
383 use_insertmanyvalues=use_insertmanyvalues,
384 use_sentinel_columns=use_sentinel_columns,
385 )
386
387
388@overload
389def _create_bind_param(
390 compiler: SQLCompiler,
391 col: ColumnElement[Any],
392 value: Any,
393 process: Literal[True] = ...,
394 required: bool = False,
395 name: Optional[str] = None,
396 **kw: Any,
397) -> str: ...
398
399
400@overload
401def _create_bind_param(
402 compiler: SQLCompiler,
403 col: ColumnElement[Any],
404 value: Any,
405 **kw: Any,
406) -> str: ...
407
408
409def _create_bind_param(
410 compiler: SQLCompiler,
411 col: ColumnElement[Any],
412 value: Any,
413 process: bool = True,
414 required: bool = False,
415 name: Optional[str] = None,
416 **kw: Any,
417) -> Union[str, elements.BindParameter[Any]]:
418 if name is None:
419 name = col.key
420 bindparam = elements.BindParameter(
421 name, value, type_=col.type, required=required
422 )
423 bindparam._is_crud = True
424 if process:
425 return bindparam._compiler_dispatch(compiler, **kw)
426 else:
427 return bindparam
428
429
430def _handle_values_anonymous_param(compiler, col, value, name, **kw):
431 # the insert() and update() constructs as of 1.4 will now produce anonymous
432 # bindparam() objects in the values() collections up front when given plain
433 # literal values. This is so that cache key behaviors, which need to
434 # produce bound parameters in deterministic order without invoking any
435 # compilation here, can be applied to these constructs when they include
436 # values() (but not yet multi-values, which are not included in caching
437 # right now).
438 #
439 # in order to produce the desired "crud" style name for these parameters,
440 # which will also be targetable in engine/default.py through the usual
441 # conventions, apply our desired name to these unique parameters by
442 # populating the compiler truncated names cache with the desired name,
443 # rather than having
444 # compiler.visit_bindparam()->compiler._truncated_identifier make up a
445 # name. Saves on call counts also.
446
447 # for INSERT/UPDATE that's a CTE, we don't need names to match to
448 # external parameters and these would also conflict in the case where
449 # multiple insert/update are combined together using CTEs
450 is_cte = "visiting_cte" in kw
451
452 if (
453 not is_cte
454 and value.unique
455 and isinstance(value.key, elements._truncated_label)
456 ):
457 compiler.truncated_names[("bindparam", value.key)] = name
458
459 if value.type._isnull:
460 # either unique parameter, or other bound parameters that were
461 # passed in directly
462 # set type to that of the column unconditionally
463 value = value._with_binary_element_type(col.type)
464
465 return value._compiler_dispatch(compiler, **kw)
466
467
468def _key_getters_for_crud_column(
469 compiler: SQLCompiler, stmt: ValuesBase, compile_state: DMLState
470) -> Tuple[
471 Callable[[Union[str, ColumnClause[Any]]], Union[str, Tuple[str, str]]],
472 Callable[[ColumnClause[Any]], Union[str, Tuple[str, str]]],
473 _BindNameForColProtocol,
474]:
475 if dml.isupdate(compile_state) and compile_state._extra_froms:
476 # when extra tables are present, refer to the columns
477 # in those extra tables as table-qualified, including in
478 # dictionaries and when rendering bind param names.
479 # the "main" table of the statement remains unqualified,
480 # allowing the most compatibility with a non-multi-table
481 # statement.
482 _et = set(compile_state._extra_froms)
483
484 c_key_role = functools.partial(
485 coercions.expect_as_key, roles.DMLColumnRole
486 )
487
488 def _column_as_key(
489 key: Union[ColumnClause[Any], str]
490 ) -> Union[str, Tuple[str, str]]:
491 str_key = c_key_role(key)
492 if hasattr(key, "table") and key.table in _et:
493 return (key.table.name, str_key) # type: ignore
494 else:
495 return str_key
496
497 def _getattr_col_key(
498 col: ColumnClause[Any],
499 ) -> Union[str, Tuple[str, str]]:
500 if col.table in _et:
501 return (col.table.name, col.key) # type: ignore
502 else:
503 return col.key
504
505 def _col_bind_name(col: ColumnClause[Any]) -> str:
506 if col.table in _et:
507 if TYPE_CHECKING:
508 assert isinstance(col.table, TableClause)
509 return "%s_%s" % (col.table.name, col.key)
510 else:
511 return col.key
512
513 else:
514 _column_as_key = functools.partial(
515 coercions.expect_as_key, roles.DMLColumnRole
516 )
517 _getattr_col_key = _col_bind_name = operator.attrgetter("key") # type: ignore # noqa: E501
518
519 return _column_as_key, _getattr_col_key, _col_bind_name
520
521
522def _scan_insert_from_select_cols(
523 compiler,
524 stmt,
525 compile_state,
526 parameters,
527 _getattr_col_key,
528 _column_as_key,
529 _col_bind_name,
530 check_columns,
531 values,
532 toplevel,
533 kw,
534):
535 cols = [stmt.table.c[_column_as_key(name)] for name in stmt._select_names]
536
537 assert compiler.stack[-1]["selectable"] is stmt
538
539 compiler.stack[-1]["insert_from_select"] = stmt.select
540
541 add_select_cols: List[_CrudParamElementSQLExpr] = []
542 if stmt.include_insert_from_select_defaults:
543 col_set = set(cols)
544 for col in stmt.table.columns:
545 # omit columns that were not in the SELECT statement.
546 # this will omit columns marked as omit_from_statements naturally,
547 # as long as that col was not explicit in the SELECT.
548 # if an omit_from_statements col has a "default" on it, then
549 # we need to include it, as these defaults should still fire off.
550 # but, if it has that default and it's the "sentinel" default,
551 # we don't do sentinel default operations for insert_from_select
552 # here so we again omit it.
553 if (
554 col not in col_set
555 and col.default
556 and not col.default.is_sentinel
557 ):
558 cols.append(col)
559
560 for c in cols:
561 col_key = _getattr_col_key(c)
562 if col_key in parameters and col_key not in check_columns:
563 parameters.pop(col_key)
564 values.append((c, compiler.preparer.format_column(c), None, ()))
565 else:
566 _append_param_insert_select_hasdefault(
567 compiler, stmt, c, add_select_cols, kw
568 )
569
570 if add_select_cols:
571 values.extend(add_select_cols)
572 ins_from_select = compiler.stack[-1]["insert_from_select"]
573 if not isinstance(ins_from_select, Select):
574 raise exc.CompileError(
575 f"Can't extend statement for INSERT..FROM SELECT to include "
576 f"additional default-holding column(s) "
577 f"""{
578 ', '.join(repr(key) for _, key, _, _ in add_select_cols)
579 }. Convert the selectable to a subquery() first, or pass """
580 "include_defaults=False to Insert.from_select() to skip these "
581 "columns."
582 )
583 ins_from_select = ins_from_select._generate()
584 # copy raw_columns
585 ins_from_select._raw_columns = list(ins_from_select._raw_columns) + [
586 expr for _, _, expr, _ in add_select_cols
587 ]
588 compiler.stack[-1]["insert_from_select"] = ins_from_select
589
590
591def _scan_cols(
592 compiler,
593 stmt,
594 compile_state,
595 parameters,
596 _getattr_col_key,
597 _column_as_key,
598 _col_bind_name,
599 check_columns,
600 values,
601 toplevel,
602 kw,
603):
604 (
605 need_pks,
606 implicit_returning,
607 implicit_return_defaults,
608 postfetch_lastrowid,
609 use_insertmanyvalues,
610 use_sentinel_columns,
611 ) = _get_returning_modifiers(compiler, stmt, compile_state, toplevel)
612
613 assert compile_state.isupdate or compile_state.isinsert
614
615 if compile_state._parameter_ordering:
616 parameter_ordering = [
617 _column_as_key(key) for key in compile_state._parameter_ordering
618 ]
619 ordered_keys = set(parameter_ordering)
620 cols = [
621 stmt.table.c[key]
622 for key in parameter_ordering
623 if isinstance(key, str) and key in stmt.table.c
624 ] + [c for c in stmt.table.c if c.key not in ordered_keys]
625
626 else:
627 cols = stmt.table.columns
628
629 isinsert = _compile_state_isinsert(compile_state)
630 if isinsert and not compile_state._has_multi_parameters:
631 # new rules for #7998. fetch lastrowid or implicit returning
632 # for autoincrement column even if parameter is NULL, for DBs that
633 # override NULL param for primary key (sqlite, mysql/mariadb)
634 autoincrement_col = stmt.table._autoincrement_column
635 insert_null_pk_still_autoincrements = (
636 compiler.dialect.insert_null_pk_still_autoincrements
637 )
638 else:
639 autoincrement_col = insert_null_pk_still_autoincrements = None
640
641 if stmt._supplemental_returning:
642 supplemental_returning = set(stmt._supplemental_returning)
643 else:
644 supplemental_returning = set()
645
646 compiler_implicit_returning = compiler.implicit_returning
647
648 # TODO - see TODO(return_defaults_columns) below
649 # cols_in_params = set()
650
651 for c in cols:
652 # scan through every column in the target table
653
654 col_key = _getattr_col_key(c)
655
656 if col_key in parameters and col_key not in check_columns:
657 # parameter is present for the column. use that.
658
659 _append_param_parameter(
660 compiler,
661 stmt,
662 compile_state,
663 c,
664 col_key,
665 parameters,
666 _col_bind_name,
667 implicit_returning,
668 implicit_return_defaults,
669 postfetch_lastrowid,
670 values,
671 autoincrement_col,
672 insert_null_pk_still_autoincrements,
673 kw,
674 )
675
676 # TODO - see TODO(return_defaults_columns) below
677 # cols_in_params.add(c)
678
679 elif isinsert:
680 # no parameter is present and it's an insert.
681
682 if c.primary_key and need_pks:
683 # it's a primary key column, it will need to be generated by a
684 # default generator of some kind, and the statement expects
685 # inserted_primary_key to be available.
686
687 if implicit_returning:
688 # we can use RETURNING, find out how to invoke this
689 # column and get the value where RETURNING is an option.
690 # we can inline server-side functions in this case.
691
692 _append_param_insert_pk_returning(
693 compiler, stmt, c, values, kw
694 )
695 else:
696 # otherwise, find out how to invoke this column
697 # and get its value where RETURNING is not an option.
698 # if we have to invoke a server-side function, we need
699 # to pre-execute it. or if this is a straight
700 # autoincrement column and the dialect supports it
701 # we can use cursor.lastrowid.
702
703 _append_param_insert_pk_no_returning(
704 compiler, stmt, c, values, kw
705 )
706
707 elif c.default is not None:
708 # column has a default, but it's not a pk column, or it is but
709 # we don't need to get the pk back.
710 if not c.default.is_sentinel or (
711 use_sentinel_columns is not None
712 ):
713 _append_param_insert_hasdefault(
714 compiler, stmt, c, implicit_return_defaults, values, kw
715 )
716
717 elif c.server_default is not None:
718 # column has a DDL-level default, and is either not a pk
719 # column or we don't need the pk.
720 if implicit_return_defaults and c in implicit_return_defaults:
721 compiler_implicit_returning.append(c)
722 elif not c.primary_key:
723 compiler.postfetch.append(c)
724
725 elif implicit_return_defaults and c in implicit_return_defaults:
726 compiler_implicit_returning.append(c)
727
728 elif (
729 c.primary_key
730 and c is not stmt.table._autoincrement_column
731 and not c.nullable
732 ):
733 _warn_pk_with_no_anticipated_value(c)
734
735 elif compile_state.isupdate:
736 # no parameter is present and it's an insert.
737
738 _append_param_update(
739 compiler,
740 compile_state,
741 stmt,
742 c,
743 implicit_return_defaults,
744 values,
745 kw,
746 )
747
748 # adding supplemental cols to implicit_returning in table
749 # order so that order is maintained between multiple INSERT
750 # statements which may have different parameters included, but all
751 # have the same RETURNING clause
752 if (
753 c in supplemental_returning
754 and c not in compiler_implicit_returning
755 ):
756 compiler_implicit_returning.append(c)
757
758 if supplemental_returning:
759 # we should have gotten every col into implicit_returning,
760 # however supplemental returning can also have SQL functions etc.
761 # in it
762 remaining_supplemental = supplemental_returning.difference(
763 compiler_implicit_returning
764 )
765 compiler_implicit_returning.extend(
766 c
767 for c in stmt._supplemental_returning
768 if c in remaining_supplemental
769 )
770
771 # TODO(return_defaults_columns): there can still be more columns in
772 # _return_defaults_columns in the case that they are from something like an
773 # aliased of the table. we can add them here, however this breaks other ORM
774 # things. so this is for another day. see
775 # test/orm/dml/test_update_delete_where.py -> test_update_from_alias
776
777 # if stmt._return_defaults_columns:
778 # compiler_implicit_returning.extend(
779 # set(stmt._return_defaults_columns)
780 # .difference(compiler_implicit_returning)
781 # .difference(cols_in_params)
782 # )
783
784 return (use_insertmanyvalues, use_sentinel_columns)
785
786
787def _setup_delete_return_defaults(
788 compiler,
789 stmt,
790 compile_state,
791 parameters,
792 _getattr_col_key,
793 _column_as_key,
794 _col_bind_name,
795 check_columns,
796 values,
797 toplevel,
798 kw,
799):
800 (_, _, implicit_return_defaults, *_) = _get_returning_modifiers(
801 compiler, stmt, compile_state, toplevel
802 )
803
804 if not implicit_return_defaults:
805 return
806
807 if stmt._return_defaults_columns:
808 compiler.implicit_returning.extend(implicit_return_defaults)
809
810 if stmt._supplemental_returning:
811 ir_set = set(compiler.implicit_returning)
812 compiler.implicit_returning.extend(
813 c for c in stmt._supplemental_returning if c not in ir_set
814 )
815
816
817def _append_param_parameter(
818 compiler,
819 stmt,
820 compile_state,
821 c,
822 col_key,
823 parameters,
824 _col_bind_name,
825 implicit_returning,
826 implicit_return_defaults,
827 postfetch_lastrowid,
828 values,
829 autoincrement_col,
830 insert_null_pk_still_autoincrements,
831 kw,
832):
833 value = parameters.pop(col_key)
834
835 col_value = compiler.preparer.format_column(
836 c, use_table=compile_state.include_table_with_column_exprs
837 )
838
839 accumulated_bind_names: Set[str] = set()
840
841 if coercions._is_literal(value):
842 if (
843 insert_null_pk_still_autoincrements
844 and c.primary_key
845 and c is autoincrement_col
846 ):
847 # support use case for #7998, fetch autoincrement cols
848 # even if value was given.
849
850 if postfetch_lastrowid:
851 compiler.postfetch_lastrowid = True
852 elif implicit_returning:
853 compiler.implicit_returning.append(c)
854
855 value = _create_bind_param(
856 compiler,
857 c,
858 value,
859 required=value is REQUIRED,
860 name=(
861 _col_bind_name(c)
862 if not _compile_state_isinsert(compile_state)
863 or not compile_state._has_multi_parameters
864 else "%s_m0" % _col_bind_name(c)
865 ),
866 accumulate_bind_names=accumulated_bind_names,
867 **kw,
868 )
869 elif value._is_bind_parameter:
870 if (
871 insert_null_pk_still_autoincrements
872 and value.value is None
873 and c.primary_key
874 and c is autoincrement_col
875 ):
876 # support use case for #7998, fetch autoincrement cols
877 # even if value was given
878 if implicit_returning:
879 compiler.implicit_returning.append(c)
880 elif compiler.dialect.postfetch_lastrowid:
881 compiler.postfetch_lastrowid = True
882
883 value = _handle_values_anonymous_param(
884 compiler,
885 c,
886 value,
887 name=(
888 _col_bind_name(c)
889 if not _compile_state_isinsert(compile_state)
890 or not compile_state._has_multi_parameters
891 else "%s_m0" % _col_bind_name(c)
892 ),
893 accumulate_bind_names=accumulated_bind_names,
894 **kw,
895 )
896 else:
897 # value is a SQL expression
898 value = compiler.process(
899 value.self_group(),
900 accumulate_bind_names=accumulated_bind_names,
901 **kw,
902 )
903
904 if compile_state.isupdate:
905 if implicit_return_defaults and c in implicit_return_defaults:
906 compiler.implicit_returning.append(c)
907
908 else:
909 compiler.postfetch.append(c)
910 else:
911 if c.primary_key:
912 if implicit_returning:
913 compiler.implicit_returning.append(c)
914 elif compiler.dialect.postfetch_lastrowid:
915 compiler.postfetch_lastrowid = True
916
917 elif implicit_return_defaults and (c in implicit_return_defaults):
918 compiler.implicit_returning.append(c)
919
920 else:
921 # postfetch specifically means, "we can SELECT the row we just
922 # inserted by primary key to get back the server generated
923 # defaults". so by definition this can't be used to get the
924 # primary key value back, because we need to have it ahead of
925 # time.
926
927 compiler.postfetch.append(c)
928
929 values.append((c, col_value, value, accumulated_bind_names))
930
931
932def _append_param_insert_pk_returning(compiler, stmt, c, values, kw):
933 """Create a primary key expression in the INSERT statement where
934 we want to populate result.inserted_primary_key and RETURNING
935 is available.
936
937 """
938 if c.default is not None:
939 if c.default.is_sequence:
940 if compiler.dialect.supports_sequences and (
941 not c.default.optional
942 or not compiler.dialect.sequences_optional
943 ):
944 accumulated_bind_names: Set[str] = set()
945 values.append(
946 (
947 c,
948 compiler.preparer.format_column(c),
949 compiler.process(
950 c.default,
951 accumulate_bind_names=accumulated_bind_names,
952 **kw,
953 ),
954 accumulated_bind_names,
955 )
956 )
957 compiler.implicit_returning.append(c)
958 elif c.default.is_clause_element:
959 accumulated_bind_names = set()
960 values.append(
961 (
962 c,
963 compiler.preparer.format_column(c),
964 compiler.process(
965 c.default.arg.self_group(),
966 accumulate_bind_names=accumulated_bind_names,
967 **kw,
968 ),
969 accumulated_bind_names,
970 )
971 )
972 compiler.implicit_returning.append(c)
973 else:
974 # client side default. OK we can't use RETURNING, need to
975 # do a "prefetch", which in fact fetches the default value
976 # on the Python side
977 values.append(
978 (
979 c,
980 compiler.preparer.format_column(c),
981 _create_insert_prefetch_bind_param(compiler, c, **kw),
982 (c.key,),
983 )
984 )
985 elif c is stmt.table._autoincrement_column or c.server_default is not None:
986 compiler.implicit_returning.append(c)
987 elif not c.nullable:
988 # no .default, no .server_default, not autoincrement, we have
989 # no indication this primary key column will have any value
990 _warn_pk_with_no_anticipated_value(c)
991
992
993def _append_param_insert_pk_no_returning(compiler, stmt, c, values, kw):
994 """Create a primary key expression in the INSERT statement where
995 we want to populate result.inserted_primary_key and we cannot use
996 RETURNING.
997
998 Depending on the kind of default here we may create a bound parameter
999 in the INSERT statement and pre-execute a default generation function,
1000 or we may use cursor.lastrowid if supported by the dialect.
1001
1002
1003 """
1004
1005 if (
1006 # column has a Python-side default
1007 c.default is not None
1008 and (
1009 # and it either is not a sequence, or it is and we support
1010 # sequences and want to invoke it
1011 not c.default.is_sequence
1012 or (
1013 compiler.dialect.supports_sequences
1014 and (
1015 not c.default.optional
1016 or not compiler.dialect.sequences_optional
1017 )
1018 )
1019 )
1020 ) or (
1021 # column is the "autoincrement column"
1022 c is stmt.table._autoincrement_column
1023 and (
1024 # dialect can't use cursor.lastrowid
1025 not compiler.dialect.postfetch_lastrowid
1026 and (
1027 # column has a Sequence and we support those
1028 (
1029 c.default is not None
1030 and c.default.is_sequence
1031 and compiler.dialect.supports_sequences
1032 )
1033 or
1034 # column has no default on it, but dialect can run the
1035 # "autoincrement" mechanism explicitly, e.g. PostgreSQL
1036 # SERIAL we know the sequence name
1037 (
1038 c.default is None
1039 and compiler.dialect.preexecute_autoincrement_sequences
1040 )
1041 )
1042 )
1043 ):
1044 # do a pre-execute of the default
1045 values.append(
1046 (
1047 c,
1048 compiler.preparer.format_column(c),
1049 _create_insert_prefetch_bind_param(compiler, c, **kw),
1050 (c.key,),
1051 )
1052 )
1053 elif (
1054 c.default is None
1055 and c.server_default is None
1056 and not c.nullable
1057 and c is not stmt.table._autoincrement_column
1058 ):
1059 # no .default, no .server_default, not autoincrement, we have
1060 # no indication this primary key column will have any value
1061 _warn_pk_with_no_anticipated_value(c)
1062 elif compiler.dialect.postfetch_lastrowid:
1063 # finally, where it seems like there will be a generated primary key
1064 # value and we haven't set up any other way to fetch it, and the
1065 # dialect supports cursor.lastrowid, switch on the lastrowid flag so
1066 # that the DefaultExecutionContext calls upon cursor.lastrowid
1067 compiler.postfetch_lastrowid = True
1068
1069
1070def _append_param_insert_hasdefault(
1071 compiler, stmt, c, implicit_return_defaults, values, kw
1072):
1073 if c.default.is_sequence:
1074 if compiler.dialect.supports_sequences and (
1075 not c.default.optional or not compiler.dialect.sequences_optional
1076 ):
1077 accumulated_bind_names: Set[str] = set()
1078 values.append(
1079 (
1080 c,
1081 compiler.preparer.format_column(c),
1082 compiler.process(
1083 c.default,
1084 accumulate_bind_names=accumulated_bind_names,
1085 **kw,
1086 ),
1087 accumulated_bind_names,
1088 )
1089 )
1090 if implicit_return_defaults and c in implicit_return_defaults:
1091 compiler.implicit_returning.append(c)
1092 elif not c.primary_key:
1093 compiler.postfetch.append(c)
1094 elif c.default.is_clause_element:
1095 accumulated_bind_names = set()
1096 values.append(
1097 (
1098 c,
1099 compiler.preparer.format_column(c),
1100 compiler.process(
1101 c.default.arg.self_group(),
1102 accumulate_bind_names=accumulated_bind_names,
1103 **kw,
1104 ),
1105 accumulated_bind_names,
1106 )
1107 )
1108
1109 if implicit_return_defaults and c in implicit_return_defaults:
1110 compiler.implicit_returning.append(c)
1111 elif not c.primary_key:
1112 # don't add primary key column to postfetch
1113 compiler.postfetch.append(c)
1114 else:
1115 values.append(
1116 (
1117 c,
1118 compiler.preparer.format_column(c),
1119 _create_insert_prefetch_bind_param(compiler, c, **kw),
1120 (c.key,),
1121 )
1122 )
1123
1124
1125def _append_param_insert_select_hasdefault(
1126 compiler: SQLCompiler,
1127 stmt: ValuesBase,
1128 c: ColumnClause[Any],
1129 values: List[_CrudParamElementSQLExpr],
1130 kw: Dict[str, Any],
1131) -> None:
1132 if default_is_sequence(c.default):
1133 if compiler.dialect.supports_sequences and (
1134 not c.default.optional or not compiler.dialect.sequences_optional
1135 ):
1136 values.append(
1137 (
1138 c,
1139 compiler.preparer.format_column(c),
1140 c.default.next_value(),
1141 (),
1142 )
1143 )
1144 elif default_is_clause_element(c.default):
1145 values.append(
1146 (
1147 c,
1148 compiler.preparer.format_column(c),
1149 c.default.arg.self_group(),
1150 (),
1151 )
1152 )
1153 else:
1154 values.append(
1155 (
1156 c,
1157 compiler.preparer.format_column(c),
1158 _create_insert_prefetch_bind_param(
1159 compiler, c, process=False, **kw
1160 ),
1161 (c.key,),
1162 )
1163 )
1164
1165
1166def _append_param_update(
1167 compiler, compile_state, stmt, c, implicit_return_defaults, values, kw
1168):
1169 include_table = compile_state.include_table_with_column_exprs
1170 if c.onupdate is not None and not c.onupdate.is_sequence:
1171 if c.onupdate.is_clause_element:
1172 values.append(
1173 (
1174 c,
1175 compiler.preparer.format_column(
1176 c,
1177 use_table=include_table,
1178 ),
1179 compiler.process(c.onupdate.arg.self_group(), **kw),
1180 (),
1181 )
1182 )
1183 if implicit_return_defaults and c in implicit_return_defaults:
1184 compiler.implicit_returning.append(c)
1185 else:
1186 compiler.postfetch.append(c)
1187 else:
1188 values.append(
1189 (
1190 c,
1191 compiler.preparer.format_column(
1192 c,
1193 use_table=include_table,
1194 ),
1195 _create_update_prefetch_bind_param(compiler, c, **kw),
1196 (c.key,),
1197 )
1198 )
1199 elif c.server_onupdate is not None:
1200 if implicit_return_defaults and c in implicit_return_defaults:
1201 compiler.implicit_returning.append(c)
1202 else:
1203 compiler.postfetch.append(c)
1204 elif (
1205 implicit_return_defaults
1206 and (stmt._return_defaults_columns or not stmt._return_defaults)
1207 and c in implicit_return_defaults
1208 ):
1209 compiler.implicit_returning.append(c)
1210
1211
1212@overload
1213def _create_insert_prefetch_bind_param(
1214 compiler: SQLCompiler,
1215 c: ColumnElement[Any],
1216 process: Literal[True] = ...,
1217 **kw: Any,
1218) -> str: ...
1219
1220
1221@overload
1222def _create_insert_prefetch_bind_param(
1223 compiler: SQLCompiler,
1224 c: ColumnElement[Any],
1225 process: Literal[False],
1226 **kw: Any,
1227) -> elements.BindParameter[Any]: ...
1228
1229
1230def _create_insert_prefetch_bind_param(
1231 compiler: SQLCompiler,
1232 c: ColumnElement[Any],
1233 process: bool = True,
1234 name: Optional[str] = None,
1235 **kw: Any,
1236) -> Union[elements.BindParameter[Any], str]:
1237 param = _create_bind_param(
1238 compiler, c, None, process=process, name=name, **kw
1239 )
1240 compiler.insert_prefetch.append(c) # type: ignore
1241 return param
1242
1243
1244@overload
1245def _create_update_prefetch_bind_param(
1246 compiler: SQLCompiler,
1247 c: ColumnElement[Any],
1248 process: Literal[True] = ...,
1249 **kw: Any,
1250) -> str: ...
1251
1252
1253@overload
1254def _create_update_prefetch_bind_param(
1255 compiler: SQLCompiler,
1256 c: ColumnElement[Any],
1257 process: Literal[False],
1258 **kw: Any,
1259) -> elements.BindParameter[Any]: ...
1260
1261
1262def _create_update_prefetch_bind_param(
1263 compiler: SQLCompiler,
1264 c: ColumnElement[Any],
1265 process: bool = True,
1266 name: Optional[str] = None,
1267 **kw: Any,
1268) -> Union[elements.BindParameter[Any], str]:
1269 param = _create_bind_param(
1270 compiler, c, None, process=process, name=name, **kw
1271 )
1272 compiler.update_prefetch.append(c) # type: ignore
1273 return param
1274
1275
1276class _multiparam_column(elements.ColumnElement[Any]):
1277 _is_multiparam_column = True
1278
1279 def __init__(self, original, index):
1280 self.index = index
1281 self.key = "%s_m%d" % (original.key, index + 1)
1282 self.original = original
1283 self.default = original.default
1284 self.type = original.type
1285
1286 def compare(self, other, **kw):
1287 raise NotImplementedError()
1288
1289 def _copy_internals(self, **kw):
1290 raise NotImplementedError()
1291
1292 def __eq__(self, other):
1293 return (
1294 isinstance(other, _multiparam_column)
1295 and other.key == self.key
1296 and other.original == self.original
1297 )
1298
1299 @util.memoized_property
1300 def _default_description_tuple(self) -> _DefaultDescriptionTuple:
1301 """used by default.py -> _process_execute_defaults()"""
1302
1303 return _DefaultDescriptionTuple._from_column_default(self.default)
1304
1305 @util.memoized_property
1306 def _onupdate_description_tuple(self) -> _DefaultDescriptionTuple:
1307 """used by default.py -> _process_execute_defaults()"""
1308
1309 return _DefaultDescriptionTuple._from_column_default(self.onupdate)
1310
1311
1312def _process_multiparam_default_bind(
1313 compiler: SQLCompiler,
1314 stmt: ValuesBase,
1315 c: KeyedColumnElement[Any],
1316 index: int,
1317 kw: Dict[str, Any],
1318) -> str:
1319 if not c.default:
1320 raise exc.CompileError(
1321 "INSERT value for column %s is explicitly rendered as a bound"
1322 "parameter in the VALUES clause; "
1323 "a Python-side value or SQL expression is required" % c
1324 )
1325 elif default_is_clause_element(c.default):
1326 return compiler.process(c.default.arg.self_group(), **kw)
1327 elif c.default.is_sequence:
1328 # these conditions would have been established
1329 # by append_param_insert_(?:hasdefault|pk_returning|pk_no_returning)
1330 # in order for us to be here, so these don't need to be
1331 # checked
1332 # assert compiler.dialect.supports_sequences and (
1333 # not c.default.optional
1334 # or not compiler.dialect.sequences_optional
1335 # )
1336 return compiler.process(c.default, **kw)
1337 else:
1338 col = _multiparam_column(c, index)
1339 assert isinstance(stmt, dml.Insert)
1340 return _create_insert_prefetch_bind_param(
1341 compiler, col, process=True, **kw
1342 )
1343
1344
1345def _get_update_multitable_params(
1346 compiler,
1347 stmt,
1348 compile_state,
1349 stmt_parameter_tuples,
1350 check_columns,
1351 _col_bind_name,
1352 _getattr_col_key,
1353 values,
1354 kw,
1355):
1356 normalized_params = {
1357 coercions.expect(roles.DMLColumnRole, c): param
1358 for c, param in stmt_parameter_tuples or ()
1359 }
1360
1361 include_table = compile_state.include_table_with_column_exprs
1362
1363 affected_tables = set()
1364 for t in compile_state._extra_froms:
1365 for c in t.c:
1366 if c in normalized_params:
1367 affected_tables.add(t)
1368 check_columns[_getattr_col_key(c)] = c
1369 value = normalized_params[c]
1370
1371 col_value = compiler.process(c, include_table=include_table)
1372 if coercions._is_literal(value):
1373 value = _create_bind_param(
1374 compiler,
1375 c,
1376 value,
1377 required=value is REQUIRED,
1378 name=_col_bind_name(c),
1379 **kw, # TODO: no test coverage for literal binds here
1380 )
1381 accumulated_bind_names: Iterable[str] = (c.key,)
1382 elif value._is_bind_parameter:
1383 cbn = _col_bind_name(c)
1384 value = _handle_values_anonymous_param(
1385 compiler, c, value, name=cbn, **kw
1386 )
1387 accumulated_bind_names = (cbn,)
1388 else:
1389 compiler.postfetch.append(c)
1390 value = compiler.process(value.self_group(), **kw)
1391 accumulated_bind_names = ()
1392 values.append((c, col_value, value, accumulated_bind_names))
1393 # determine tables which are actually to be updated - process onupdate
1394 # and server_onupdate for these
1395 for t in affected_tables:
1396 for c in t.c:
1397 if c in normalized_params:
1398 continue
1399 elif c.onupdate is not None and not c.onupdate.is_sequence:
1400 if c.onupdate.is_clause_element:
1401 values.append(
1402 (
1403 c,
1404 compiler.process(c, include_table=include_table),
1405 compiler.process(
1406 c.onupdate.arg.self_group(), **kw
1407 ),
1408 (),
1409 )
1410 )
1411 compiler.postfetch.append(c)
1412 else:
1413 values.append(
1414 (
1415 c,
1416 compiler.process(c, include_table=include_table),
1417 _create_update_prefetch_bind_param(
1418 compiler, c, name=_col_bind_name(c), **kw
1419 ),
1420 (c.key,),
1421 )
1422 )
1423 elif c.server_onupdate is not None:
1424 compiler.postfetch.append(c)
1425
1426
1427def _extend_values_for_multiparams(
1428 compiler: SQLCompiler,
1429 stmt: ValuesBase,
1430 compile_state: DMLState,
1431 initial_values: Sequence[_CrudParamElementStr],
1432 _column_as_key: Callable[..., str],
1433 kw: Dict[str, Any],
1434) -> List[Sequence[_CrudParamElementStr]]:
1435 values_0 = initial_values
1436 values = [initial_values]
1437
1438 mp = compile_state._multi_parameters
1439 assert mp is not None
1440 for i, row in enumerate(mp[1:]):
1441 extension: List[_CrudParamElementStr] = []
1442
1443 row = {_column_as_key(key): v for key, v in row.items()}
1444
1445 for col, col_expr, param, accumulated_names in values_0:
1446 if col.key in row:
1447 key = col.key
1448
1449 if coercions._is_literal(row[key]):
1450 new_param = _create_bind_param(
1451 compiler,
1452 col,
1453 row[key],
1454 name="%s_m%d" % (col.key, i + 1),
1455 **kw,
1456 )
1457 else:
1458 new_param = compiler.process(row[key].self_group(), **kw)
1459 else:
1460 new_param = _process_multiparam_default_bind(
1461 compiler, stmt, col, i, kw
1462 )
1463
1464 extension.append((col, col_expr, new_param, accumulated_names))
1465
1466 values.append(extension)
1467
1468 return values
1469
1470
1471def _get_stmt_parameter_tuples_params(
1472 compiler,
1473 compile_state,
1474 parameters,
1475 stmt_parameter_tuples,
1476 _column_as_key,
1477 values,
1478 kw,
1479):
1480 for k, v in stmt_parameter_tuples:
1481 colkey = _column_as_key(k)
1482 if colkey is not None:
1483 parameters.setdefault(colkey, v)
1484 else:
1485 # a non-Column expression on the left side;
1486 # add it to values() in an "as-is" state,
1487 # coercing right side to bound param
1488
1489 # note one of the main use cases for this is array slice
1490 # updates on PostgreSQL, as the left side is also an expression.
1491
1492 col_expr = compiler.process(
1493 k, include_table=compile_state.include_table_with_column_exprs
1494 )
1495
1496 if coercions._is_literal(v):
1497 v = compiler.process(
1498 elements.BindParameter(None, v, type_=k.type), **kw
1499 )
1500 else:
1501 if v._is_bind_parameter and v.type._isnull:
1502 # either unique parameter, or other bound parameters that
1503 # were passed in directly
1504 # set type to that of the column unconditionally
1505 v = v._with_binary_element_type(k.type)
1506
1507 v = compiler.process(v.self_group(), **kw)
1508
1509 # TODO: not sure if accumulated_bind_names applies here
1510 values.append((k, col_expr, v, ()))
1511
1512
1513def _get_returning_modifiers(compiler, stmt, compile_state, toplevel):
1514 """determines RETURNING strategy, if any, for the statement.
1515
1516 This is where it's determined what we need to fetch from the
1517 INSERT or UPDATE statement after it's invoked.
1518
1519 """
1520
1521 dialect = compiler.dialect
1522
1523 need_pks = (
1524 toplevel
1525 and _compile_state_isinsert(compile_state)
1526 and not stmt._inline
1527 and (
1528 not compiler.for_executemany
1529 or (dialect.insert_executemany_returning and stmt._return_defaults)
1530 )
1531 and not stmt._returning
1532 # and (not stmt._returning or stmt._return_defaults)
1533 and not compile_state._has_multi_parameters
1534 )
1535
1536 # check if we have access to simple cursor.lastrowid. we can use that
1537 # after the INSERT if that's all we need.
1538 postfetch_lastrowid = (
1539 need_pks
1540 and dialect.postfetch_lastrowid
1541 and stmt.table._autoincrement_column is not None
1542 )
1543
1544 # see if we want to add RETURNING to an INSERT in order to get
1545 # primary key columns back. This would be instead of postfetch_lastrowid
1546 # if that's set.
1547 implicit_returning = (
1548 # statement itself can veto it
1549 need_pks
1550 # the dialect can veto it if it just doesnt support RETURNING
1551 # with INSERT
1552 and dialect.insert_returning
1553 # user-defined implicit_returning on Table can veto it
1554 and compile_state._primary_table.implicit_returning
1555 # the compile_state can veto it (SQlite uses this to disable
1556 # RETURNING for an ON CONFLICT insert, as SQLite does not return
1557 # for rows that were updated, which is wrong)
1558 and compile_state._supports_implicit_returning
1559 and (
1560 # since we support MariaDB and SQLite which also support lastrowid,
1561 # decide if we should use lastrowid or RETURNING. for insert
1562 # that didnt call return_defaults() and has just one set of
1563 # parameters, we can use lastrowid. this is more "traditional"
1564 # and a lot of weird use cases are supported by it.
1565 # SQLite lastrowid times 3x faster than returning,
1566 # Mariadb lastrowid 2x faster than returning
1567 (not postfetch_lastrowid or dialect.favor_returning_over_lastrowid)
1568 or compile_state._has_multi_parameters
1569 or stmt._return_defaults
1570 )
1571 )
1572 if implicit_returning:
1573 postfetch_lastrowid = False
1574
1575 if _compile_state_isinsert(compile_state):
1576 should_implicit_return_defaults = (
1577 implicit_returning and stmt._return_defaults
1578 )
1579 explicit_returning = (
1580 should_implicit_return_defaults
1581 or stmt._returning
1582 or stmt._supplemental_returning
1583 )
1584 use_insertmanyvalues = (
1585 toplevel
1586 and compiler.for_executemany
1587 and dialect.use_insertmanyvalues
1588 and (
1589 explicit_returning or dialect.use_insertmanyvalues_wo_returning
1590 )
1591 )
1592
1593 use_sentinel_columns = None
1594 if (
1595 use_insertmanyvalues
1596 and explicit_returning
1597 and stmt._sort_by_parameter_order
1598 ):
1599 use_sentinel_columns = compiler._get_sentinel_column_for_table(
1600 stmt.table
1601 )
1602
1603 elif compile_state.isupdate:
1604 should_implicit_return_defaults = (
1605 stmt._return_defaults
1606 and compile_state._primary_table.implicit_returning
1607 and compile_state._supports_implicit_returning
1608 and dialect.update_returning
1609 )
1610 use_insertmanyvalues = False
1611 use_sentinel_columns = None
1612 elif compile_state.isdelete:
1613 should_implicit_return_defaults = (
1614 stmt._return_defaults
1615 and compile_state._primary_table.implicit_returning
1616 and compile_state._supports_implicit_returning
1617 and dialect.delete_returning
1618 )
1619 use_insertmanyvalues = False
1620 use_sentinel_columns = None
1621 else:
1622 should_implicit_return_defaults = False # pragma: no cover
1623 use_insertmanyvalues = False
1624 use_sentinel_columns = None
1625
1626 if should_implicit_return_defaults:
1627 if not stmt._return_defaults_columns:
1628 # TODO: this is weird. See #9685 where we have to
1629 # take an extra step to prevent this from happening. why
1630 # would this ever be *all* columns? but if we set to blank, then
1631 # that seems to break things also in the ORM. So we should
1632 # try to clean this up and figure out what return_defaults
1633 # needs to do w/ the ORM etc. here
1634 implicit_return_defaults = set(stmt.table.c)
1635 else:
1636 implicit_return_defaults = set(stmt._return_defaults_columns)
1637 else:
1638 implicit_return_defaults = None
1639
1640 return (
1641 need_pks,
1642 implicit_returning or should_implicit_return_defaults,
1643 implicit_return_defaults,
1644 postfetch_lastrowid,
1645 use_insertmanyvalues,
1646 use_sentinel_columns,
1647 )
1648
1649
1650def _warn_pk_with_no_anticipated_value(c):
1651 msg = (
1652 "Column '%s.%s' is marked as a member of the "
1653 "primary key for table '%s', "
1654 "but has no Python-side or server-side default generator indicated, "
1655 "nor does it indicate 'autoincrement=True' or 'nullable=True', "
1656 "and no explicit value is passed. "
1657 "Primary key columns typically may not store NULL."
1658 % (c.table.fullname, c.name, c.table.fullname)
1659 )
1660 if len(c.table.primary_key) > 1:
1661 msg += (
1662 " Note that as of SQLAlchemy 1.1, 'autoincrement=True' must be "
1663 "indicated explicitly for composite (e.g. multicolumn) primary "
1664 "keys if AUTO_INCREMENT/SERIAL/IDENTITY "
1665 "behavior is expected for one of the columns in the primary key. "
1666 "CREATE TABLE statements are impacted by this change as well on "
1667 "most backends."
1668 )
1669 util.warn(msg)