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

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

515 statements  

1# sql/crud.py 

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

17import re 

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 DMLTargetCopy 

57 from .elements import KeyedColumnElement 

58 from .schema import _SQLExprDefault 

59 from .schema import Column 

60 

61REQUIRED = util.symbol( 

62 "REQUIRED", 

63 """ 

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

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

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

67 

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

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

70values present. 

71 

72""", 

73) 

74 

75 

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

77 if not isinstance(c, ColumnClause): 

78 raise exc.CompileError( 

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

80 ) 

81 return c 

82 

83 

84_CrudParamElement = Tuple[ 

85 "ColumnElement[Any]", 

86 str, # column name 

87 Optional[ 

88 Union[str, "_SQLExprDefault"] 

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

90 Iterable[str], 

91] 

92_CrudParamElementStr = Tuple[ 

93 "KeyedColumnElement[Any]", 

94 str, # column name 

95 str, # bound parameter string 

96 Iterable[str], 

97] 

98_CrudParamElementSQLExpr = Tuple[ 

99 "ColumnClause[Any]", 

100 str, 

101 "_SQLExprDefault", # SQL expression to apply 

102 Iterable[str], 

103] 

104 

105_CrudParamSequence = List[_CrudParamElement] 

106 

107 

108class _CrudParams(NamedTuple): 

109 single_params: _CrudParamSequence 

110 all_multi_params: List[Sequence[_CrudParamElementStr]] 

111 is_default_metavalue_only: bool = False 

112 use_insertmanyvalues: bool = False 

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

114 

115 

116def _get_crud_params( 

117 compiler: SQLCompiler, 

118 stmt: ValuesBase, 

119 compile_state: DMLState, 

120 toplevel: bool, 

121 **kw: Any, 

122) -> _CrudParams: 

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

124 in an INSERT or UPDATE statement. 

125 

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

127 returning column collections, used for default handling and ultimately 

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

129 collections. 

130 

131 """ 

132 

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

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

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

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

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

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

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

140 

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

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

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

144 

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

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

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

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

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

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

151 

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

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

154 # as well as here. 

155 

156 compiler.postfetch = [] 

157 compiler.insert_prefetch = [] 

158 compiler.update_prefetch = [] 

159 compiler.implicit_returning = [] 

160 

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

162 if visiting_cte is not None: 

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

164 # _crud_accumulate_bind_names collection; the INSERT we process here 

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

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

167 kw.pop("accumulate_bind_names", None) 

168 assert ( 

169 "accumulate_bind_names" not in kw 

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

171 

172 bindmarkers: MutableMapping[ColumnElement[Any], DMLTargetCopy[Any]] = {} 

173 kw["bindmarkers"] = bindmarkers 

174 

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

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

177 # .key must conditionally take tablename into account 

178 ( 

179 _column_as_key, 

180 _getattr_col_key, 

181 _col_bind_name, 

182 ) = _key_getters_for_crud_column(compiler, stmt, compile_state) 

183 

184 compiler._get_bind_name_for_col = _col_bind_name 

185 

186 if stmt._returning and stmt._return_defaults: 

187 raise exc.CompileError( 

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

189 "return_defaults() simultaneously" 

190 ) 

191 

192 if compile_state.isdelete: 

193 _setup_delete_return_defaults( 

194 compiler, 

195 stmt, 

196 compile_state, 

197 (), 

198 _getattr_col_key, 

199 _column_as_key, 

200 _col_bind_name, 

201 (), 

202 (), 

203 toplevel, 

204 kw, 

205 ) 

206 return _CrudParams([], []) 

207 

208 # no parameters in the statement, no parameters in the 

209 # compiled params - return binds for all columns 

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

211 return _CrudParams( 

212 [ 

213 ( 

214 c, 

215 compiler.preparer.format_column(c), 

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

217 (c.key,), 

218 ) 

219 for c in stmt.table.columns 

220 if not c._omit_from_statements 

221 ], 

222 [], 

223 ) 

224 

225 stmt_parameter_tuples: Optional[ 

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

227 ] 

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

229 

230 if ( 

231 _compile_state_isinsert(compile_state) 

232 and compile_state._has_multi_parameters 

233 ): 

234 mp = compile_state._multi_parameters 

235 assert mp is not None 

236 spd = mp[0] 

237 stmt_parameter_tuples = list(spd.items()) 

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_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 

336 if dml.isupdate(compile_state): 

337 tables_mentioned = set( 

338 c.table 

339 for c, v in stmt_parameter_tuples 

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

341 ).difference([compile_state.dml_table]) 

342 

343 multi_not_in_from = tables_mentioned.difference( 

344 compile_state._extra_froms 

345 ) 

346 

347 if tables_mentioned and ( 

348 not compile_state.is_multitable 

349 or not compiler.render_table_with_column_in_update_from 

350 ): 

351 if not compiler.render_table_with_column_in_update_from: 

352 preamble = ( 

353 "Backend does not support additional " 

354 "tables in the SET clause" 

355 ) 

356 else: 

357 preamble = ( 

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

359 ) 

360 

361 raise exc.CompileError( 

362 f"{preamble}; cannot " 

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

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

365 for t in tables_mentioned) 

366 } in SET clause""" 

367 ) 

368 

369 elif multi_not_in_from: 

370 assert compiler.render_table_with_column_in_update_from 

371 raise exc.CompileError( 

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

373 "table(s) " 

374 f"""{ 

375 ", ".join( 

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

377 t in multi_not_in_from) 

378 }""" 

379 ) 

