Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/sqlalchemy/sql/crud.py: 40%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

500 statements  

1# sql/crud.py 

2# Copyright (C) 2005-2026 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""" 

13 

14from __future__ import annotations 

15 

16import functools 

17import operator 

18from typing import Any 

19from typing import Callable 

20from typing import cast 

21from typing import Dict 

22from typing import Iterable 

23from typing import List 

24from typing import MutableMapping 

25from typing import NamedTuple 

26from typing import Optional 

27from typing import overload 

28from typing import Sequence 

29from typing import Set 

30from typing import Tuple 

31from typing import TYPE_CHECKING 

32from typing import Union 

33 

34from . import coercions 

35from . import dml 

36from . import elements 

37from . import roles 

38from .base import _DefaultDescriptionTuple 

39from .dml import isinsert as _compile_state_isinsert 

40from .elements import ColumnClause 

41from .schema import default_is_clause_element 

42from .schema import default_is_sequence 

43from .selectable import Select 

44from .selectable import TableClause 

45from .. import exc 

46from .. import util 

47from ..util.typing import Literal 

48 

49if TYPE_CHECKING: 

50 from .compiler import _BindNameForColProtocol 

51 from .compiler import SQLCompiler 

52 from .dml import _DMLColumnElement 

53 from .dml import DMLState 

54 from .dml import ValuesBase 

55 from .elements import ColumnElement 

56 from .elements import KeyedColumnElement 

57 from .schema import _SQLExprDefault 

58 from .schema import Column 

59 

60REQUIRED = util.symbol( 

61 "REQUIRED", 

62 """ 

63Placeholder for the value within a :class:`.BindParameter` 

64which is required to be present when the statement is passed 

65to :meth:`_engine.Connection.execute`. 

66 

67This symbol is typically used when a :func:`_expression.insert` 

68or :func:`_expression.update` statement is compiled without parameter 

69values present. 

70 

71""", 

72) 

73 

74 

75def _as_dml_column(c: ColumnElement[Any]) -> ColumnClause[Any]: 

76 if not isinstance(c, ColumnClause): 

77 raise exc.CompileError( 

78 f"Can't create DML statement against column expression {c!r}" 

79 ) 

80 return c 

81 

82 

83_CrudParamElement = Tuple[ 

84 "ColumnElement[Any]", 

85 str, # column name 

86 Optional[ 

87 Union[str, "_SQLExprDefault"] 

88 ], # bound parameter string or SQL expression to apply 

89 Iterable[str], 

90] 

91_CrudParamElementStr = Tuple[ 

92 "KeyedColumnElement[Any]", 

93 str, # column name 

94 str, # bound parameter string 

95 Iterable[str], 

96] 

97_CrudParamElementSQLExpr = Tuple[ 

98 "ColumnClause[Any]", 

99 str, 

100 "_SQLExprDefault", # SQL expression to apply 

101 Iterable[str], 

102] 

103 

104_CrudParamSequence = List[_CrudParamElement] 

105 

106 

107class _CrudParams(NamedTuple): 

108 single_params: List[_CrudParamElementStr] 

109 all_multi_params: List[Sequence[_CrudParamElementStr]] 

110 is_default_metavalue_only: bool = False 

111 use_insertmanyvalues: bool = False 

112 use_sentinel_columns: Optional[Sequence[Column[Any]]] = None 

113 

114 

115def _get_crud_params( 

116 compiler: SQLCompiler, 

117 stmt: ValuesBase, 

118 compile_state: DMLState, 

119 toplevel: bool, 

120 **kw: Any, 

121) -> _CrudParams: 

122 """create a set of tuples representing column/string pairs for use 

123 in an INSERT or UPDATE statement. 

124 

125 Also generates the Compiled object's postfetch, prefetch, and 

126 returning column collections, used for default handling and ultimately 

127 populating the CursorResult's prefetch_cols() and postfetch_cols() 

128 collections. 

129 

130 """ 

131 

132 # note: the _get_crud_params() system was written with the notion in mind 

133 # that INSERT, UPDATE, DELETE are always the top level statement and 

134 # that there is only one of them. With the addition of CTEs that can 

135 # make use of DML, this assumption is no longer accurate; the DML 

136 # statement is not necessarily the top-level "row returning" thing 

137 # and it is also theoretically possible (fortunately nobody has asked yet) 

138 # to have a single statement with multiple DMLs inside of it via CTEs. 

139 

140 # the current _get_crud_params() design doesn't accommodate these cases 

141 # right now. It "just works" for a CTE that has a single DML inside of 

142 # it, and for a CTE with multiple DML, it's not clear what would happen. 

143 

144 # overall, the "compiler.XYZ" collections here would need to be in a 

145 # per-DML structure of some kind, and DefaultDialect would need to 

146 # navigate these collections on a per-statement basis, with additional 

147 # emphasis on the "toplevel returning data" statement. However we 

148 # still need to run through _get_crud_params() for all DML as we have 

149 # Python / SQL generated column defaults that need to be rendered. 

150 

151 # if there is user need for this kind of thing, it's likely a post 2.0 

152 # kind of change as it would require deep changes to DefaultDialect 

153 # as well as here. 

154 

155 compiler.postfetch = [] 

156 compiler.insert_prefetch = [] 

157 compiler.update_prefetch = [] 

158 compiler.implicit_returning = [] 

159 

160 visiting_cte = kw.get("visiting_cte", None) 

161 if visiting_cte is not None: 

162 # for insert -> CTE -> insert, don't populate an incoming 

163 # _crud_accumulate_bind_names collection; the INSERT we process here 

164 # will not be inline within the VALUES of the enclosing INSERT as the 

165 # CTE is placed on the outside. See issue #9173 

166 kw.pop("accumulate_bind_names", None) 

167 assert ( 

168 "accumulate_bind_names" not in kw 

169 ), "Don't know how to handle insert within insert without a CTE" 

170 

171 # getters - these are normally just column.key, 

172 # but in the case of mysql multi-table update, the rules for 

173 # .key must conditionally take tablename into account 

174 ( 

175 _column_as_key, 

176 _getattr_col_key, 

177 _col_bind_name, 

178 ) = _key_getters_for_crud_column(compiler, stmt, compile_state) 

179 

180 compiler._get_bind_name_for_col = _col_bind_name 

181 

182 if stmt._returning and stmt._return_defaults: 

183 raise exc.CompileError( 

184 "Can't compile statement that includes returning() and " 

185 "return_defaults() simultaneously" 

186 ) 

187 

188 if compile_state.isdelete: 

189 _setup_delete_return_defaults( 

190 compiler, 

191 stmt, 

192 compile_state, 

193 (), 

194 _getattr_col_key, 

195 _column_as_key, 

196 _col_bind_name, 

197 (), 

198 (), 

199 toplevel, 

200 kw, 

201 ) 

202 return _CrudParams([], []) 

203 

204 # no parameters in the statement, no parameters in the 

205 # compiled params - return binds for all columns 

206 if compiler.column_keys is None and compile_state._no_parameters: 

207 return _CrudParams( 

208 [ 

209 ( 

210 c, 

211 compiler.preparer.format_column(c), 

212 _create_bind_param(compiler, c, None, required=True), 

213 (c.key,), 

214 ) 

215 for c in stmt.table.columns 

216 if not c._omit_from_statements 

217 ], 

218 [], 

219 ) 

220 

221 stmt_parameter_tuples: Optional[ 

222 List[Tuple[Union[str, ColumnClause[Any]], Any]] 

223 ] 

224 spd: Optional[MutableMapping[_DMLColumnElement, Any]] 

225 

226 if ( 

227 _compile_state_isinsert(compile_state) 

228 and compile_state._has_multi_parameters 

229 ): 