380 

381 raise exc.CompileError( 

382 "Unconsumed column names: %s" 

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

384 ) 

385 

386 is_default_metavalue_only = False 

387 

388 if ( 

389 _compile_state_isinsert(compile_state) 

390 and compile_state._has_multi_parameters 

391 ): 

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

393 assert not stmt._select_names 

394 multi_extended_values = _extend_values_for_multiparams( 

395 compiler, 

396 stmt, 

397 compile_state, 

398 cast( 

399 "Sequence[_CrudParamElementStr]", 

400 values, 

401 ), 

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

403 kw, 

404 ) 

405 

406 if bindmarkers: 

407 _replace_bindmarkers( 

408 compiler, 

409 _column_as_key, 

410 bindmarkers, 

411 compile_state, 

412 values, 

413 kw, 

414 ) 

415 for m_v in multi_extended_values: 

416 _replace_bindmarkers( 

417 compiler, 

418 _column_as_key, 

419 bindmarkers, 

420 compile_state, 

421 m_v, 

422 kw, 

423 ) 

424 

425 return _CrudParams(values, multi_extended_values) 

426 elif ( 

427 not values 

428 and compiler.for_executemany 

429 and compiler.dialect.supports_default_metavalue 

430 ): 

431 # convert an "INSERT DEFAULT VALUES" 

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

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

434 # insert_executemany_returning mode :) 

435 values = [ 

436 ( 

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

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

439 compiler.dialect.default_metavalue_token, 

440 (), 

441 ) 

442 ] 

443 is_default_metavalue_only = True 

444 

445 if bindmarkers: 

446 _replace_bindmarkers( 

447 compiler, _column_as_key, bindmarkers, compile_state, values, kw 

448 ) 

449 return _CrudParams( 

450 values, 

451 [], 

452 is_default_metavalue_only=is_default_metavalue_only, 

453 use_insertmanyvalues=use_insertmanyvalues, 

454 use_sentinel_columns=use_sentinel_columns, 

455 ) 

456 

457 

458def _replace_bindmarkers( 

459 compiler, _column_as_key, bindmarkers, compile_state, values, kw 

460): 

461 _expr_by_col_key = { 

462 _column_as_key(col): compiled_str for col, _, compiled_str, _ in values 

463 } 

464 

465 def replace_marker(m): 

466 try: 

467 return _expr_by_col_key[m.group(1)] 

468 except KeyError as ke: 

469 if dml.isupdate(compile_state): 

470 return compiler.process(bindmarkers[m.group(1)].column, **kw) 

471 else: 

472 raise exc.CompileError( 

473 f"Can't resolve referenced column name in " 

474 f"INSERT statement: {m.group(1)!r}" 

475 ) from ke 

476 

477 values[:] = [ 

478 ( 

479 col, 

480 col_value, 

481 re.sub( 

482 r"__BINDMARKER_~~(.+?)~~", 

483 replace_marker, 

484 compiled_str, 

485 ), 

486 accumulated_bind_names, 

487 ) 

488 for ( 

489 col, 

490 col_value, 

491 compiled_str, 

492 accumulated_bind_names, 

493 ) in values 

494 ] 

495 

496 

497@overload 

498def _create_bind_param( 

499 compiler: SQLCompiler, 

500 col: ColumnElement[Any], 

501 value: Any, 

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

503 required: bool = False, 

504 name: Optional[str] = None, 

505 force_anonymous: bool = False, 

506 **kw: Any, 

507) -> str: ... 

508 

509 

510@overload 

511def _create_bind_param( 

512 compiler: SQLCompiler, 

513 col: ColumnElement[Any], 

514 value: Any, 

515 **kw: Any, 

516) -> str: ... 

517 

518 

519def _create_bind_param( 

520 compiler: SQLCompiler, 

521 col: ColumnElement[Any], 

522 value: Any, 

523 process: bool = True, 

524 required: bool = False, 

525 name: Optional[str] = None, 

526 force_anonymous: bool = False, 

527 **kw: Any, 

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

529 if force_anonymous: 

530 name = None 

531 elif name is None: 

532 name = col.key 

533 

534 bindparam = elements.BindParameter( 

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

536 ) 

537 bindparam._is_crud = True 

538 if process: 

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

540 else: 

541 return bindparam 

542 

543 

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

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

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

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

548 # produce bound parameters in deterministic order without invoking any 

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

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

551 # right now). 

552 # 

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

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

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

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

557 # rather than having 

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

559 # name. Saves on call counts also. 

560 

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

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

563 # multiple insert/update are combined together using CTEs 

564 is_cte = "visiting_cte" in kw 

565 

566 if ( 

567 not is_cte 

568 and value.unique 

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

570 ): 

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

572 

573 if value.type._isnull: 

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

575 # passed in directly 

576 # set type to that of the column unconditionally 

577 value = value._with_binary_element_type(col.type) 

578 

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

580 

581 

582def _key_getters_for_crud_column( 

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

584) -> Tuple[ 

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

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

587 _BindNameForColProtocol, 

588]: 

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

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

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

592 # dictionaries and when rendering bind param names. 

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

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

595 # statement. 

596 _et = set(compile_state._extra_froms) 

597 

598 c_key_role = functools.partial( 

599 coercions.expect_as_key, roles.DMLColumnRole 

600 ) 

601 

602 def _column_as_key( 

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

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

605 str_key = c_key_role(key) 

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

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

608 else: 

609 return str_key 

610 

611 def _getattr_col_key( 

612 col: ColumnClause[Any], 

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

614 if col.table in _et: 

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

616 else: 

617 return col.key 

618 

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

620 if col.table in _et: 

621 if TYPE_CHECKING: 

622 assert isinstance(col.table, TableClause) 

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

624 else: 

625 return col.key 

626 

627 else: 

628 _column_as_key = functools.partial( 

629 coercions.expect_as_key, roles.DMLColumnRole 

630 ) 

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

632 

633 return _column_as_key, _getattr_col_key, _col_bind_name 

634 

635 

636def _scan_insert_from_select_cols( 

637 compiler, 

638 stmt, 

639 compile_state, 

640 parameters, 

641 _getattr_col_key, 

642 _column_as_key, 

643 _col_bind_name, 

644 check_columns, 

645 values, 

646 toplevel, 

647 kw, 

648): 

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

650 

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

652 

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

654 

655 add_select_cols: List[_CrudParamElementSQLExpr] = [] 

656 if stmt.include_insert_from_select_defaults: 

657 col_set = set(cols) 

658 for col in stmt.table.columns: 

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

660 # this will omit columns marked as omit_from_statements naturally, 

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

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

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

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

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

666 # here so we again omit it. 

667 if ( 

668 col not in col_set 

669 and col.default 

670 and not col.default.is_sentinel 

671 ): 

672 cols.append(col) 

673 

674 for c in cols: 

675 col_key = _getattr_col_key(c) 

676 if col_key in parameters and col_key not in check_columns: 

677 parameters.pop(col_key) 

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

679 else: 

680 _append_param_insert_select_hasdefault( 

681 compiler, stmt, c, add_select_cols, kw 

682 ) 

683 

684 if add_select_cols: 

685 values.extend(add_select_cols) 

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

687 if not isinstance(ins_from_select, Select): 

688 raise exc.CompileError( 

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

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

691 f"""{ 

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

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

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

695 "columns." 

696 ) 

697 ins_from_select = ins_from_select._generate() 

698 # copy raw_columns 

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

700 expr for _, _, expr, _ in add_select_cols 

701 ] 

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

703 

704 

705def _scan_cols( 

706 compiler, 

707 stmt, 

708 compile_state, 

709 parameters, 

710 _getattr_col_key, 

711 _column_as_key, 

712 _col_bind_name, 

713 check_columns, 

714 values, 

715 toplevel, 

716 kw, 

717): 

718 ( 

719 need_pks, 

720 implicit_returning, 

721 implicit_return_defaults, 

722 postfetch_lastrowid, 

723 use_insertmanyvalues, 

724 use_sentinel_columns, 

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

726 

727 assert compile_state.isupdate or compile_state.isinsert 

728 

729 if compile_state._maintain_values_ordering: 

730 parameter_ordering = [ 

731 _column_as_key(key) for key in compile_state._dict_parameters 

732 ] 

733 ordered_keys = set(parameter_ordering) 

734 cols = [ 

735 stmt.table.c[key] 

736 for key in parameter_ordering 

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

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

739 

740 else: 

741 cols = stmt.table.columns 

742 

743 isinsert = _compile_state_isinsert(compile_state) 

744 if isinsert and not compile_state._has_multi_parameters: 

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

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

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

748 autoincrement_col = stmt.table._autoincrement_column 

749 insert_null_pk_still_autoincrements = ( 

750 compiler.dialect.insert_null_pk_still_autoincrements 

751 ) 

752 else: 

753 autoincrement_col = insert_null_pk_still_autoincrements = None 

754 

755 if stmt._supplemental_returning: 

756 supplemental_returning = set(stmt._supplemental_returning) 

757 else: 

758 supplemental_returning = set() 

759 

760 compiler_implicit_returning = compiler.implicit_returning 

761 

762 # TODO - see TODO(return_defaults_columns) below 

763 # cols_in_params = set() 

764 

765 for c in cols: 

766 # scan through every column in the target table 

767 

768 col_key = _getattr_col_key(c) 

769 

770 if col_key in parameters and col_key not in check_columns: 

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

772 

773 _append_param_parameter( 

774 compiler, 

775 stmt, 

776 compile_state, 

777 c, 

778 col_key, 

779 parameters, 

780 _col_bind_name, 

781 implicit_returning, 

782 implicit_return_defaults, 

783 postfetch_lastrowid, 

784 values, 

785 autoincrement_col, 

786 insert_null_pk_still_autoincrements, 

787 kw, 

788 ) 

789 

790 # TODO - see TODO(return_defaults_columns) below 

791 # cols_in_params.add(c) 

792 

793 elif isinsert: 

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

795 

796 if c.primary_key and need_pks: 

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

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

799 # inserted_primary_key to be available. 

800 

801 if implicit_returning: 

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

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

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

805 

806 _append_param_insert_pk_returning( 

807 compiler, stmt, c, values, kw 

808 ) 

809 else: 

810 # otherwise, find out how to invoke this column 

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

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

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

814 # autoincrement column and the dialect supports it 

815 # we can use cursor.lastrowid. 

816 

817 _append_param_insert_pk_no_returning( 

818 compiler, stmt, c, values, kw 

819 ) 

820 

821 elif c.default is not None: 

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

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

824 if not c.default.is_sentinel or ( 

825 use_sentinel_columns is not None 

826 ): 

827 _append_param_insert_hasdefault( 

828 compiler, stmt, c, implicit_return_defaults, values, kw 

829 ) 

830 

831 elif c.server_default is not None: 

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

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

834 if implicit_return_defaults and c in implicit_return_defaults: 

835 compiler_implicit_returning.append(c) 

836 elif not c.primary_key: 

837 compiler.postfetch.append(c) 

838 

839 elif implicit_return_defaults and c in implicit_return_defaults: 

840 compiler_implicit_returning.append(c) 

841 

842 elif ( 

843 c.primary_key 

844 and c is not stmt.table._autoincrement_column 

845 and not c.nullable 

846 ): 

847 _warn_pk_with_no_anticipated_value(c) 

848 

849 elif compile_state.isupdate: 

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

851 

852 _append_param_update( 

853 compiler, 

854 compile_state, 

855 stmt, 

856 c, 

857 implicit_return_defaults, 

858 values, 

859 kw, 

860 ) 

861 

862 # adding supplemental cols to implicit_returning in table 

863 # order so that order is maintained between multiple INSERT 

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

865 # have the same RETURNING clause 

866 if ( 

867 c in supplemental_returning 

868 and c not in compiler_implicit_returning 

869 ): 

870 compiler_implicit_returning.append(c) 

871 

872 if supplemental_returning: 

873 # we should have gotten every col into implicit_returning, 

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

875 # in it 

876 remaining_supplemental = supplemental_returning.difference( 

877 compiler_implicit_returning 

878 ) 

879 compiler_implicit_returning.extend( 

880 c 

881 for c in stmt._supplemental_returning 

882 if c in remaining_supplemental 

883 ) 

884 

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

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

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

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

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

890 

891 # if stmt._return_defaults_columns: 

892 # compiler_implicit_returning.extend( 

893 # set(stmt._return_defaults_columns) 

894 # .difference(compiler_implicit_returning) 

895 # .difference(cols_in_params) 

896 # ) 

897 

898 return (use_insertmanyvalues, use_sentinel_columns) 

899 

900 

901def _setup_delete_return_defaults( 

902 compiler, 

903 stmt, 

904 compile_state, 

905 parameters, 

906 _getattr_col_key, 

907 _column_as_key, 

908 _col_bind_name, 

909 check_columns, 

910 values, 

911 toplevel, 

912 kw, 

913): 

914 (_, _, implicit_return_defaults, *_) = _get_returning_modifiers( 

915 compiler, stmt, compile_state, toplevel 

916 ) 

917 

918 if not implicit_return_defaults: 

919 return 

920 

921 if stmt._return_defaults_columns: 

922 compiler.implicit_returning.extend(implicit_return_defaults) 

923 

924 if stmt._supplemental_returning: 

925 ir_set = set(compiler.implicit_returning) 

926 compiler.implicit_returning.extend( 

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

928 ) 

929 

930 

931def _append_param_parameter( 

932 compiler, 

933 stmt, 

934 compile_state, 

935 c, 

936 col_key, 

937 parameters, 

938 _col_bind_name, 

939 implicit_returning, 

940 implicit_return_defaults, 

941 postfetch_lastrowid, 

942 values, 

943 autoincrement_col, 

944 insert_null_pk_still_autoincrements, 

945 kw, 

946): 

947 value = parameters.pop(col_key) 

948 

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

950 col_value = compiler.preparer.format_column( 

951 c, use_table=compile_state.include_table_with_column_exprs 

952 ) 

953 

954 accumulated_bind_names: Set[str] = set() 

955 

956 if coercions._is_literal(value): 

957 if ( 

958 insert_null_pk_still_autoincrements 

959 and c.primary_key 

960 and c is autoincrement_col 

961 ): 

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

963 # even if value was given. 

964 

965 if postfetch_lastrowid: 

966 compiler.postfetch_lastrowid = True 

967 elif implicit_returning: 

968 compiler.implicit_returning.append(c) 

969 

970 value = _create_bind_param( 

971 compiler, 

972 c, 

973 value, 

974 required=value is REQUIRED, 

975 name=( 

976 _col_bind_name(c) 

977 if not _compile_state_isinsert(compile_state) 

978 or not compile_state._has_multi_parameters 

979 else "%s_m0" % _col_bind_name(c) 

980 ), 

981 accumulate_bind_names=accumulated_bind_names, 

982 force_anonymous=has_visiting_cte, 

983 **kw, 

984 ) 

985 elif value._is_bind_parameter: 

986 if ( 

987 insert_null_pk_still_autoincrements 

988 and value.value is None 

989 and c.primary_key 

990 and c is autoincrement_col 

991 ): 

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

993 # even if value was given 

994 if implicit_returning: 

995 compiler.implicit_returning.append(c) 

996 elif compiler.dialect.postfetch_lastrowid: 

997 compiler.postfetch_lastrowid = True 

998 

999 value = _handle_values_anonymous_param( 

1000 compiler, 

1001 c, 

1002 value, 

1003 name=( 

1004 _col_bind_name(c) 

1005 if not _compile_state_isinsert(compile_state) 

1006 or not compile_state._has_multi_parameters 

1007 else "%s_m0" % _col_bind_name(c) 

1008 ), 

1009 accumulate_bind_names=accumulated_bind_names, 

1010 **kw, 

1011 ) 

1012 else: 

1013 # value is a SQL expression 

1014 value = compiler.process( 

1015 value.self_group(), 

1016 accumulate_bind_names=accumulated_bind_names, 

1017 **kw, 

1018 ) 

1019 

1020 if compile_state.isupdate: 

1021 if implicit_return_defaults and c in implicit_return_defaults: 

1022 compiler.implicit_returning.append(c) 

1023 

1024 else: 

1025 compiler.postfetch.append(c) 

1026 else: 

1027 if c.primary_key: 

1028 if implicit_returning: 

1029 compiler.implicit_returning.append(c) 

1030 elif compiler.dialect.postfetch_lastrowid: 

1031 compiler.postfetch_lastrowid = True 

1032 

1033 elif implicit_return_defaults and (c in implicit_return_defaults): 

1034 compiler.implicit_returning.append(c) 

1035 

1036 else: 

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

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

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

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

1041 # time. 

1042 

1043 compiler.postfetch.append(c) 

1044 

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

1046 

1047 

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

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

1050 we want to populate result.inserted_primary_key and RETURNING 

1051 is available. 

1052 

1053 """ 

1054 if c.default is not None: 

1055 if c.default.is_sequence: 

1056 if compiler.dialect.supports_sequences and ( 

1057 not c.default.optional 

1058 or not compiler.dialect.sequences_optional 

1059 ): 

1060 accumulated_bind_names: Set[str] = set() 

1061 values.append( 

1062 ( 

1063 c, 

1064 compiler.preparer.format_column(c), 

1065 compiler.process( 

1066 c.default, 

1067 accumulate_bind_names=accumulated_bind_names, 

1068 **kw, 

1069 ), 

1070 accumulated_bind_names, 

1071 ) 

1072 ) 

1073 compiler.implicit_returning.append(c) 

1074 elif c.default.is_clause_element: 

1075 accumulated_bind_names = set() 

1076 values.append( 

1077 ( 

1078 c, 

1079 compiler.preparer.format_column(c), 

1080 compiler.process( 

1081 c.default.arg.self_group(), 

1082 accumulate_bind_names=accumulated_bind_names, 

1083 **kw, 

1084 ), 

1085 accumulated_bind_names, 

1086 ) 

1087 ) 

1088 compiler.implicit_returning.append(c) 

1089 else: 

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

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

1092 # on the Python side 

1093 values.append( 

1094 ( 

1095 c, 

1096 compiler.preparer.format_column(c), 

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

1098 (c.key,), 

1099 ) 

1100 ) 

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

1102 compiler.implicit_returning.append(c) 

1103 elif not c.nullable: 

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

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

1106 _warn_pk_with_no_anticipated_value(c) 

1107 

1108 

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

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

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

1112 RETURNING. 

1113 

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

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

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

1117 

1118 

1119 """ 

1120 

1121 if ( 

1122 # column has a Python-side default 

1123 c.default is not None 

1124 and ( 

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

1126 # sequences and want to invoke it 

1127 not c.default.is_sequence 

1128 or ( 

1129 compiler.dialect.supports_sequences 

1130 and ( 

1131 not c.default.optional 

1132 or not compiler.dialect.sequences_optional 

1133 ) 

1134 ) 

1135 ) 

1136 ) or ( 

1137 # column is the "autoincrement column" 

1138 c is stmt.table._autoincrement_column 

1139 and ( 

1140 # dialect can't use cursor.lastrowid 

1141 not compiler.dialect.postfetch_lastrowid 

1142 and ( 

1143 # column has a Sequence and we support those 

1144 ( 

1145 c.default is not None 

1146 and c.default.is_sequence 

1147 and compiler.dialect.supports_sequences 

1148 ) 

1149 or 

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

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

1152 # SERIAL we know the sequence name 

1153 ( 

1154 c.default is None 

1155 and compiler.dialect.preexecute_autoincrement_sequences 

1156 ) 

1157 ) 

1158 ) 

1159 ): 

1160 # do a pre-execute of the default 

1161 values.append( 

1162 ( 

1163 c, 

1164 compiler.preparer.format_column(c), 

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

1166 (c.key,), 

1167 ) 

1168 ) 

1169 elif ( 

1170 c.default is None 

1171 and c.server_default is None 

1172 and not c.nullable 

1173 and c is not stmt.table._autoincrement_column 

1174 ): 

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

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

1177 _warn_pk_with_no_anticipated_value(c) 

1178 elif compiler.dialect.postfetch_lastrowid: 

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

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

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

1182 # that the DefaultExecutionContext calls upon cursor.lastrowid 

1183 compiler.postfetch_lastrowid = True 

1184 

1185 

1186def _append_param_insert_hasdefault( 

1187 compiler, stmt, c, implicit_return_defaults, values, kw 

1188): 

1189 if c.default.is_sequence: 

1190 if compiler.dialect.supports_sequences and ( 

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

1192 ): 

1193 accumulated_bind_names: Set[str] = set() 

1194 values.append( 

1195 ( 

1196 c, 

1197 compiler.preparer.format_column(c), 

1198 compiler.process( 

1199 c.default, 

1200 accumulate_bind_names=accumulated_bind_names, 

1201 **kw, 

1202 ), 

1203 accumulated_bind_names, 

1204 ) 

1205 ) 

1206 if implicit_return_defaults and c in implicit_return_defaults: 

1207 compiler.implicit_returning.append(c) 

1208 elif not c.primary_key: 

1209 compiler.postfetch.append(c) 

1210 elif c.default.is_clause_element: 

1211 accumulated_bind_names = set() 

1212 values.append( 

1213 ( 

1214 c, 

1215 compiler.preparer.format_column(c), 

1216 compiler.process( 

1217 c.default.arg.self_group(), 

1218 accumulate_bind_names=accumulated_bind_names, 

1219 **kw, 

1220 ), 

1221 accumulated_bind_names, 

1222 ) 

1223 ) 

1224 

1225 if implicit_return_defaults and c in implicit_return_defaults: 

1226 compiler.implicit_returning.append(c) 

1227 elif not c.primary_key: 

1228 # don't add primary key column to postfetch 

1229 compiler.postfetch.append(c) 

1230 else: 

1231 values.append( 

1232 ( 

1233 c, 

1234 compiler.preparer.format_column(c), 

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

1236 (c.key,), 

1237 ) 

1238 ) 

1239 

1240 

1241def _append_param_insert_select_hasdefault( 

1242 compiler: SQLCompiler, 

1243 stmt: ValuesBase, 

1244 c: ColumnClause[Any], 

1245 values: List[_CrudParamElementSQLExpr], 

1246 kw: Dict[str, Any], 

1247) -> None: 

1248 if default_is_sequence(c.default): 

1249 if compiler.dialect.supports_sequences and ( 

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

1251 ): 

1252 values.append( 

1253 ( 

1254 c, 

1255 compiler.preparer.format_column(c), 

1256 c.default.next_value(), 

1257 (), 

1258 ) 

1259 ) 

1260 elif default_is_clause_element(c.default): 

1261 values.append( 

1262 ( 

1263 c, 

1264 compiler.preparer.format_column(c), 

1265 c.default.arg.self_group(), 

1266 (), 

1267 ) 

1268 ) 

1269 else: 

1270 values.append( 

1271 ( 

1272 c, 

1273 compiler.preparer.format_column(c), 

1274 _create_insert_prefetch_bind_param( 

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

1276 ), 

1277 (c.key,), 

1278 ) 

1279 ) 

1280 

1281 

1282def _append_param_update( 

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

1284): 

1285 include_table = compile_state.include_table_with_column_exprs 

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

1287 if c.onupdate.is_clause_element: 

1288 values.append( 

1289 ( 

1290 c, 

1291 compiler.preparer.format_column( 

1292 c, 

1293 use_table=include_table, 

1294 ), 

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

1296 (), 

1297 ) 

1298 ) 

1299 if implicit_return_defaults and c in implicit_return_defaults: 

1300 compiler.implicit_returning.append(c) 

1301 else: 

1302 compiler.postfetch.append(c) 

1303 else: 

1304 values.append( 

1305 ( 

1306 c, 

1307 compiler.preparer.format_column( 

1308 c, 

1309 use_table=include_table, 

1310 ), 

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

1312 (c.key,), 

1313 ) 

1314 ) 

1315 elif c.server_onupdate is not None: 

1316 if implicit_return_defaults and c in implicit_return_defaults: 

1317 compiler.implicit_returning.append(c) 

1318 else: 

1319 compiler.postfetch.append(c) 

1320 elif ( 

1321 implicit_return_defaults 

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

1323 and c in implicit_return_defaults 

1324 ): 

1325 compiler.implicit_returning.append(c) 

1326 

1327 

1328@overload 

1329def _create_insert_prefetch_bind_param( 

1330 compiler: SQLCompiler, 

1331 c: ColumnElement[Any], 

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

1333 **kw: Any, 

1334) -> str: ... 

1335 

1336 

1337@overload 

1338def _create_insert_prefetch_bind_param( 

1339 compiler: SQLCompiler, 

1340 c: ColumnElement[Any], 

1341 process: Literal[False], 

1342 **kw: Any, 

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

1344 

1345 

1346def _create_insert_prefetch_bind_param( 

1347 compiler: SQLCompiler, 

1348 c: ColumnElement[Any], 

1349 process: bool = True, 

1350 name: Optional[str] = None, 

1351 **kw: Any, 

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

1353 param = _create_bind_param( 

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

1355 ) 

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

1357 return param 

1358 

1359 

1360@overload 

1361def _create_update_prefetch_bind_param( 

1362 compiler: SQLCompiler, 

1363 c: ColumnElement[Any], 

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

1365 **kw: Any, 

1366) -> str: ... 

1367 

1368 

1369@overload 

1370def _create_update_prefetch_bind_param( 

1371 compiler: SQLCompiler, 

1372 c: ColumnElement[Any], 

1373 process: Literal[False], 

1374 **kw: Any, 

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

1376 

1377 

1378def _create_update_prefetch_bind_param( 

1379 compiler: SQLCompiler, 

1380 c: ColumnElement[Any], 

1381 process: bool = True, 

1382 name: Optional[str] = None, 

1383 **kw: Any, 

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

1385 param = _create_bind_param( 

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

1387 ) 

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

1389 return param 

1390 

1391 

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

1393 _is_multiparam_column = True 

1394 

1395 def __init__(self, original, index): 

1396 self.index = index 

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

1398 self.original = original 

1399 self.default = original.default 

1400 self.type = original.type 

1401 

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

1403 raise NotImplementedError() 

1404 

1405 def _copy_internals(self, **kw): 

1406 raise NotImplementedError() 

1407 

1408 def __eq__(self, other): 

1409 return ( 

1410 isinstance(other, _multiparam_column) 

1411 and other.key == self.key 

1412 and other.original == self.original 

1413 ) 

1414 

1415 @util.memoized_property 

1416 def _default_description_tuple(self) -> _DefaultDescriptionTuple: 

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

1418 

1419 return _DefaultDescriptionTuple._from_column_default(self.default) 

1420 

1421 @util.memoized_property 

1422 def _onupdate_description_tuple(self) -> _DefaultDescriptionTuple: 

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

1424 

1425 return _DefaultDescriptionTuple._from_column_default(self.onupdate) 

1426 

1427 

1428def _process_multiparam_default_bind( 

1429 compiler: SQLCompiler, 

1430 stmt: ValuesBase, 

1431 c: KeyedColumnElement[Any], 

1432 index: int, 

1433 kw: Dict[str, Any], 

1434) -> str: 

1435 if not c.default: 

1436 raise exc.CompileError( 

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

1438 "parameter in the VALUES clause; " 

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

1440 ) 

1441 elif default_is_clause_element(c.default): 

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

1443 elif c.default.is_sequence: 

1444 # these conditions would have been established 

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

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

1447 # checked 

1448 # assert compiler.dialect.supports_sequences and ( 

1449 # not c.default.optional 

1450 # or not compiler.dialect.sequences_optional 

1451 # ) 

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

1453 else: 

1454 col = _multiparam_column(c, index) 

1455 assert isinstance(stmt, dml.Insert) 

1456 return _create_insert_prefetch_bind_param( 

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

1458 ) 

1459 

1460 

1461def _get_update_multitable_params( 

1462 compiler, 

1463 stmt, 

1464 compile_state, 

1465 stmt_parameter_tuples, 

1466 check_columns, 

1467 _col_bind_name, 

1468 _getattr_col_key, 

1469 values, 

1470 kw, 

1471): 

1472 normalized_params = { 

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

1474 for c, param in stmt_parameter_tuples or () 

1475 } 

1476 

1477 include_table = compile_state.include_table_with_column_exprs 

1478 

1479 affected_tables = set() 

1480 for t in compile_state._extra_froms: 

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

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

1483 # supported 

1484 we_shouldnt_be_here_if_columns_found = ( 

1485 not include_table 

1486 and not compile_state.dml_table.is_derived_from(t) 

1487 ) 

1488 

1489 for c in t.c: 

1490 if c in normalized_params: 

1491 

1492 if we_shouldnt_be_here_if_columns_found: 

1493 raise exc.CompileError( 

1494 "Backend does not support additional tables " 

1495 "in the SET " 

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

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

1498 "SET clause" 

1499 ) 

1500 

1501 affected_tables.add(t) 

1502 

1503 check_columns[_getattr_col_key(c)] = c 

1504 value = normalized_params[c] 

1505 

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

1507 if coercions._is_literal(value): 

1508 value = _create_bind_param( 

1509 compiler, 

1510 c, 

1511 value, 

1512 required=value is REQUIRED, 

1513 name=_col_bind_name(c), 

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

1515 ) 

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

1517 elif value._is_bind_parameter: 

1518 cbn = _col_bind_name(c) 

1519 value = _handle_values_anonymous_param( 

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

1521 ) 

1522 accumulated_bind_names = (cbn,) 

1523 else: 

1524 compiler.postfetch.append(c) 

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

1526 accumulated_bind_names = () 

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

1528 

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

1530 # and server_onupdate for these 

1531 for t in affected_tables: 

1532 for c in t.c: 

1533 if c in normalized_params: 

1534 continue 

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

1536 if c.onupdate.is_clause_element: 

1537 values.append( 

1538 ( 

1539 c, 

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

1541 compiler.process( 

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

1543 ), 

1544 (), 

1545 ) 

1546 ) 

1547 compiler.postfetch.append(c) 

1548 else: 

1549 values.append( 

1550 ( 

1551 c, 

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

1553 _create_update_prefetch_bind_param( 

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

1555 ), 

1556 (c.key,), 

1557 ) 

1558 ) 

1559 elif c.server_onupdate is not None: 

1560 compiler.postfetch.append(c) 

1561 

1562 

1563def _extend_values_for_multiparams( 

1564 compiler: SQLCompiler, 

1565 stmt: ValuesBase, 

1566 compile_state: DMLState, 

1567 initial_values: Sequence[_CrudParamElementStr], 

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

1569 kw: Dict[str, Any], 

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

1571 values_0 = initial_values 

1572 values = [initial_values] 

1573 

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

1575 mp = compile_state._multi_parameters 

1576 assert mp is not None 

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

1578 extension: List[_CrudParamElementStr] = [] 

1579 

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

1581 

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

1583 if col.key in row: 

1584 key = col.key 

1585 

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

1587 new_param = _create_bind_param( 

1588 compiler, 

1589 col, 

1590 row[key], 

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

1592 force_anonymous=has_visiting_cte, 

1593 **kw, 

1594 ) 

1595 else: 

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

1597 else: 

1598 new_param = _process_multiparam_default_bind( 

1599 compiler, stmt, col, i, kw 

1600 ) 

1601 

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

1603 

1604 values.append(extension) 

1605 

1606 return values 

1607 

1608 

1609def _get_stmt_parameter_tuples_params( 

1610 compiler, 

1611 compile_state, 

1612 parameters, 

1613 stmt_parameter_tuples, 

1614 _column_as_key, 

1615 values, 

1616 kw, 

1617): 

1618 for k, v in stmt_parameter_tuples: 

1619 colkey = _column_as_key(k) 

1620 if colkey is not None: 

1621 parameters.setdefault(colkey, v) 

1622 else: 

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

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

1625 # coercing right side to bound param 

1626 

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

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

1629 

1630 col_expr = compiler.process( 

1631 k, include_table=compile_state.include_table_with_column_exprs 

1632 ) 

1633 

1634 if coercions._is_literal(v): 

1635 v = compiler.process( 

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

1637 ) 

1638 else: 

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

1640 # either unique parameter, or other bound parameters that 

1641 # were passed in directly 

1642 # set type to that of the column unconditionally 

1643 v = v._with_binary_element_type(k.type) 

1644 

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

1646 

1647 # TODO: not sure if accumulated_bind_names applies here 

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

1649 

1650 

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

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

1653 

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

1655 INSERT or UPDATE statement after it's invoked. 

1656 

1657 """ 

1658 

1659 dialect = compiler.dialect 

1660 

1661 need_pks = ( 

1662 toplevel 

1663 and _compile_state_isinsert(compile_state) 

1664 and not stmt._inline 

1665 and ( 

1666 not compiler.for_executemany 

1667 or (dialect.insert_executemany_returning and stmt._return_defaults) 

1668 ) 

1669 and not stmt._returning 

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

1671 and not compile_state._has_multi_parameters 

1672 ) 

1673 

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

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

1676 postfetch_lastrowid = ( 

1677 need_pks 

1678 and dialect.postfetch_lastrowid 

1679 and stmt.table._autoincrement_column is not None 

1680 ) 

1681 

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

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

1684 # if that's set. 

1685 implicit_returning = ( 

1686 # statement itself can veto it 

1687 need_pks 

1688 # the dialect can veto it if it just doesnt support RETURNING 

1689 # with INSERT 

1690 and dialect.insert_returning 

1691 # user-defined implicit_returning on Table can veto it 

1692 and compile_state._primary_table.implicit_returning 

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

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

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

1696 and compile_state._supports_implicit_returning 

1697 and ( 

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

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

1700 # that didnt call return_defaults() and has just one set of 

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

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

1703 # SQLite lastrowid times 3x faster than returning, 

1704 # Mariadb lastrowid 2x faster than returning 

1705 (not postfetch_lastrowid or dialect.favor_returning_over_lastrowid) 

1706 or compile_state._has_multi_parameters 

1707 or stmt._return_defaults 

1708 ) 

1709 ) 

1710 if implicit_returning: 

1711 postfetch_lastrowid = False 

1712 

1713 if _compile_state_isinsert(compile_state): 

1714 should_implicit_return_defaults = ( 

1715 implicit_returning and stmt._return_defaults 

1716 ) 

1717 explicit_returning = ( 

1718 should_implicit_return_defaults 

1719 or stmt._returning 

1720 or stmt._supplemental_returning 

1721 ) 

1722 use_insertmanyvalues = ( 

1723 toplevel 

1724 and compiler.for_executemany 

1725 and dialect.use_insertmanyvalues 

1726 and ( 

1727 explicit_returning or dialect.use_insertmanyvalues_wo_returning 

1728 ) 

1729 ) 

1730 

1731 use_sentinel_columns = None 

1732 if ( 

1733 use_insertmanyvalues 

1734 and explicit_returning 

1735 and stmt._sort_by_parameter_order 

1736 ): 

1737 use_sentinel_columns = compiler._get_sentinel_column_for_table( 

1738 stmt.table 

1739 ) 

1740 

1741 elif compile_state.isupdate: 

1742 should_implicit_return_defaults = ( 

1743 stmt._return_defaults 

1744 and compile_state._primary_table.implicit_returning 

1745 and compile_state._supports_implicit_returning 

1746 and dialect.update_returning 

1747 ) 

1748 use_insertmanyvalues = False 

1749 use_sentinel_columns = None 

1750 elif compile_state.isdelete: 

1751 should_implicit_return_defaults = ( 

1752 stmt._return_defaults 

1753 and compile_state._primary_table.implicit_returning 

1754 and compile_state._supports_implicit_returning 

1755 and dialect.delete_returning 

1756 ) 

1757 use_insertmanyvalues = False 

1758 use_sentinel_columns = None 

1759 else: 

1760 should_implicit_return_defaults = False # pragma: no cover 

1761 use_insertmanyvalues = False 

1762 use_sentinel_columns = None 

1763 

1764 if should_implicit_return_defaults: 

1765 if not stmt._return_defaults_columns: 

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

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

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

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

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

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

1772 implicit_return_defaults = set(stmt.table.c) 

1773 else: 

1774 implicit_return_defaults = set(stmt._return_defaults_columns) 

1775 else: 

1776 implicit_return_defaults = None 

1777 

1778 return ( 

1779 need_pks, 

1780 implicit_returning or should_implicit_return_defaults, 

1781 implicit_return_defaults, 

1782 postfetch_lastrowid, 

1783 use_insertmanyvalues, 

1784 use_sentinel_columns, 

1785 ) 

1786 

1787 

1788def _warn_pk_with_no_anticipated_value(c): 

1789 msg = ( 

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

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

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

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

1794 "and no explicit value is passed. " 

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

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

1797 ) 

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

1799 msg += ( 

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

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

1802 "keys if AUTO_INCREMENT/SERIAL/IDENTITY " 

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

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

1805 "most backends." 

1806 ) 

1807 util.warn(msg)