230 mp = compile_state._multi_parameters 

231 assert mp is not None 

232 spd = mp[0] 

233 stmt_parameter_tuples = list(spd.items()) 

234 spd_str_key = {_column_as_key(key) for key in spd} 

235 elif compile_state._ordered_values: 

236 spd = compile_state._dict_parameters 

237 stmt_parameter_tuples = compile_state._ordered_values 

238 assert spd is not None 

239 spd_str_key = {_column_as_key(key) for key in spd} 

240 elif compile_state._dict_parameters: 

241 spd = compile_state._dict_parameters 

242 stmt_parameter_tuples = list(spd.items()) 

243 spd_str_key = {_column_as_key(key) for key in spd} 

244 else: 

245 stmt_parameter_tuples = spd_str_key = None 

246 

247 # if we have statement parameters - set defaults in the 

248 # compiled params 

249 if compiler.column_keys is None: 

250 parameters = {} 

251 elif stmt_parameter_tuples: 

252 assert spd_str_key is not None 

253 parameters = { 

254 _column_as_key(key): REQUIRED 

255 for key in compiler.column_keys 

256 if key not in spd_str_key 

257 } 

258 else: 

259 parameters = { 

260 _column_as_key(key): REQUIRED for key in compiler.column_keys 

261 } 

262 

263 # create a list of column assignment clauses as tuples 

264 values: List[_CrudParamElementStr] = [] 

265 

266 if stmt_parameter_tuples is not None: 

267 _get_stmt_parameter_tuples_params( 

268 compiler, 

269 compile_state, 

270 parameters, 

271 stmt_parameter_tuples, 

272 _column_as_key, 

273 values, 

274 kw, 

275 ) 

276 

277 check_columns: Dict[str, ColumnClause[Any]] = {} 

278 

279 # special logic that only occurs for multi-table UPDATE 

280 # statements 

281 if dml.isupdate(compile_state) and compile_state.is_multitable: 

282 _get_update_multitable_params( 

283 compiler, 

284 stmt, 

285 compile_state, 

286 stmt_parameter_tuples, 

287 check_columns, 

288 _col_bind_name, 

289 _getattr_col_key, 

290 values, 

291 kw, 

292 ) 

293 

294 if _compile_state_isinsert(compile_state) and stmt._select_names: 

295 # is an insert from select, is not a multiparams 

296 

297 assert not compile_state._has_multi_parameters 

298 

299 _scan_insert_from_select_cols( 

300 compiler, 

301 stmt, 

302 compile_state, 

303 parameters, 

304 _getattr_col_key, 

305 _column_as_key, 

306 _col_bind_name, 

307 check_columns, 

308 values, 

309 toplevel, 

310 kw, 

311 ) 

312 use_insertmanyvalues = False 

313 use_sentinel_columns = None 

314 else: 

315 use_insertmanyvalues, use_sentinel_columns = _scan_cols( 

316 compiler, 

317 stmt, 

318 compile_state, 

319 parameters, 

320 _getattr_col_key, 

321 _column_as_key, 

322 _col_bind_name, 

323 check_columns, 

324 values, 

325 toplevel, 

326 kw, 

327 ) 

328 

329 if parameters and stmt_parameter_tuples: 

330 check = ( 

331 set(parameters) 

332 .intersection(_column_as_key(k) for k, v in stmt_parameter_tuples) 

333 .difference(check_columns) 

334 ) 

335 if check: 

336 

337 if dml.isupdate(compile_state): 

338 tables_mentioned = set( 

339 c.table 

340 for c, v in stmt_parameter_tuples 

341 if isinstance(c, ColumnClause) and c.table is not None 

342 ).difference([compile_state.dml_table]) 

343 

344 multi_not_in_from = tables_mentioned.difference( 

345 compile_state._extra_froms 

346 ) 

347 

348 if tables_mentioned and ( 

349 not compile_state.is_multitable 

350 or not compiler.render_table_with_column_in_update_from 

351 ): 

352 if not compiler.render_table_with_column_in_update_from: 

353 preamble = ( 

354 "Backend does not support additional " 

355 "tables in the SET clause" 

356 ) 

357 else: 

358 preamble = ( 

359 "Statement is not a multi-table UPDATE statement" 

360 ) 

361 

362 raise exc.CompileError( 

363 f"{preamble}; cannot " 

364 f"""include columns from table(s) { 

365 ", ".join(f"'{t.description}'" 

366 for t in tables_mentioned) 

367 } in SET clause""" 

368 ) 

369 

370 elif multi_not_in_from: 

371 assert compiler.render_table_with_column_in_update_from 

372 raise exc.CompileError( 

373 f"Multi-table UPDATE statement does not include " 

374 "table(s) " 

375 f"""{ 

376 ", ".join( 

377 f"'{t.description}'" for 

378 t in multi_not_in_from) 

379 }""" 

380 ) 

381 

382 raise exc.CompileError( 

383 "Unconsumed column names: %s" 

384 % (", ".join("%s" % (c,) for c in check)) 

385 ) 

386 

387 is_default_metavalue_only = False 

388 

389 if ( 

390 _compile_state_isinsert(compile_state) 

391 and compile_state._has_multi_parameters 

392 ): 

393 # is a multiparams, is not an insert from a select 

394 assert not stmt._select_names 

395 multi_extended_values = _extend_values_for_multiparams( 

396 compiler, 

397 stmt, 

398 compile_state, 

399 cast( 

400 "Sequence[_CrudParamElementStr]", 

401 values, 

402 ), 

403 cast("Callable[..., str]", _column_as_key), 

404 kw, 

405 ) 

406 return _CrudParams(values, multi_extended_values) 

407 elif ( 

408 not values 

409 and compiler.for_executemany 

410 and compiler.dialect.supports_default_metavalue 

411 ): 

412 # convert an "INSERT DEFAULT VALUES" 

413 # into INSERT (firstcol) VALUES (DEFAULT) which can be turned 

414 # into an in-place multi values. This supports 

415 # insert_executemany_returning mode :) 

416 values = [ 

417 ( 

418 _as_dml_column(stmt.table.columns[0]), 

419 compiler.preparer.format_column(stmt.table.columns[0]), 

420 compiler.dialect.default_metavalue_token, 

421 (), 

422 ) 

423 ] 

424 is_default_metavalue_only = True 

425 

426 return _CrudParams( 

427 values, 

428 [], 

429 is_default_metavalue_only=is_default_metavalue_only, 

430 use_insertmanyvalues=use_insertmanyvalues, 

431 use_sentinel_columns=use_sentinel_columns, 

432 ) 

433 

434 

435@overload 

436def _create_bind_param( 

437 compiler: SQLCompiler, 

438 col: ColumnElement[Any], 

439 value: Any, 

440 process: Literal[True] = ..., 

441 required: bool = False, 

442 name: Optional[str] = None, 

443 force_anonymous: bool = False, 

444 **kw: Any, 

445) -> str: ... 

446 

447 

448@overload 

449def _create_bind_param( 

450 compiler: SQLCompiler, 

451 col: ColumnElement[Any], 

452 value: Any, 

453 **kw: Any, 

454) -> str: ... 

455 

456 

457def _create_bind_param( 

458 compiler: SQLCompiler, 

459 col: ColumnElement[Any], 

460 value: Any, 

461 process: bool = True, 

462 required: bool = False, 

463 name: Optional[str] = None, 

464 force_anonymous: bool = False, 

465 **kw: Any, 

466) -> Union[str, elements.BindParameter[Any]]: 

467 if force_anonymous: 

468 name = None 

469 elif name is None: 

470 name = col.key 

471 

472 bindparam = elements.BindParameter( 

473 name, value, type_=col.type, required=required 

474 ) 

475 bindparam._is_crud = True 

476 if process: 

477 return bindparam._compiler_dispatch(compiler, **kw) 

478 else: 

479 return bindparam 

480 

481 

482def _handle_values_anonymous_param(compiler, col, value, name, **kw): 

483 # the insert() and update() constructs as of 1.4 will now produce anonymous 

484 # bindparam() objects in the values() collections up front when given plain 

485 # literal values. This is so that cache key behaviors, which need to 

486 # produce bound parameters in deterministic order without invoking any 

487 # compilation here, can be applied to these constructs when they include 

488 # values() (but not yet multi-values, which are not included in caching 

489 # right now). 

490 # 

491 # in order to produce the desired "crud" style name for these parameters, 

492 # which will also be targetable in engine/default.py through the usual 

493 # conventions, apply our desired name to these unique parameters by 

494 # populating the compiler truncated names cache with the desired name, 

495 # rather than having 

496 # compiler.visit_bindparam()->compiler._truncated_identifier make up a 

497 # name. Saves on call counts also. 

498 

499 # for INSERT/UPDATE that's a CTE, we don't need names to match to 

500 # external parameters and these would also conflict in the case where 

501 # multiple insert/update are combined together using CTEs 

502 is_cte = "visiting_cte" in kw 

503 

504 if ( 

505 not is_cte 

506 and value.unique 

507 and isinstance(value.key, elements._truncated_label) 

508 ): 

509 compiler.truncated_names[("bindparam", value.key)] = name 

510 

511 if value.type._isnull: 

512 # either unique parameter, or other bound parameters that were 

513 # passed in directly 

514 # set type to that of the column unconditionally 

515 value = value._with_binary_element_type(col.type) 

516 

517 return value._compiler_dispatch(compiler, **kw) 

518 

519 

520def _key_getters_for_crud_column( 

521 compiler: SQLCompiler, stmt: ValuesBase, compile_state: DMLState 

522) -> Tuple[ 

523 Callable[[Union[str, ColumnClause[Any]]], Union[str, Tuple[str, str]]], 

524 Callable[[ColumnClause[Any]], Union[str, Tuple[str, str]]], 

525 _BindNameForColProtocol, 

526]: 

527 if dml.isupdate(compile_state) and compile_state._extra_froms: 

528 # when extra tables are present, refer to the columns 

529 # in those extra tables as table-qualified, including in 

530 # dictionaries and when rendering bind param names. 

531 # the "main" table of the statement remains unqualified, 

532 # allowing the most compatibility with a non-multi-table 

533 # statement. 

534 _et = set(compile_state._extra_froms) 

535 

536 c_key_role = functools.partial( 

537 coercions.expect_as_key, roles.DMLColumnRole 

538 ) 

539 

540 def _column_as_key( 

541 key: Union[ColumnClause[Any], str], 

542 ) -> Union[str, Tuple[str, str]]: 

543 str_key = c_key_role(key) 

544 if hasattr(key, "table") and key.table in _et: 

545 return (key.table.name, str_key) # type: ignore 

546 else: 

547 return str_key 

548 

549 def _getattr_col_key( 

550 col: ColumnClause[Any], 

551 ) -> Union[str, Tuple[str, str]]: 

552 if col.table in _et: 

553 return (col.table.name, col.key) # type: ignore 

554 else: 

555 return col.key 

556 

557 def _col_bind_name(col: ColumnClause[Any]) -> str: 

558 if col.table in _et: 

559 if TYPE_CHECKING: 

560 assert isinstance(col.table, TableClause) 

561 return "%s_%s" % (col.table.name, col.key) 

562 else: 

563 return col.key 

564 

565 else: 

566 _column_as_key = functools.partial( 

567 coercions.expect_as_key, roles.DMLColumnRole 

568 ) 

569 _getattr_col_key = _col_bind_name = operator.attrgetter("key") # type: ignore # noqa: E501 

570 

571 return _column_as_key, _getattr_col_key, _col_bind_name 

572 

573 

574def _scan_insert_from_select_cols( 

575 compiler, 

576 stmt, 

577 compile_state, 

578 parameters, 

579 _getattr_col_key, 

580 _column_as_key, 

581 _col_bind_name, 

582 check_columns, 

583 values, 

584 toplevel, 

585 kw, 

586): 

587 cols = [stmt.table.c[_column_as_key(name)] for name in stmt._select_names] 

588 

589 assert compiler.stack[-1]["selectable"] is stmt 

590 

591 compiler.stack[-1]["insert_from_select"] = stmt.select 

592 

593 add_select_cols: List[_CrudParamElementSQLExpr] = [] 

594 if stmt.include_insert_from_select_defaults: 

595 col_set = set(cols) 

596 for col in stmt.table.columns: 

597 # omit columns that were not in the SELECT statement. 

598 # this will omit columns marked as omit_from_statements naturally, 

599 # as long as that col was not explicit in the SELECT. 

600 # if an omit_from_statements col has a "default" on it, then 

601 # we need to include it, as these defaults should still fire off. 

602 # but, if it has that default and it's the "sentinel" default, 

603 # we don't do sentinel default operations for insert_from_select 

604 # here so we again omit it. 

605 if ( 

606 col not in col_set 

607 and col.default 

608 and not col.default.is_sentinel 

609 ): 

610 cols.append(col) 

611 

612 for c in cols: 

613 col_key = _getattr_col_key(c) 

614 if col_key in parameters and col_key not in check_columns: 

615 parameters.pop(col_key) 

616 values.append((c, compiler.preparer.format_column(c), None, ())) 

617 else: 

618 _append_param_insert_select_hasdefault( 

619 compiler, stmt, c, add_select_cols, kw 

620 ) 

621 

622 if add_select_cols: 

623 values.extend(add_select_cols) 

624 ins_from_select = compiler.stack[-1]["insert_from_select"] 

625 if not isinstance(ins_from_select, Select): 

626 raise exc.CompileError( 

627 f"Can't extend statement for INSERT..FROM SELECT to include " 

628 f"additional default-holding column(s) " 

629 f"""{ 

630 ', '.join(repr(key) for _, key, _, _ in add_select_cols) 

631 }. Convert the selectable to a subquery() first, or pass """ 

632 "include_defaults=False to Insert.from_select() to skip these " 

633 "columns." 

634 ) 

635 ins_from_select = ins_from_select._generate() 

636 # copy raw_columns 

637 ins_from_select._raw_columns = list(ins_from_select._raw_columns) + [ 

638 expr for _, _, expr, _ in add_select_cols 

639 ] 

640 compiler.stack[-1]["insert_from_select"] = ins_from_select 

641 

642 

643def _scan_cols( 

644 compiler, 

645 stmt, 

646 compile_state, 

647 parameters, 

648 _getattr_col_key, 

649 _column_as_key, 

650 _col_bind_name, 

651 check_columns, 

652 values, 

653 toplevel, 

654 kw, 

655): 

656 ( 

657 need_pks, 

658 implicit_returning, 

659 implicit_return_defaults, 

660 postfetch_lastrowid, 

661 use_insertmanyvalues, 

662 use_sentinel_columns, 

663 ) = _get_returning_modifiers(compiler, stmt, compile_state, toplevel) 

664 

665 assert compile_state.isupdate or compile_state.isinsert 

666 

667 if compile_state._parameter_ordering: 

668 parameter_ordering = [ 

669 _column_as_key(key) for key in compile_state._parameter_ordering 

670 ] 

671 ordered_keys = set(parameter_ordering) 

672 cols = [ 

673 stmt.table.c[key] 

674 for key in parameter_ordering 

675 if isinstance(key, str) and key in stmt.table.c 

676 ] + [c for c in stmt.table.c if c.key not in ordered_keys] 

677 

678 else: 

679 cols = stmt.table.columns 

680 

681 isinsert = _compile_state_isinsert(compile_state) 

682 if isinsert and not compile_state._has_multi_parameters: 

683 # new rules for #7998. fetch lastrowid or implicit returning 

684 # for autoincrement column even if parameter is NULL, for DBs that 

685 # override NULL param for primary key (sqlite, mysql/mariadb) 

686 autoincrement_col = stmt.table._autoincrement_column 

687 insert_null_pk_still_autoincrements = ( 

688 compiler.dialect.insert_null_pk_still_autoincrements 

689 ) 

690 else: 

691 autoincrement_col = insert_null_pk_still_autoincrements = None 

692 

693 if stmt._supplemental_returning: 

694 supplemental_returning = set(stmt._supplemental_returning) 

695 else: 

696 supplemental_returning = set() 

697 

698 compiler_implicit_returning = compiler.implicit_returning 

699 

700 # TODO - see TODO(return_defaults_columns) below 

701 # cols_in_params = set() 

702 

703 for c in cols: 

704 # scan through every column in the target table 

705 

706 col_key = _getattr_col_key(c) 

707 

708 if col_key in parameters and col_key not in check_columns: 

709 # parameter is present for the column. use that. 

710 

711 _append_param_parameter( 

712 compiler, 

713 stmt, 

714 compile_state, 

715 c, 

716 col_key, 

717 parameters, 

718 _col_bind_name, 

719 implicit_returning, 

720 implicit_return_defaults, 

721 postfetch_lastrowid, 

722 values, 

723 autoincrement_col, 

724 insert_null_pk_still_autoincrements, 

725 kw, 

726 ) 

727 

728 # TODO - see TODO(return_defaults_columns) below 

729 # cols_in_params.add(c) 

730 

731 elif isinsert: 

732 # no parameter is present and it's an insert. 

733 

734 if c.primary_key and need_pks: 

735 # it's a primary key column, it will need to be generated by a 

736 # default generator of some kind, and the statement expects 

737 # inserted_primary_key to be available. 

738 

739 if implicit_returning: 

740 # we can use RETURNING, find out how to invoke this 

741 # column and get the value where RETURNING is an option. 

742 # we can inline server-side functions in this case. 

743 

744 _append_param_insert_pk_returning( 

745 compiler, stmt, c, values, kw 

746 ) 

747 else: 

748 # otherwise, find out how to invoke this column 

749 # and get its value where RETURNING is not an option. 

750 # if we have to invoke a server-side function, we need 

751 # to pre-execute it. or if this is a straight 

752 # autoincrement column and the dialect supports it 

753 # we can use cursor.lastrowid. 

754 

755 _append_param_insert_pk_no_returning( 

756 compiler, stmt, c, values, kw 

757 ) 

758 

759 elif c.default is not None: 

760 # column has a default, but it's not a pk column, or it is but 

761 # we don't need to get the pk back. 

762 if not c.default.is_sentinel or ( 

763 use_sentinel_columns is not None 

764 ): 

765 _append_param_insert_hasdefault( 

766 compiler, stmt, c, implicit_return_defaults, values, kw 

767 ) 

768 

769 elif c.server_default is not None: 

770 # column has a DDL-level default, and is either not a pk 

771 # column or we don't need the pk. 

772 if implicit_return_defaults and c in implicit_return_defaults: 

773 compiler_implicit_returning.append(c) 

774 elif not c.primary_key: 

775 compiler.postfetch.append(c) 

776 

777 elif implicit_return_defaults and c in implicit_return_defaults: 

778 compiler_implicit_returning.append(c) 

779 

780 elif ( 

781 c.primary_key 

782 and c is not stmt.table._autoincrement_column 

783 and not c.nullable 

784 ): 

785 _warn_pk_with_no_anticipated_value(c) 

786 

787 elif compile_state.isupdate: 

788 # no parameter is present and it's an insert. 

789 

790 _append_param_update( 

791 compiler, 

792 compile_state, 

793 stmt, 

794 c, 

795 implicit_return_defaults, 

796 values, 

797 kw, 

798 ) 

799 

800 # adding supplemental cols to implicit_returning in table 

801 # order so that order is maintained between multiple INSERT 

802 # statements which may have different parameters included, but all 

803 # have the same RETURNING clause 

804 if ( 

805 c in supplemental_returning 

806 and c not in compiler_implicit_returning 

807 ): 

808 compiler_implicit_returning.append(c) 

809 

810 if supplemental_returning: 

811 # we should have gotten every col into implicit_returning, 

812 # however supplemental returning can also have SQL functions etc. 

813 # in it 

814 remaining_supplemental = supplemental_returning.difference( 

815 compiler_implicit_returning 

816 ) 

817 compiler_implicit_returning.extend( 

818 c 

819 for c in stmt._supplemental_returning 

820 if c in remaining_supplemental 

821 ) 

822 

823 # TODO(return_defaults_columns): there can still be more columns in 

824 # _return_defaults_columns in the case that they are from something like an 

825 # aliased of the table. we can add them here, however this breaks other ORM 

826 # things. so this is for another day. see 

827 # test/orm/dml/test_update_delete_where.py -> test_update_from_alias 

828 

829 # if stmt._return_defaults_columns: 

830 # compiler_implicit_returning.extend( 

831 # set(stmt._return_defaults_columns) 

832 # .difference(compiler_implicit_returning) 

833 # .difference(cols_in_params) 

834 # ) 

835 

836 return (use_insertmanyvalues, use_sentinel_columns) 

837 

838 

839def _setup_delete_return_defaults( 

840 compiler, 

841 stmt, 

842 compile_state, 

843 parameters, 

844 _getattr_col_key, 

845 _column_as_key, 

846 _col_bind_name, 

847 check_columns, 

848 values, 

849 toplevel, 

850 kw, 

851): 

852 _, _, implicit_return_defaults, *_ = _get_returning_modifiers( 

853 compiler, stmt, compile_state, toplevel 

854 ) 

855 

856 if not implicit_return_defaults: 

857 return 

858 

859 if stmt._return_defaults_columns: 

860 compiler.implicit_returning.extend(implicit_return_defaults) 

861 

862 if stmt._supplemental_returning: 

863 ir_set = set(compiler.implicit_returning) 

864 compiler.implicit_returning.extend( 

865 c for c in stmt._supplemental_returning if c not in ir_set 

866 ) 

867 

868 

869def _append_param_parameter( 

870 compiler, 

871 stmt, 

872 compile_state, 

873 c, 

874 col_key, 

875 parameters, 

876 _col_bind_name, 

877 implicit_returning, 

878 implicit_return_defaults, 

879 postfetch_lastrowid, 

880 values, 

881 autoincrement_col, 

882 insert_null_pk_still_autoincrements, 

883 kw, 

884): 

885 value = parameters.pop(col_key) 

886 

887 has_visiting_cte = kw.get("visiting_cte") is not None 

888 col_value = compiler.preparer.format_column( 

889 c, use_table=compile_state.include_table_with_column_exprs 

890 ) 

891 

892 accumulated_bind_names: Set[str] = set() 

893 

894 if coercions._is_literal(value): 

895 if ( 

896 insert_null_pk_still_autoincrements 

897 and c.primary_key 

898 and c is autoincrement_col 

899 ): 

900 # support use case for #7998, fetch autoincrement cols 

901 # even if value was given. 

902 

903 if postfetch_lastrowid: 

904 compiler.postfetch_lastrowid = True 

905 elif implicit_returning: 

906 compiler.implicit_returning.append(c) 

907 

908 value = _create_bind_param( 

909 compiler, 

910 c, 

911 value, 

912 required=value is REQUIRED, 

913 name=( 

914 _col_bind_name(c) 

915 if not _compile_state_isinsert(compile_state) 

916 or not compile_state._has_multi_parameters 

917 else "%s_m0" % _col_bind_name(c) 

918 ), 

919 accumulate_bind_names=accumulated_bind_names, 

920 force_anonymous=has_visiting_cte, 

921 **kw, 

922 ) 

923 elif value._is_bind_parameter: 

924 if ( 

925 insert_null_pk_still_autoincrements 

926 and value.value is None 

927 and c.primary_key 

928 and c is autoincrement_col 

929 ): 

930 # support use case for #7998, fetch autoincrement cols 

931 # even if value was given 

932 if implicit_returning: 

933 compiler.implicit_returning.append(c) 

934 elif compiler.dialect.postfetch_lastrowid: 

935 compiler.postfetch_lastrowid = True 

936 

937 value = _handle_values_anonymous_param( 

938 compiler, 

939 c, 

940 value, 

941 name=( 

942 _col_bind_name(c) 

943 if not _compile_state_isinsert(compile_state) 

944 or not compile_state._has_multi_parameters 

945 else "%s_m0" % _col_bind_name(c) 

946 ), 

947 accumulate_bind_names=accumulated_bind_names, 

948 **kw, 

949 ) 

950 else: 

951 # value is a SQL expression 

952 value = compiler.process( 

953 value.self_group(), 

954 accumulate_bind_names=accumulated_bind_names, 

955 **kw, 

956 ) 

957 

958 if compile_state.isupdate: 

959 if implicit_return_defaults and c in implicit_return_defaults: 

960 compiler.implicit_returning.append(c) 

961 

962 else: 

963 compiler.postfetch.append(c) 

964 else: 

965 if c.primary_key: 

966 if implicit_returning: 

967 compiler.implicit_returning.append(c) 

968 elif compiler.dialect.postfetch_lastrowid: 

969 compiler.postfetch_lastrowid = True 

970 

971 elif implicit_return_defaults and (c in implicit_return_defaults): 

972 compiler.implicit_returning.append(c) 

973 

974 else: 

975 # postfetch specifically means, "we can SELECT the row we just 

976 # inserted by primary key to get back the server generated 

977 # defaults". so by definition this can't be used to get the 

978 # primary key value back, because we need to have it ahead of 

979 # time. 

980 

981 compiler.postfetch.append(c) 

982 

983 values.append((c, col_value, value, accumulated_bind_names)) 

984 

985 

986def _append_param_insert_pk_returning(compiler, stmt, c, values, kw): 

987 """Create a primary key expression in the INSERT statement where 

988 we want to populate result.inserted_primary_key and RETURNING 

989 is available. 

990 

991 """ 

992 if c.default is not None: 

993 if c.default.is_sequence: 

994 if compiler.dialect.supports_sequences and ( 

995 not c.default.optional 

996 or not compiler.dialect.sequences_optional 

997 ): 

998 accumulated_bind_names: Set[str] = set() 

999 values.append( 

1000 ( 

1001 c, 

1002 compiler.preparer.format_column(c), 

1003 compiler.process( 

1004 c.default, 

1005 accumulate_bind_names=accumulated_bind_names, 

1006 **kw, 

1007 ), 

1008 accumulated_bind_names, 

1009 ) 

1010 ) 

1011 compiler.implicit_returning.append(c) 

1012 elif c.default.is_clause_element: 

1013 accumulated_bind_names = set() 

1014 values.append( 

1015 ( 

1016 c, 

1017 compiler.preparer.format_column(c), 

1018 compiler.process( 

1019 c.default.arg.self_group(), 

1020 accumulate_bind_names=accumulated_bind_names, 

1021 **kw, 

1022 ), 

1023 accumulated_bind_names, 

1024 ) 

1025 ) 

1026 compiler.implicit_returning.append(c) 

1027 else: 

1028 # client side default. OK we can't use RETURNING, need to 

1029 # do a "prefetch", which in fact fetches the default value 

1030 # on the Python side 

1031 values.append( 

1032 ( 

1033 c, 

1034 compiler.preparer.format_column(c), 

1035 _create_insert_prefetch_bind_param(compiler, c, **kw), 

1036 (c.key,), 

1037 ) 

1038 ) 

1039 elif c is stmt.table._autoincrement_column or c.server_default is not None: 

1040 compiler.implicit_returning.append(c) 

1041 elif not c.nullable: 

1042 # no .default, no .server_default, not autoincrement, we have 

1043 # no indication this primary key column will have any value 

1044 _warn_pk_with_no_anticipated_value(c) 

1045 

1046 

1047def _append_param_insert_pk_no_returning(compiler, stmt, c, values, kw): 

1048 """Create a primary key expression in the INSERT statement where 

1049 we want to populate result.inserted_primary_key and we cannot use 

1050 RETURNING. 

1051 

1052 Depending on the kind of default here we may create a bound parameter 

1053 in the INSERT statement and pre-execute a default generation function, 

1054 or we may use cursor.lastrowid if supported by the dialect. 

1055 

1056 

1057 """ 

1058 

1059 if ( 

1060 # column has a Python-side default 

1061 c.default is not None 

1062 and ( 

1063 # and it either is not a sequence, or it is and we support 

1064 # sequences and want to invoke it 

1065 not c.default.is_sequence 

1066 or ( 

1067 compiler.dialect.supports_sequences 

1068 and ( 

1069 not c.default.optional 

1070 or not compiler.dialect.sequences_optional 

1071 ) 

1072 ) 

1073 ) 

1074 ) or ( 

1075 # column is the "autoincrement column" 

1076 c is stmt.table._autoincrement_column 

1077 and ( 

1078 # dialect can't use cursor.lastrowid 

1079 not compiler.dialect.postfetch_lastrowid 

1080 and ( 

1081 # column has a Sequence and we support those 

1082 ( 

1083 c.default is not None 

1084 and c.default.is_sequence 

1085 and compiler.dialect.supports_sequences 

1086 ) 

1087 or 

1088 # column has no default on it, but dialect can run the 

1089 # "autoincrement" mechanism explicitly, e.g. PostgreSQL 

1090 # SERIAL we know the sequence name 

1091 ( 

1092 c.default is None 

1093 and compiler.dialect.preexecute_autoincrement_sequences 

1094 ) 

1095 ) 

1096 ) 

1097 ): 

1098 # do a pre-execute of the default 

1099 values.append( 

1100 ( 

1101 c, 

1102 compiler.preparer.format_column(c), 

1103 _create_insert_prefetch_bind_param(compiler, c, **kw), 

1104 (c.key,), 

1105 ) 

1106 ) 

1107 elif ( 

1108 c.default is None 

1109 and c.server_default is None 

1110 and not c.nullable 

1111 and c is not stmt.table._autoincrement_column 

1112 ): 

1113 # no .default, no .server_default, not autoincrement, we have 

1114 # no indication this primary key column will have any value 

1115 _warn_pk_with_no_anticipated_value(c) 

1116 elif compiler.dialect.postfetch_lastrowid: 

1117 # finally, where it seems like there will be a generated primary key 

1118 # value and we haven't set up any other way to fetch it, and the 

1119 # dialect supports cursor.lastrowid, switch on the lastrowid flag so 

1120 # that the DefaultExecutionContext calls upon cursor.lastrowid 

1121 compiler.postfetch_lastrowid = True 

1122 

1123 

1124def _append_param_insert_hasdefault( 

1125 compiler, stmt, c, implicit_return_defaults, values, kw 

1126): 

1127 if c.default.is_sequence: 

1128 if compiler.dialect.supports_sequences and ( 

1129 not c.default.optional or not compiler.dialect.sequences_optional 

1130 ): 

1131 accumulated_bind_names: Set[str] = set() 

1132 values.append( 

1133 ( 

1134 c, 

1135 compiler.preparer.format_column(c), 

1136 compiler.process( 

1137 c.default, 

1138 accumulate_bind_names=accumulated_bind_names, 

1139 **kw, 

1140 ), 

1141 accumulated_bind_names, 

1142 ) 

1143 ) 

1144 if implicit_return_defaults and c in implicit_return_defaults: 

1145 compiler.implicit_returning.append(c) 

1146 elif not c.primary_key: 

1147 compiler.postfetch.append(c) 

1148 elif c.default.is_clause_element: 

1149 accumulated_bind_names = set() 

1150 values.append( 

1151 ( 

1152 c, 

1153 compiler.preparer.format_column(c), 

1154 compiler.process( 

1155 c.default.arg.self_group(), 

1156 accumulate_bind_names=accumulated_bind_names, 

1157 **kw, 

1158 ), 

1159 accumulated_bind_names, 

1160 ) 

1161 ) 

1162 

1163 if implicit_return_defaults and c in implicit_return_defaults: 

1164 compiler.implicit_returning.append(c) 

1165 elif not c.primary_key: 

1166 # don't add primary key column to postfetch 

1167 compiler.postfetch.append(c) 

1168 else: 

1169 values.append( 

1170 ( 

1171 c, 

1172 compiler.preparer.format_column(c), 

1173 _create_insert_prefetch_bind_param(compiler, c, **kw), 

1174 (c.key,), 

1175 ) 

1176 ) 

1177 

1178 

1179def _append_param_insert_select_hasdefault( 

1180 compiler: SQLCompiler, 

1181 stmt: ValuesBase, 

1182 c: ColumnClause[Any], 

1183 values: List[_CrudParamElementSQLExpr], 

1184 kw: Dict[str, Any], 

1185) -> None: 

1186 if default_is_sequence(c.default): 

1187 if compiler.dialect.supports_sequences and ( 

1188 not c.default.optional or not compiler.dialect.sequences_optional 

1189 ): 

1190 values.append( 

1191 ( 

1192 c, 

1193 compiler.preparer.format_column(c), 

1194 c.default.next_value(), 

1195 (), 

1196 ) 

1197 ) 

1198 elif default_is_clause_element(c.default): 

1199 values.append( 

1200 ( 

1201 c, 

1202 compiler.preparer.format_column(c), 

1203 c.default.arg.self_group(), 

1204 (), 

1205 ) 

1206 ) 

1207 else: 

1208 values.append( 

1209 ( 

1210 c, 

1211 compiler.preparer.format_column(c), 

1212 _create_insert_prefetch_bind_param( 

1213 compiler, c, process=False, **kw 

1214 ), 

1215 (c.key,), 

1216 ) 

1217 ) 

1218 

1219 

1220def _append_param_update( 

1221 compiler, compile_state, stmt, c, implicit_return_defaults, values, kw 

1222): 

1223 include_table = compile_state.include_table_with_column_exprs 

1224 if c.onupdate is not None and not c.onupdate.is_sequence: 

1225 if c.onupdate.is_clause_element: 

1226 values.append( 

1227 ( 

1228 c, 

1229 compiler.preparer.format_column( 

1230 c, 

1231 use_table=include_table, 

1232 ), 

1233 compiler.process(c.onupdate.arg.self_group(), **kw), 

1234 (), 

1235 ) 

1236 ) 

1237 if implicit_return_defaults and c in implicit_return_defaults: 

1238 compiler.implicit_returning.append(c) 

1239 else: 

1240 compiler.postfetch.append(c) 

1241 else: 

1242 values.append( 

1243 ( 

1244 c, 

1245 compiler.preparer.format_column( 

1246 c, 

1247 use_table=include_table, 

1248 ), 

1249 _create_update_prefetch_bind_param(compiler, c, **kw), 

1250 (c.key,), 

1251 ) 

1252 ) 

1253 elif c.server_onupdate is not None: 

1254 if implicit_return_defaults and c in implicit_return_defaults: 

1255 compiler.implicit_returning.append(c) 

1256 else: 

1257 compiler.postfetch.append(c) 

1258 elif ( 

1259 implicit_return_defaults 

1260 and (stmt._return_defaults_columns or not stmt._return_defaults) 

1261 and c in implicit_return_defaults 

1262 ): 

1263 compiler.implicit_returning.append(c) 

1264 

1265 

1266@overload 

1267def _create_insert_prefetch_bind_param( 

1268 compiler: SQLCompiler, 

1269 c: ColumnElement[Any], 

1270 process: Literal[True] = ..., 

1271 **kw: Any, 

1272) -> str: ... 

1273 

1274 

1275@overload 

1276def _create_insert_prefetch_bind_param( 

1277 compiler: SQLCompiler, 

1278 c: ColumnElement[Any], 

1279 process: Literal[False], 

1280 **kw: Any, 

1281) -> elements.BindParameter[Any]: ... 

1282 

1283 

1284def _create_insert_prefetch_bind_param( 

1285 compiler: SQLCompiler, 

1286 c: ColumnElement[Any], 

1287 process: bool = True, 

1288 name: Optional[str] = None, 

1289 **kw: Any, 

1290) -> Union[elements.BindParameter[Any], str]: 

1291 param = _create_bind_param( 

1292 compiler, c, None, process=process, name=name, **kw 

1293 ) 

1294 compiler.insert_prefetch.append(c) # type: ignore 

1295 return param 

1296 

1297 

1298@overload 

1299def _create_update_prefetch_bind_param( 

1300 compiler: SQLCompiler, 

1301 c: ColumnElement[Any], 

1302 process: Literal[True] = ..., 

1303 **kw: Any, 

1304) -> str: ... 

1305 

1306 

1307@overload 

1308def _create_update_prefetch_bind_param( 

1309 compiler: SQLCompiler, 

1310 c: ColumnElement[Any], 

1311 process: Literal[False], 

1312 **kw: Any, 

1313) -> elements.BindParameter[Any]: ... 

1314 

1315 

1316def _create_update_prefetch_bind_param( 

1317 compiler: SQLCompiler, 

1318 c: ColumnElement[Any], 

1319 process: bool = True, 

1320 name: Optional[str] = None, 

1321 **kw: Any, 

1322) -> Union[elements.BindParameter[Any], str]: 

1323 param = _create_bind_param( 

1324 compiler, c, None, process=process, name=name, **kw 

1325 ) 

1326 compiler.update_prefetch.append(c) # type: ignore 

1327 return param 

1328 

1329 

1330class _multiparam_column(elements.ColumnElement[Any]): 

1331 _is_multiparam_column = True 

1332 

1333 def __init__(self, original, index): 

1334 self.index = index 

1335 self.key = "%s_m%d" % (original.key, index + 1) 

1336 self.original = original 

1337 self.default = original.default 

1338 self.type = original.type 

1339 

1340 def compare(self, other, **kw): 

1341 raise NotImplementedError() 

1342 

1343 def _copy_internals(self, **kw): 

1344 raise NotImplementedError() 

1345 

1346 def __eq__(self, other): 

1347 return ( 

1348 isinstance(other, _multiparam_column) 

1349 and other.key == self.key 

1350 and other.original == self.original 

1351 ) 

1352 

1353 @util.memoized_property 

1354 def _default_description_tuple(self) -> _DefaultDescriptionTuple: 

1355 """used by default.py -> _process_execute_defaults()""" 

1356 

1357 return _DefaultDescriptionTuple._from_column_default(self.default) 

1358 

1359 @util.memoized_property 

1360 def _onupdate_description_tuple(self) -> _DefaultDescriptionTuple: 

1361 """used by default.py -> _process_execute_defaults()""" 

1362 

1363 return _DefaultDescriptionTuple._from_column_default(self.onupdate) 

1364 

1365 

1366def _process_multiparam_default_bind( 

1367 compiler: SQLCompiler, 

1368 stmt: ValuesBase, 

1369 c: KeyedColumnElement[Any], 

1370 index: int, 

1371 kw: Dict[str, Any], 

1372) -> str: 

1373 if not c.default: 

1374 raise exc.CompileError( 

1375 "INSERT value for column %s is explicitly rendered as a bound" 

1376 "parameter in the VALUES clause; " 

1377 "a Python-side value or SQL expression is required" % c 

1378 ) 

1379 elif default_is_clause_element(c.default): 

1380 return compiler.process(c.default.arg.self_group(), **kw) 

1381 elif c.default.is_sequence: 

1382 # these conditions would have been established 

1383 # by append_param_insert_(?:hasdefault|pk_returning|pk_no_returning) 

1384 # in order for us to be here, so these don't need to be 

1385 # checked 

1386 # assert compiler.dialect.supports_sequences and ( 

1387 # not c.default.optional 

1388 # or not compiler.dialect.sequences_optional 

1389 # ) 

1390 return compiler.process(c.default, **kw) 

1391 else: 

1392 col = _multiparam_column(c, index) 

1393 assert isinstance(stmt, dml.Insert) 

1394 return _create_insert_prefetch_bind_param( 

1395 compiler, col, process=True, **kw 

1396 ) 

1397 

1398 

1399def _get_update_multitable_params( 

1400 compiler, 

1401 stmt, 

1402 compile_state, 

1403 stmt_parameter_tuples, 

1404 check_columns, 

1405 _col_bind_name, 

1406 _getattr_col_key, 

1407 values, 

1408 kw, 

1409): 

1410 normalized_params = { 

1411 coercions.expect(roles.DMLColumnRole, c): param 

1412 for c, param in stmt_parameter_tuples or () 

1413 } 

1414 

1415 include_table = compile_state.include_table_with_column_exprs 

1416 

1417 affected_tables = set() 

1418 for t in compile_state._extra_froms: 

1419 # extra gymnastics to support the probably-shouldnt-have-supported 

1420 # case of "UPDATE table AS alias SET table.foo = bar", but it's 

1421 # supported 

1422 we_shouldnt_be_here_if_columns_found = ( 

1423 not include_table 

1424 and not compile_state.dml_table.is_derived_from(t) 

1425 ) 

1426 

1427 for c in t.c: 

1428 if c in normalized_params: 

1429 

1430 if we_shouldnt_be_here_if_columns_found: 

1431 raise exc.CompileError( 

1432 "Backend does not support additional tables " 

1433 "in the SET " 

1434 "clause; cannot include columns from table(s) " 

1435 f"'{t.description}' in " 

1436 "SET clause" 

1437 ) 

1438 

1439 affected_tables.add(t) 

1440 

1441 check_columns[_getattr_col_key(c)] = c 

1442 value = normalized_params[c] 

1443 

1444 col_value = compiler.process(c, include_table=include_table) 

1445 if coercions._is_literal(value): 

1446 value = _create_bind_param( 

1447 compiler, 

1448 c, 

1449 value, 

1450 required=value is REQUIRED, 

1451 name=_col_bind_name(c), 

1452 **kw, # TODO: no test coverage for literal binds here 

1453 ) 

1454 accumulated_bind_names: Iterable[str] = (c.key,) 

1455 elif value._is_bind_parameter: 

1456 cbn = _col_bind_name(c) 

1457 value = _handle_values_anonymous_param( 

1458 compiler, c, value, name=cbn, **kw 

1459 ) 

1460 accumulated_bind_names = (cbn,) 

1461 else: 

1462 compiler.postfetch.append(c) 

1463 value = compiler.process(value.self_group(), **kw) 

1464 accumulated_bind_names = () 

1465 values.append((c, col_value, value, accumulated_bind_names)) 

1466 

1467 # determine tables which are actually to be updated - process onupdate 

1468 # and server_onupdate for these 

1469 for t in affected_tables: 

1470 for c in t.c: 

1471 if c in normalized_params: 

1472 continue 

1473 elif c.onupdate is not None and not c.onupdate.is_sequence: 

1474 if c.onupdate.is_clause_element: 

1475 values.append( 

1476 ( 

1477 c, 

1478 compiler.process(c, include_table=include_table), 

1479 compiler.process( 

1480 c.onupdate.arg.self_group(), **kw 

1481 ), 

1482 (), 

1483 ) 

1484 ) 

1485 compiler.postfetch.append(c) 

1486 else: 

1487 values.append( 

1488 ( 

1489 c, 

1490 compiler.process(c, include_table=include_table), 

1491 _create_update_prefetch_bind_param( 

1492 compiler, c, name=_col_bind_name(c), **kw 

1493 ), 

1494 (c.key,), 

1495 ) 

1496 ) 

1497 elif c.server_onupdate is not None: 

1498 compiler.postfetch.append(c) 

1499 

1500 

1501def _extend_values_for_multiparams( 

1502 compiler: SQLCompiler, 

1503 stmt: ValuesBase, 

1504 compile_state: DMLState, 

1505 initial_values: Sequence[_CrudParamElementStr], 

1506 _column_as_key: Callable[..., str], 

1507 kw: Dict[str, Any], 

1508) -> List[Sequence[_CrudParamElementStr]]: 

1509 values_0 = initial_values 

1510 values = [initial_values] 

1511 

1512 has_visiting_cte = kw.get("visiting_cte") is not None 

1513 mp = compile_state._multi_parameters 

1514 assert mp is not None 

1515 for i, row in enumerate(mp[1:]): 

1516 extension: List[_CrudParamElementStr] = [] 

1517 

1518 row = {_column_as_key(key): v for key, v in row.items()} 

1519 

1520 for col, col_expr, param, accumulated_names in values_0: 

1521 if col.key in row: 

1522 key = col.key 

1523 

1524 if coercions._is_literal(row[key]): 

1525 new_param = _create_bind_param( 

1526 compiler, 

1527 col, 

1528 row[key], 

1529 name=("%s_m%d" % (col.key, i + 1)), 

1530 force_anonymous=has_visiting_cte, 

1531 **kw, 

1532 ) 

1533 else: 

1534 new_param = compiler.process(row[key].self_group(), **kw) 

1535 else: 

1536 new_param = _process_multiparam_default_bind( 

1537 compiler, stmt, col, i, kw 

1538 ) 

1539 

1540 extension.append((col, col_expr, new_param, accumulated_names)) 

1541 

1542 values.append(extension) 

1543 

1544 return values 

1545 

1546 

1547def _get_stmt_parameter_tuples_params( 

1548 compiler, 

1549 compile_state, 

1550 parameters, 

1551 stmt_parameter_tuples, 

1552 _column_as_key, 

1553 values, 

1554 kw, 

1555): 

1556 for k, v in stmt_parameter_tuples: 

1557 colkey = _column_as_key(k) 

1558 if colkey is not None: 

1559 parameters.setdefault(colkey, v) 

1560 else: 

1561 # a non-Column expression on the left side; 

1562 # add it to values() in an "as-is" state, 

1563 # coercing right side to bound param 

1564 

1565 # note one of the main use cases for this is array slice 

1566 # updates on PostgreSQL, as the left side is also an expression. 

1567 

1568 col_expr = compiler.process( 

1569 k, include_table=compile_state.include_table_with_column_exprs 

1570 ) 

1571 

1572 if coercions._is_literal(v): 

1573 v = compiler.process( 

1574 elements.BindParameter(None, v, type_=k.type), **kw 

1575 ) 

1576 else: 

1577 if v._is_bind_parameter and v.type._isnull: 

1578 # either unique parameter, or other bound parameters that 

1579 # were passed in directly 

1580 # set type to that of the column unconditionally 

1581 v = v._with_binary_element_type(k.type) 

1582 

1583 v = compiler.process(v.self_group(), **kw) 

1584 

1585 # TODO: not sure if accumulated_bind_names applies here 

1586 values.append((k, col_expr, v, ())) 

1587 

1588 

1589def _get_returning_modifiers(compiler, stmt, compile_state, toplevel): 

1590 """determines RETURNING strategy, if any, for the statement. 

1591 

1592 This is where it's determined what we need to fetch from the 

1593 INSERT or UPDATE statement after it's invoked. 

1594 

1595 """ 

1596 

1597 dialect = compiler.dialect 

1598 

1599 need_pks = ( 

1600 toplevel 

1601 and _compile_state_isinsert(compile_state) 

1602 and not stmt._inline 

1603 and ( 

1604 not compiler.for_executemany 

1605 or (dialect.insert_executemany_returning and stmt._return_defaults) 

1606 ) 

1607 and not stmt._returning 

1608 # and (not stmt._returning or stmt._return_defaults) 

1609 and not compile_state._has_multi_parameters 

1610 ) 

1611 

1612 # check if we have access to simple cursor.lastrowid. we can use that 

1613 # after the INSERT if that's all we need. 

1614 postfetch_lastrowid = ( 

1615 need_pks 

1616 and dialect.postfetch_lastrowid 

1617 and stmt.table._autoincrement_column is not None 

1618 ) 

1619 

1620 # see if we want to add RETURNING to an INSERT in order to get 

1621 # primary key columns back. This would be instead of postfetch_lastrowid 

1622 # if that's set. 

1623 implicit_returning = ( 

1624 # statement itself can veto it 

1625 need_pks 

1626 # the dialect can veto it if it just doesn't support RETURNING 

1627 # with INSERT 

1628 and dialect.insert_returning 

1629 # user-defined implicit_returning on Table can veto it 

1630 and compile_state._primary_table.implicit_returning 

1631 # the compile_state can veto it (SQlite uses this to disable 

1632 # RETURNING for an ON CONFLICT insert, as SQLite does not return 

1633 # for rows that were updated, which is wrong) 

1634 and compile_state._supports_implicit_returning 

1635 and ( 

1636 # since we support MariaDB and SQLite which also support lastrowid, 

1637 # decide if we should use lastrowid or RETURNING. for insert 

1638 # that didn't call return_defaults() and has just one set of 

1639 # parameters, we can use lastrowid. this is more "traditional" 

1640 # and a lot of weird use cases are supported by it. 

1641 # SQLite lastrowid times 3x faster than returning, 

1642 # Mariadb lastrowid 2x faster than returning 

1643 (not postfetch_lastrowid or dialect.favor_returning_over_lastrowid) 

1644 or compile_state._has_multi_parameters 

1645 or stmt._return_defaults 

1646 ) 

1647 ) 

1648 if implicit_returning: 

1649 postfetch_lastrowid = False 

1650 

1651 if _compile_state_isinsert(compile_state): 

1652 should_implicit_return_defaults = ( 

1653 implicit_returning and stmt._return_defaults 

1654 ) 

1655 explicit_returning = ( 

1656 should_implicit_return_defaults 

1657 or stmt._returning 

1658 or stmt._supplemental_returning 

1659 ) 

1660 use_insertmanyvalues = ( 

1661 toplevel 

1662 and compiler.for_executemany 

1663 and dialect.use_insertmanyvalues 

1664 and ( 

1665 explicit_returning 

1666 or ( 

1667 dialect.use_insertmanyvalues_wo_returning 

1668 # Disable insertmanyvalues_wo_returning when there's a 

1669 # post-values clause like ON CONFLICT DO UPDATE. 

1670 # This is a performance optimization flag and the batching 

1671 # doesn't work correctly with these clauses. See #13130. 

1672 and stmt._post_values_clause is None 

1673 ) 

1674 ) 

1675 ) 

1676 

1677 use_sentinel_columns = None 

1678 if ( 

1679 use_insertmanyvalues 

1680 and explicit_returning 

1681 and stmt._sort_by_parameter_order 

1682 ): 

1683 use_sentinel_columns = compiler._get_sentinel_column_for_table( 

1684 stmt.table 

1685 ) 

1686 

1687 elif compile_state.isupdate: 

1688 should_implicit_return_defaults = ( 

1689 stmt._return_defaults 

1690 and compile_state._primary_table.implicit_returning 

1691 and compile_state._supports_implicit_returning 

1692 and dialect.update_returning 

1693 ) 

1694 use_insertmanyvalues = False 

1695 use_sentinel_columns = None 

1696 elif compile_state.isdelete: 

1697 should_implicit_return_defaults = ( 

1698 stmt._return_defaults 

1699 and compile_state._primary_table.implicit_returning 

1700 and compile_state._supports_implicit_returning 

1701 and dialect.delete_returning 

1702 ) 

1703 use_insertmanyvalues = False 

1704 use_sentinel_columns = None 

1705 else: 

1706 should_implicit_return_defaults = False # pragma: no cover 

1707 use_insertmanyvalues = False 

1708 use_sentinel_columns = None 

1709 

1710 if should_implicit_return_defaults: 

1711 if not stmt._return_defaults_columns: 

1712 # TODO: this is weird. See #9685 where we have to 

1713 # take an extra step to prevent this from happening. why 

1714 # would this ever be *all* columns? but if we set to blank, then 

1715 # that seems to break things also in the ORM. So we should 

1716 # try to clean this up and figure out what return_defaults 

1717 # needs to do w/ the ORM etc. here 

1718 implicit_return_defaults = set(stmt.table.c) 

1719 else: 

1720 implicit_return_defaults = set(stmt._return_defaults_columns) 

1721 else: 

1722 implicit_return_defaults = None 

1723 

1724 return ( 

1725 need_pks, 

1726 implicit_returning or should_implicit_return_defaults, 

1727 implicit_return_defaults, 

1728 postfetch_lastrowid, 

1729 use_insertmanyvalues, 

1730 use_sentinel_columns, 

1731 ) 

1732 

1733 

1734def _warn_pk_with_no_anticipated_value(c): 

1735 msg = ( 

1736 "Column '%s.%s' is marked as a member of the " 

1737 "primary key for table '%s', " 

1738 "but has no Python-side or server-side default generator indicated, " 

1739 "nor does it indicate 'autoincrement=True' or 'nullable=True', " 

1740 "and no explicit value is passed. " 

1741 "Primary key columns typically may not store NULL." 

1742 % (c.table.fullname, c.name, c.table.fullname) 

1743 ) 

1744 if len(c.table.primary_key) > 1: 

1745 msg += ( 

1746 " Note that as of SQLAlchemy 1.1, 'autoincrement=True' must be " 

1747 "indicated explicitly for composite (e.g. multicolumn) primary " 

1748 "keys if AUTO_INCREMENT/SERIAL/IDENTITY " 

1749 "behavior is expected for one of the columns in the primary key. " 

1750 "CREATE TABLE statements are impacted by this change as well on " 

1751 "most backends." 

1752 ) 

1753 util.warn(msg)