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

18import re 

19from typing import Any 

20from typing import Callable 

21from typing import cast 

22from typing import Dict 

23from typing import Iterable 

24from typing import List 

25from typing import Literal 

26from typing import MutableMapping 

27from typing import NamedTuple 

28from typing import Optional 

29from typing import overload 

30from typing import Sequence 

31from typing import Set 

32from typing import Tuple 

33from typing import TYPE_CHECKING 

34from typing import Union 

35 

36from . import coercions 

37from . import dml 

38from . import elements 

39from . import roles 

40from .base import _DefaultDescriptionTuple 

41from .dml import isinsert as _compile_state_isinsert 

42from .elements import ColumnClause 

43from .schema import default_is_clause_element 

44from .schema import default_is_sequence 

45from .selectable import Select 

46from .selectable import TableClause 

47from .. import exc 

48from .. import util 

49 

50if TYPE_CHECKING: 

51 from .compiler import _BindNameForColProtocol 

52 from .compiler import SQLCompiler 

53 from .dml import _DMLColumnElement 

54 from .dml import DMLState 

55 from .dml import ValuesBase 

56 from .elements import ColumnElement 

57 from .elements import DMLTargetCopy 

58 from .elements import KeyedColumnElement 

59 from .schema import _SQLExprDefault 

60 from .schema import Column 

61 

62REQUIRED = util.symbol( 

63 "REQUIRED", 

64 """ 

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

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

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

68 

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

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

71values present. 

72 

73""", 

74) 

75 

76 

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

78 if not isinstance(c, ColumnClause): 

79 raise exc.CompileError( 

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

81 ) 

82 return c 

83 

84 

85_CrudParamElement = Tuple[ 

86 "ColumnElement[Any]", 

87 str, # column name 

88 Optional[ 

89 Union[str, "_SQLExprDefault"] 

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

91 Iterable[str], 

92] 

93_CrudParamElementStr = Tuple[ 

94 "KeyedColumnElement[Any]", 

95 str, # column name 

96 str, # bound parameter string 

97 Iterable[str], 

98] 

99_CrudParamElementSQLExpr = Tuple[ 

100 "ColumnClause[Any]", 

101 str, 

102 "_SQLExprDefault", # SQL expression to apply 

103 Iterable[str], 

104] 

105 

106_CrudParamSequence = List[_CrudParamElement] 

107 

108 

109class _CrudParams(NamedTuple): 

110 single_params: List[_CrudParamElementStr] 

111 all_multi_params: List[Sequence[_CrudParamElementStr]] 

112 is_default_metavalue_only: bool = False 

113 use_insertmanyvalues: bool = False 

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

115 

116 

117def _get_crud_params( 

118 compiler: SQLCompiler, 

119 stmt: ValuesBase, 

120 compile_state: DMLState, 

121 toplevel: bool, 

122 **kw: Any, 

123) -> _CrudParams: 

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

125 in an INSERT or UPDATE statement. 

126 

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

128 returning column collections, used for default handling and ultimately 

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

130 collections. 

131 

132 """ 

133 

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

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

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

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

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

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

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

141 

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

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

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

145 

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

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

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

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

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

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

152 

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

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

155 # as well as here. 

156 

157 compiler.postfetch = [] 

158 compiler.insert_prefetch = [] 

159 compiler.update_prefetch = [] 

160 compiler.implicit_returning = [] 

161 

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

163 if visiting_cte is not None: 

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

165 # _crud_accumulate_bind_names collection; the INSERT we process here 

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

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

168 kw.pop("accumulate_bind_names", None) 

169 assert ( 

170 "accumulate_bind_names" not in kw 

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

172 

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

174 kw["bindmarkers"] = bindmarkers 

175 

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

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

178 # .key must conditionally take tablename into account 

179 ( 

180 _column_as_key, 

181 _getattr_col_key, 

182 _col_bind_name, 

183 ) = _key_getters_for_crud_column(compiler, stmt, compile_state) 

184 

185 compiler._get_bind_name_for_col = _col_bind_name 

186 

187 if stmt._returning and stmt._return_defaults: 

188 raise exc.CompileError( 

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

190 "return_defaults() simultaneously" 

191 ) 

192 

193 if compile_state.isdelete: 

194 _setup_delete_return_defaults( 

195 compiler, 

196 stmt, 

197 compile_state, 

198 (), 

199 _getattr_col_key, 

200 _column_as_key, 

201 _col_bind_name, 

202 (), 

203 (), 

204 toplevel, 

205 kw, 

206 ) 

207 return _CrudParams([], []) 

208 

209 # no parameters in the statement, no parameters in the 

210 # compiled params - return binds for all columns 

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

212 return _CrudParams( 

213 [ 

214 ( 

215 c, 

216 compiler.preparer.format_column(c), 

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

218 (c.key,), 

219 ) 

220 for c in stmt.table.columns 

221 if not c._omit_from_statements 

222 ], 

223 [], 

224 ) 

225 

226 stmt_parameter_tuples: Optional[ 

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

228 ] 

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

230 

231 if ( 

232 _compile_state_isinsert(compile_state) 

233 and compile_state._has_multi_parameters 

234 ): 

235 mp = compile_state._multi_parameters 

236 assert mp is not None 

237 spd = mp[0] 

238 stmt_parameter_tuples = list(spd.items()) 

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 

407 if bindmarkers: 

408 _replace_bindmarkers( 

409 compiler, 

410 _column_as_key, 

411 bindmarkers, 

412 compile_state, 

413 values, 

414 kw, 

415 ) 

416 for m_v in multi_extended_values: 

417 _replace_bindmarkers( 

418 compiler, 

419 _column_as_key, 

420 bindmarkers, 

421 compile_state, 

422 m_v, 

423 kw, 

424 ) 

425 

426 return _CrudParams(values, multi_extended_values) 

427 elif ( 

428 not values 

429 and compiler.for_executemany 

430 and compiler.dialect.supports_default_metavalue 

431 ): 

432 # convert an "INSERT DEFAULT VALUES" 

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

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

435 # insert_executemany_returning mode :) 

436 values = [ 

437 ( 

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

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

440 compiler.dialect.default_metavalue_token, 

441 (), 

442 ) 

443 ] 

444 is_default_metavalue_only = True 

445 

446 if bindmarkers: 

447 _replace_bindmarkers( 

448 compiler, _column_as_key, bindmarkers, compile_state, values, kw 

449 ) 

450 return _CrudParams( 

451 values, 

452 [], 

453 is_default_metavalue_only=is_default_metavalue_only, 

454 use_insertmanyvalues=use_insertmanyvalues, 

455 use_sentinel_columns=use_sentinel_columns, 

456 ) 

457 

458 

459def _replace_bindmarkers( 

460 compiler, _column_as_key, bindmarkers, compile_state, values, kw 

461): 

462 _expr_by_col_key = { 

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

464 } 

465 

466 def replace_marker(m): 

467 try: 

468 return _expr_by_col_key[m.group(1)] 

469 except KeyError as ke: 

470 if dml.isupdate(compile_state): 

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

472 else: 

473 raise exc.CompileError( 

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

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

476 ) from ke 

477 

478 values[:] = [ 

479 ( 

480 col, 

481 col_value, 

482 re.sub( 

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

484 replace_marker, 

485 compiled_str, 

486 ), 

487 accumulated_bind_names, 

488 ) 

489 for ( 

490 col, 

491 col_value, 

492 compiled_str, 

493 accumulated_bind_names, 

494 ) in values 

495 ] 

496 

497 

498@overload 

499def _create_bind_param( 

500 compiler: SQLCompiler, 

501 col: ColumnElement[Any], 

502 value: Any, 

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

504 required: bool = False, 

505 name: Optional[str] = None, 

506 force_anonymous: bool = False, 

507 **kw: Any, 

508) -> str: ... 

509 

510 

511@overload 

512def _create_bind_param( 

513 compiler: SQLCompiler, 

514 col: ColumnElement[Any], 

515 value: Any, 

516 **kw: Any, 

517) -> str: ... 

518 

519 

520def _create_bind_param( 

521 compiler: SQLCompiler, 

522 col: ColumnElement[Any], 

523 value: Any, 

524 process: bool = True, 

525 required: bool = False, 

526 name: Optional[str] = None, 

527 force_anonymous: bool = False, 

528 **kw: Any, 

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

530 if force_anonymous: 

531 name = None 

532 elif name is None: 

533 name = col.key 

534 

535 bindparam = elements.BindParameter( 

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

537 ) 

538 bindparam._is_crud = True 

539 if process: 

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

541 else: 

542 return bindparam 

543 

544 

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

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

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

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

549 # produce bound parameters in deterministic order without invoking any 

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

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

552 # right now). 

553 # 

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

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

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

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

558 # rather than having 

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

560 # name. Saves on call counts also. 

561 

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

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

564 # multiple insert/update are combined together using CTEs 

565 is_cte = "visiting_cte" in kw 

566 

567 if ( 

568 not is_cte 

569 and value.unique 

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

571 ): 

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

573 

574 if value.type._isnull: 

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

576 # passed in directly 

577 # set type to that of the column unconditionally 

578 value = value._with_binary_element_type(col.type) 

579 

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

581 

582 

583def _key_getters_for_crud_column( 

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

585) -> Tuple[ 

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

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

588 _BindNameForColProtocol, 

589]: 

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

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

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

593 # dictionaries and when rendering bind param names. 

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

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

596 # statement. 

597 _et = set(compile_state._extra_froms) 

598 

599 c_key_role = functools.partial( 

600 coercions.expect_as_key, roles.DMLColumnRole 

601 ) 

602 

603 def _column_as_key( 

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

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

606 str_key = c_key_role(key) 

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

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

609 else: 

610 return str_key 

611 

612 def _getattr_col_key( 

613 col: ColumnClause[Any], 

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

615 if col.table in _et: 

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

617 else: 

618 return col.key 

619 

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

621 if col.table in _et: 

622 if TYPE_CHECKING: 

623 assert isinstance(col.table, TableClause) 

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

625 else: 

626 return col.key 

627 

628 else: 

629 _column_as_key = functools.partial( 

630 coercions.expect_as_key, roles.DMLColumnRole 

631 ) 

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

633 

634 return _column_as_key, _getattr_col_key, _col_bind_name 

635 

636 

637def _scan_insert_from_select_cols( 

638 compiler, 

639 stmt, 

640 compile_state, 

641 parameters, 

642 _getattr_col_key, 

643 _column_as_key, 

644 _col_bind_name, 

645 check_columns, 

646 values, 

647 toplevel, 

648 kw, 

649): 

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

651 

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

653 

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

655 

656 add_select_cols: List[_CrudParamElementSQLExpr] = [] 

657 if stmt.include_insert_from_select_defaults: 

658 col_set = set(cols) 

659 for col in stmt.table.columns: 

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

661 # this will omit columns marked as omit_from_statements naturally, 

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

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

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

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

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

667 # here so we again omit it. 

668 if ( 

669 col not in col_set 

670 and col.default 

671 and not col.default.is_sentinel 

672 ): 

673 cols.append(col) 

674 

675 for c in cols: 

676 col_key = _getattr_col_key(c) 

677 if col_key in parameters and col_key not in check_columns: 

678 parameters.pop(col_key) 

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

680 else: 

681 _append_param_insert_select_hasdefault( 

682 compiler, stmt, c, add_select_cols, kw 

683 ) 

684 

685 if add_select_cols: 

686 values.extend(add_select_cols) 

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

688 if not isinstance(ins_from_select, Select): 

689 raise exc.CompileError( 

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

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

692 f"""{ 

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

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

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

696 "columns." 

697 ) 

698 ins_from_select = ins_from_select._generate() 

699 # copy raw_columns 

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

701 expr for _, _, expr, _ in add_select_cols 

702 ] 

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

704 

705 

706def _scan_cols( 

707 compiler, 

708 stmt, 

709 compile_state, 

710 parameters, 

711 _getattr_col_key, 

712 _column_as_key, 

713 _col_bind_name, 

714 check_columns, 

715 values, 

716 toplevel, 

717 kw, 

718): 

719 ( 

720 need_pks, 

721 implicit_returning, 

722 implicit_return_defaults, 

723 postfetch_lastrowid, 

724 use_insertmanyvalues, 

725 use_sentinel_columns, 

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

727 

728 assert compile_state.isupdate or compile_state.isinsert 

729 

730 if compile_state._maintain_values_ordering: 

731 parameter_ordering = [ 

732 _column_as_key(key) for key in compile_state._dict_parameters 

733 ] 

734 ordered_keys = set(parameter_ordering) 

735 cols = [ 

736 stmt.table.c[key] 

737 for key in parameter_ordering 

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

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

740 

741 else: 

742 cols = stmt.table.columns 

743 

744 isinsert = _compile_state_isinsert(compile_state) 

745 if isinsert and not compile_state._has_multi_parameters: 

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

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

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

749 autoincrement_col = stmt.table._autoincrement_column 

750 insert_null_pk_still_autoincrements = ( 

751 compiler.dialect.insert_null_pk_still_autoincrements 

752 ) 

753 else: 

754 autoincrement_col = insert_null_pk_still_autoincrements = None 

755 

756 if stmt._supplemental_returning: 

757 supplemental_returning = set(stmt._supplemental_returning) 

758 else: 

759 supplemental_returning = set() 

760 

761 compiler_implicit_returning = compiler.implicit_returning 

762 

763 # TODO - see TODO(return_defaults_columns) below 

764 # cols_in_params = set() 

765 

766 for c in cols: 

767 # scan through every column in the target table 

768 

769 col_key = _getattr_col_key(c) 

770 

771 if col_key in parameters and col_key not in check_columns: 

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

773 

774 _append_param_parameter( 

775 compiler, 

776 stmt, 

777 compile_state, 

778 c, 

779 col_key, 

780 parameters, 

781 _col_bind_name, 

782 implicit_returning, 

783 implicit_return_defaults, 

784 postfetch_lastrowid, 

785 values, 

786 autoincrement_col, 

787 insert_null_pk_still_autoincrements, 

788 kw, 

789 ) 

790 

791 # TODO - see TODO(return_defaults_columns) below 

792 # cols_in_params.add(c) 

793 

794 elif isinsert: 

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

796 

797 if c.primary_key and need_pks: 

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

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

800 # inserted_primary_key to be available. 

801 

802 if implicit_returning: 

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

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

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

806 

807 _append_param_insert_pk_returning( 

808 compiler, stmt, c, values, kw 

809 ) 

810 else: 

811 # otherwise, find out how to invoke this column 

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

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

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

815 # autoincrement column and the dialect supports it 

816 # we can use cursor.lastrowid. 

817 

818 _append_param_insert_pk_no_returning( 

819 compiler, stmt, c, values, kw 

820 ) 

821 

822 elif c.default is not None: 

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

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

825 if not c.default.is_sentinel or ( 

826 use_sentinel_columns is not None 

827 ): 

828 _append_param_insert_hasdefault( 

829 compiler, stmt, c, implicit_return_defaults, values, kw 

830 ) 

831 

832 elif c.server_default is not None: 

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

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

835 if implicit_return_defaults and c in implicit_return_defaults: 

836 compiler_implicit_returning.append(c) 

837 elif not c.primary_key: 

838 compiler.postfetch.append(c) 

839 

840 elif implicit_return_defaults and c in implicit_return_defaults: 

841 compiler_implicit_returning.append(c) 

842 

843 elif ( 

844 c.primary_key 

845 and c is not stmt.table._autoincrement_column 

846 and not c.nullable 

847 ): 

848 _warn_pk_with_no_anticipated_value(c) 

849 

850 elif compile_state.isupdate: 

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

852 

853 _append_param_update( 

854 compiler, 

855 compile_state, 

856 stmt, 

857 c, 

858 implicit_return_defaults, 

859 values, 

860 kw, 

861 ) 

862 

863 # adding supplemental cols to implicit_returning in table 

864 # order so that order is maintained between multiple INSERT 

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

866 # have the same RETURNING clause 

867 if ( 

868 c in supplemental_returning 

869 and c not in compiler_implicit_returning 

870 ): 

871 compiler_implicit_returning.append(c) 

872 

873 if supplemental_returning: 

874 # we should have gotten every col into implicit_returning, 

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

876 # in it 

877 remaining_supplemental = supplemental_returning.difference( 

878 compiler_implicit_returning 

879 ) 

880 compiler_implicit_returning.extend( 

881 c 

882 for c in stmt._supplemental_returning 

883 if c in remaining_supplemental 

884 ) 

885 

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

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

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

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

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

891 

892 # if stmt._return_defaults_columns: 

893 # compiler_implicit_returning.extend( 

894 # set(stmt._return_defaults_columns) 

895 # .difference(compiler_implicit_returning) 

896 # .difference(cols_in_params) 

897 # ) 

898 

899 return (use_insertmanyvalues, use_sentinel_columns) 

900 

901 

902def _setup_delete_return_defaults( 

903 compiler, 

904 stmt, 

905 compile_state, 

906 parameters, 

907 _getattr_col_key, 

908 _column_as_key, 

909 _col_bind_name, 

910 check_columns, 

911 values, 

912 toplevel, 

913 kw, 

914): 

915 _, _, implicit_return_defaults, *_ = _get_returning_modifiers( 

916 compiler, stmt, compile_state, toplevel 

917 ) 

918 

919 if not implicit_return_defaults: 

920 return 

921 

922 if stmt._return_defaults_columns: 

923 compiler.implicit_returning.extend(implicit_return_defaults) 

924 

925 if stmt._supplemental_returning: 

926 ir_set = set(compiler.implicit_returning) 

927 compiler.implicit_returning.extend( 

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

929 ) 

930 

931 

932def _append_param_parameter( 

933 compiler, 

934 stmt, 

935 compile_state, 

936 c, 

937 col_key, 

938 parameters, 

939 _col_bind_name, 

940 implicit_returning, 

941 implicit_return_defaults, 

942 postfetch_lastrowid, 

943 values, 

944 autoincrement_col, 

945 insert_null_pk_still_autoincrements, 

946 kw, 

947): 

948 value = parameters.pop(col_key) 

949 

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

951 col_value = compiler.preparer.format_column( 

952 c, use_table=compile_state.include_table_with_column_exprs 

953 ) 

954 

955 accumulated_bind_names: Set[str] = set() 

956 

957 if coercions._is_literal(value): 

958 if ( 

959 insert_null_pk_still_autoincrements 

960 and c.primary_key 

961 and c is autoincrement_col 

962 ): 

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

964 # even if value was given. 

965 

966 if postfetch_lastrowid: 

967 compiler.postfetch_lastrowid = True 

968 elif implicit_returning: 

969 compiler.implicit_returning.append(c) 

970 

971 value = _create_bind_param( 

972 compiler, 

973 c, 

974 value, 

975 required=value is REQUIRED, 

976 name=( 

977 _col_bind_name(c) 

978 if not _compile_state_isinsert(compile_state) 

979 or not compile_state._has_multi_parameters 

980 else "%s_m0" % _col_bind_name(c) 

981 ), 

982 accumulate_bind_names=accumulated_bind_names, 

983 force_anonymous=has_visiting_cte, 

984 **kw, 

985 ) 

986 elif value._is_bind_parameter: 

987 if ( 

988 insert_null_pk_still_autoincrements 

989 and value.value is None 

990 and c.primary_key 

991 and c is autoincrement_col 

992 ): 

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

994 # even if value was given 

995 if implicit_returning: 

996 compiler.implicit_returning.append(c) 

997 elif compiler.dialect.postfetch_lastrowid: 

998 compiler.postfetch_lastrowid = True 

999 

1000 value = _handle_values_anonymous_param( 

1001 compiler, 

1002 c, 

1003 value, 

1004 name=( 

1005 _col_bind_name(c) 

1006 if not _compile_state_isinsert(compile_state) 

1007 or not compile_state._has_multi_parameters 

1008 else "%s_m0" % _col_bind_name(c) 

1009 ), 

1010 accumulate_bind_names=accumulated_bind_names, 

1011 **kw, 

1012 ) 

1013 else: 

1014 # value is a SQL expression 

1015 value = compiler.process( 

1016 value.self_group(), 

1017 accumulate_bind_names=accumulated_bind_names, 

1018 **kw, 

1019 ) 

1020 

1021 if compile_state.isupdate: 

1022 if implicit_return_defaults and c in implicit_return_defaults: 

1023 compiler.implicit_returning.append(c) 

1024 

1025 else: 

1026 compiler.postfetch.append(c) 

1027 else: 

1028 if c.primary_key: 

1029 if implicit_returning: 

1030 compiler.implicit_returning.append(c) 

1031 elif compiler.dialect.postfetch_lastrowid: 

1032 compiler.postfetch_lastrowid = True 

1033 

1034 elif implicit_return_defaults and (c in implicit_return_defaults): 

1035 compiler.implicit_returning.append(c) 

1036 

1037 else: 

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

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

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

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

1042 # time. 

1043 

1044 compiler.postfetch.append(c) 

1045 

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

1047 

1048 

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

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

1051 we want to populate result.inserted_primary_key and RETURNING 

1052 is available. 

1053 

1054 """ 

1055 if c.default is not None: 

1056 if c.default.is_sequence: 

1057 if compiler.dialect.supports_sequences and ( 

1058 not c.default.optional 

1059 or not compiler.dialect.sequences_optional 

1060 ): 

1061 accumulated_bind_names: Set[str] = set() 

1062 values.append( 

1063 ( 

1064 c, 

1065 compiler.preparer.format_column(c), 

1066 compiler.process( 

1067 c.default, 

1068 accumulate_bind_names=accumulated_bind_names, 

1069 **kw, 

1070 ), 

1071 accumulated_bind_names, 

1072 ) 

1073 ) 

1074 compiler.implicit_returning.append(c) 

1075 elif c.default.is_clause_element: 

1076 accumulated_bind_names = set() 

1077 values.append( 

1078 ( 

1079 c, 

1080 compiler.preparer.format_column(c), 

1081 compiler.process( 

1082 c.default.arg.self_group(), 

1083 accumulate_bind_names=accumulated_bind_names, 

1084 **kw, 

1085 ), 

1086 accumulated_bind_names, 

1087 ) 

1088 ) 

1089 compiler.implicit_returning.append(c) 

1090 else: 

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

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

1093 # on the Python side 

1094 values.append( 

1095 ( 

1096 c, 

1097 compiler.preparer.format_column(c), 

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

1099 (c.key,), 

1100 ) 

1101 ) 

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

1103 compiler.implicit_returning.append(c) 

1104 elif not c.nullable: 

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

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

1107 _warn_pk_with_no_anticipated_value(c) 

1108 

1109 

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

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

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

1113 RETURNING. 

1114 

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

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

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

1118 

1119 

1120 """ 

1121 

1122 if ( 

1123 # column has a Python-side default 

1124 c.default is not None 

1125 and ( 

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

1127 # sequences and want to invoke it 

1128 not c.default.is_sequence 

1129 or ( 

1130 compiler.dialect.supports_sequences 

1131 and ( 

1132 not c.default.optional 

1133 or not compiler.dialect.sequences_optional 

1134 ) 

1135 ) 

1136 ) 

1137 ) or ( 

1138 # column is the "autoincrement column" 

1139 c is stmt.table._autoincrement_column 

1140 and ( 

1141 # dialect can't use cursor.lastrowid 

1142 not compiler.dialect.postfetch_lastrowid 

1143 and ( 

1144 # column has a Sequence and we support those 

1145 ( 

1146 c.default is not None 

1147 and c.default.is_sequence 

1148 and compiler.dialect.supports_sequences 

1149 ) 

1150 or 

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

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

1153 # SERIAL we know the sequence name 

1154 ( 

1155 c.default is None 

1156 and compiler.dialect.preexecute_autoincrement_sequences 

1157 ) 

1158 ) 

1159 ) 

1160 ): 

1161 # do a pre-execute of the default 

1162 values.append( 

1163 ( 

1164 c, 

1165 compiler.preparer.format_column(c), 

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

1167 (c.key,), 

1168 ) 

1169 ) 

1170 elif ( 

1171 c.default is None 

1172 and c.server_default is None 

1173 and not c.nullable 

1174 and c is not stmt.table._autoincrement_column 

1175 ): 

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

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

1178 _warn_pk_with_no_anticipated_value(c) 

1179 elif compiler.dialect.postfetch_lastrowid: 

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

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

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

1183 # that the DefaultExecutionContext calls upon cursor.lastrowid 

1184 compiler.postfetch_lastrowid = True 

1185 

1186 

1187def _append_param_insert_hasdefault( 

1188 compiler, stmt, c, implicit_return_defaults, values, kw 

1189): 

1190 if c.default.is_sequence: 

1191 if compiler.dialect.supports_sequences and ( 

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

1193 ): 

1194 accumulated_bind_names: Set[str] = set() 

1195 values.append( 

1196 ( 

1197 c, 

1198 compiler.preparer.format_column(c), 

1199 compiler.process( 

1200 c.default, 

1201 accumulate_bind_names=accumulated_bind_names, 

1202 **kw, 

1203 ), 

1204 accumulated_bind_names, 

1205 ) 

1206 ) 

1207 if implicit_return_defaults and c in implicit_return_defaults: 

1208 compiler.implicit_returning.append(c) 

1209 elif not c.primary_key: 

1210 compiler.postfetch.append(c) 

1211 elif c.default.is_clause_element: 

1212 accumulated_bind_names = set() 

1213 values.append( 

1214 ( 

1215 c, 

1216 compiler.preparer.format_column(c), 

1217 compiler.process( 

1218 c.default.arg.self_group(), 

1219 accumulate_bind_names=accumulated_bind_names, 

1220 **kw, 

1221 ), 

1222 accumulated_bind_names, 

1223 ) 

1224 ) 

1225 

1226 if implicit_return_defaults and c in implicit_return_defaults: 

1227 compiler.implicit_returning.append(c) 

1228 elif not c.primary_key: 

1229 # don't add primary key column to postfetch 

1230 compiler.postfetch.append(c) 

1231 else: 

1232 values.append( 

1233 ( 

1234 c, 

1235 compiler.preparer.format_column(c), 

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

1237 (c.key,), 

1238 ) 

1239 ) 

1240 

1241 

1242def _append_param_insert_select_hasdefault( 

1243 compiler: SQLCompiler, 

1244 stmt: ValuesBase, 

1245 c: ColumnClause[Any], 

1246 values: List[_CrudParamElementSQLExpr], 

1247 kw: Dict[str, Any], 

1248) -> None: 

1249 if default_is_sequence(c.default): 

1250 if compiler.dialect.supports_sequences and ( 

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

1252 ): 

1253 values.append( 

1254 ( 

1255 c, 

1256 compiler.preparer.format_column(c), 

1257 c.default.next_value(), 

1258 (), 

1259 ) 

1260 ) 

1261 elif default_is_clause_element(c.default): 

1262 values.append( 

1263 ( 

1264 c, 

1265 compiler.preparer.format_column(c), 

1266 c.default.arg.self_group(), 

1267 (), 

1268 ) 

1269 ) 

1270 else: 

1271 values.append( 

1272 ( 

1273 c, 

1274 compiler.preparer.format_column(c), 

1275 _create_insert_prefetch_bind_param( 

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

1277 ), 

1278 (c.key,), 

1279 ) 

1280 ) 

1281 

1282 

1283def _append_param_update( 

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

1285): 

1286 include_table = compile_state.include_table_with_column_exprs 

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

1288 if c.onupdate.is_clause_element: 

1289 values.append( 

1290 ( 

1291 c, 

1292 compiler.preparer.format_column( 

1293 c, 

1294 use_table=include_table, 

1295 ), 

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

1297 (), 

1298 ) 

1299 ) 

1300 if implicit_return_defaults and c in implicit_return_defaults: 

1301 compiler.implicit_returning.append(c) 

1302 else: 

1303 compiler.postfetch.append(c) 

1304 else: 

1305 values.append( 

1306 ( 

1307 c, 

1308 compiler.preparer.format_column( 

1309 c, 

1310 use_table=include_table, 

1311 ), 

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

1313 (c.key,), 

1314 ) 

1315 ) 

1316 elif c.server_onupdate is not None: 

1317 if implicit_return_defaults and c in implicit_return_defaults: 

1318 compiler.implicit_returning.append(c) 

1319 else: 

1320 compiler.postfetch.append(c) 

1321 elif ( 

1322 implicit_return_defaults 

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

1324 and c in implicit_return_defaults 

1325 ): 

1326 compiler.implicit_returning.append(c) 

1327 

1328 

1329@overload 

1330def _create_insert_prefetch_bind_param( 

1331 compiler: SQLCompiler, 

1332 c: ColumnElement[Any], 

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

1334 **kw: Any, 

1335) -> str: ... 

1336 

1337 

1338@overload 

1339def _create_insert_prefetch_bind_param( 

1340 compiler: SQLCompiler, 

1341 c: ColumnElement[Any], 

1342 process: Literal[False], 

1343 **kw: Any, 

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

1345 

1346 

1347def _create_insert_prefetch_bind_param( 

1348 compiler: SQLCompiler, 

1349 c: ColumnElement[Any], 

1350 process: bool = True, 

1351 name: Optional[str] = None, 

1352 **kw: Any, 

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

1354 param = _create_bind_param( 

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

1356 ) 

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

1358 return param 

1359 

1360 

1361@overload 

1362def _create_update_prefetch_bind_param( 

1363 compiler: SQLCompiler, 

1364 c: ColumnElement[Any], 

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

1366 **kw: Any, 

1367) -> str: ... 

1368 

1369 

1370@overload 

1371def _create_update_prefetch_bind_param( 

1372 compiler: SQLCompiler, 

1373 c: ColumnElement[Any], 

1374 process: Literal[False], 

1375 **kw: Any, 

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

1377 

1378 

1379def _create_update_prefetch_bind_param( 

1380 compiler: SQLCompiler, 

1381 c: ColumnElement[Any], 

1382 process: bool = True, 

1383 name: Optional[str] = None, 

1384 **kw: Any, 

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

1386 param = _create_bind_param( 

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

1388 ) 

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

1390 return param 

1391 

1392 

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

1394 _is_multiparam_column = True 

1395 

1396 def __init__(self, original, index): 

1397 self.index = index 

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

1399 self.original = original 

1400 self.default = original.default 

1401 self.type = original.type 

1402 

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

1404 raise NotImplementedError() 

1405 

1406 def _copy_internals(self, **kw): 

1407 raise NotImplementedError() 

1408 

1409 def __eq__(self, other): 

1410 return ( 

1411 isinstance(other, _multiparam_column) 

1412 and other.key == self.key 

1413 and other.original == self.original 

1414 ) 

1415 

1416 @util.memoized_property 

1417 def _default_description_tuple(self) -> _DefaultDescriptionTuple: 

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

1419 

1420 return _DefaultDescriptionTuple._from_column_default(self.default) 

1421 

1422 @util.memoized_property 

1423 def _onupdate_description_tuple(self) -> _DefaultDescriptionTuple: 

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

1425 

1426 return _DefaultDescriptionTuple._from_column_default(self.onupdate) 

1427 

1428 

1429def _process_multiparam_default_bind( 

1430 compiler: SQLCompiler, 

1431 stmt: ValuesBase, 

1432 c: KeyedColumnElement[Any], 

1433 index: int, 

1434 kw: Dict[str, Any], 

1435) -> str: 

1436 if not c.default: 

1437 raise exc.CompileError( 

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

1439 "parameter in the VALUES clause; " 

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

1441 ) 

1442 elif default_is_clause_element(c.default): 

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

1444 elif c.default.is_sequence: 

1445 # these conditions would have been established 

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

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

1448 # checked 

1449 # assert compiler.dialect.supports_sequences and ( 

1450 # not c.default.optional 

1451 # or not compiler.dialect.sequences_optional 

1452 # ) 

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

1454 else: 

1455 col = _multiparam_column(c, index) 

1456 assert isinstance(stmt, dml.Insert) 

1457 return _create_insert_prefetch_bind_param( 

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

1459 ) 

1460 

1461 

1462def _get_update_multitable_params( 

1463 compiler, 

1464 stmt, 

1465 compile_state, 

1466 stmt_parameter_tuples, 

1467 check_columns, 

1468 _col_bind_name, 

1469 _getattr_col_key, 

1470 values, 

1471 kw, 

1472): 

1473 normalized_params = { 

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

1475 for c, param in stmt_parameter_tuples or () 

1476 } 

1477 

1478 include_table = compile_state.include_table_with_column_exprs 

1479 

1480 affected_tables = set() 

1481 for t in compile_state._extra_froms: 

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

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

1484 # supported 

1485 we_shouldnt_be_here_if_columns_found = ( 

1486 not include_table 

1487 and not compile_state.dml_table.is_derived_from(t) 

1488 ) 

1489 

1490 for c in t.c: 

1491 if c in normalized_params: 

1492 

1493 if we_shouldnt_be_here_if_columns_found: 

1494 raise exc.CompileError( 

1495 "Backend does not support additional tables " 

1496 "in the SET " 

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

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

1499 "SET clause" 

1500 ) 

1501 

1502 affected_tables.add(t) 

1503 

1504 check_columns[_getattr_col_key(c)] = c 

1505 value = normalized_params[c] 

1506 

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

1508 if coercions._is_literal(value): 

1509 value = _create_bind_param( 

1510 compiler, 

1511 c, 

1512 value, 

1513 required=value is REQUIRED, 

1514 name=_col_bind_name(c), 

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

1516 ) 

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

1518 elif value._is_bind_parameter: 

1519 cbn = _col_bind_name(c) 

1520 value = _handle_values_anonymous_param( 

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

1522 ) 

1523 accumulated_bind_names = (cbn,) 

1524 else: 

1525 compiler.postfetch.append(c) 

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

1527 accumulated_bind_names = () 

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

1529 

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

1531 # and server_onupdate for these 

1532 for t in affected_tables: 

1533 for c in t.c: 

1534 if c in normalized_params: 

1535 continue 

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

1537 if c.onupdate.is_clause_element: 

1538 values.append( 

1539 ( 

1540 c, 

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

1542 compiler.process( 

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

1544 ), 

1545 (), 

1546 ) 

1547 ) 

1548 compiler.postfetch.append(c) 

1549 else: 

1550 values.append( 

1551 ( 

1552 c, 

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

1554 _create_update_prefetch_bind_param( 

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

1556 ), 

1557 (c.key,), 

1558 ) 

1559 ) 

1560 elif c.server_onupdate is not None: 

1561 compiler.postfetch.append(c) 

1562 

1563 

1564def _extend_values_for_multiparams( 

1565 compiler: SQLCompiler, 

1566 stmt: ValuesBase, 

1567 compile_state: DMLState, 

1568 initial_values: Sequence[_CrudParamElementStr], 

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

1570 kw: Dict[str, Any], 

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

1572 values_0 = initial_values 

1573 values = [initial_values] 

1574 

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

1576 mp = compile_state._multi_parameters 

1577 assert mp is not None 

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

1579 extension: List[_CrudParamElementStr] = [] 

1580 

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

1582 

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

1584 if col.key in row: 

1585 key = col.key 

1586 

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

1588 new_param = _create_bind_param( 

1589 compiler, 

1590 col, 

1591 row[key], 

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

1593 force_anonymous=has_visiting_cte, 

1594 **kw, 

1595 ) 

1596 else: 

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

1598 else: 

1599 new_param = _process_multiparam_default_bind( 

1600 compiler, stmt, col, i, kw 

1601 ) 

1602 

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

1604 

1605 values.append(extension) 

1606 

1607 return values 

1608 

1609 

1610def _get_stmt_parameter_tuples_params( 

1611 compiler, 

1612 compile_state, 

1613 parameters, 

1614 stmt_parameter_tuples, 

1615 _column_as_key, 

1616 values, 

1617 kw, 

1618): 

1619 for k, v in stmt_parameter_tuples: 

1620 colkey = _column_as_key(k) 

1621 if colkey is not None: 

1622 parameters.setdefault(colkey, v) 

1623 else: 

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

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

1626 # coercing right side to bound param 

1627 

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

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

1630 

1631 col_expr = compiler.process( 

1632 k, include_table=compile_state.include_table_with_column_exprs 

1633 ) 

1634 

1635 if coercions._is_literal(v): 

1636 v = compiler.process( 

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

1638 ) 

1639 else: 

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

1641 # either unique parameter, or other bound parameters that 

1642 # were passed in directly 

1643 # set type to that of the column unconditionally 

1644 v = v._with_binary_element_type(k.type) 

1645 

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

1647 

1648 # TODO: not sure if accumulated_bind_names applies here 

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

1650 

1651 

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

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

1654 

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

1656 INSERT or UPDATE statement after it's invoked. 

1657 

1658 """ 

1659 

1660 dialect = compiler.dialect 

1661 

1662 need_pks = ( 

1663 toplevel 

1664 and _compile_state_isinsert(compile_state) 

1665 and not stmt._inline 

1666 and ( 

1667 not compiler.for_executemany 

1668 or (dialect.insert_executemany_returning and stmt._return_defaults) 

1669 ) 

1670 and not stmt._returning 

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

1672 and not compile_state._has_multi_parameters 

1673 ) 

1674 

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

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

1677 postfetch_lastrowid = ( 

1678 need_pks 

1679 and dialect.postfetch_lastrowid 

1680 and stmt.table._autoincrement_column is not None 

1681 ) 

1682 

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

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

1685 # if that's set. 

1686 implicit_returning = ( 

1687 # statement itself can veto it 

1688 need_pks 

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

1690 # with INSERT 

1691 and dialect.insert_returning 

1692 # user-defined implicit_returning on Table can veto it 

1693 and compile_state._primary_table.implicit_returning 

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

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

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

1697 and compile_state._supports_implicit_returning 

1698 and ( 

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

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

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

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

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

1704 # SQLite lastrowid times 3x faster than returning, 

1705 # Mariadb lastrowid 2x faster than returning 

1706 (not postfetch_lastrowid or dialect.favor_returning_over_lastrowid) 

1707 or compile_state._has_multi_parameters 

1708 or stmt._return_defaults 

1709 ) 

1710 ) 

1711 if implicit_returning: 

1712 postfetch_lastrowid = False 

1713 

1714 if _compile_state_isinsert(compile_state): 

1715 should_implicit_return_defaults = ( 

1716 implicit_returning and stmt._return_defaults 

1717 ) 

1718 explicit_returning = ( 

1719 should_implicit_return_defaults 

1720 or stmt._returning 

1721 or stmt._supplemental_returning 

1722 ) 

1723 use_insertmanyvalues = ( 

1724 toplevel 

1725 and compiler.for_executemany 

1726 and dialect.use_insertmanyvalues 

1727 and ( 

1728 explicit_returning 

1729 or ( 

1730 dialect.use_insertmanyvalues_wo_returning 

1731 # Disable insertmanyvalues_wo_returning when there's a 

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

1733 # This is a performance optimization flag and the batching 

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

1735 and stmt._post_values_clause is None 

1736 ) 

1737 ) 

1738 ) 

1739 

1740 use_sentinel_columns = None 

1741 if ( 

1742 use_insertmanyvalues 

1743 and explicit_returning 

1744 and stmt._sort_by_parameter_order 

1745 ): 

1746 use_sentinel_columns = compiler._get_sentinel_column_for_table( 

1747 stmt.table 

1748 ) 

1749 

1750 elif compile_state.isupdate: 

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.update_returning 

1756 ) 

1757 use_insertmanyvalues = False 

1758 use_sentinel_columns = None 

1759 elif compile_state.isdelete: 

1760 should_implicit_return_defaults = ( 

1761 stmt._return_defaults 

1762 and compile_state._primary_table.implicit_returning 

1763 and compile_state._supports_implicit_returning 

1764 and dialect.delete_returning 

1765 ) 

1766 use_insertmanyvalues = False 

1767 use_sentinel_columns = None 

1768 else: 

1769 should_implicit_return_defaults = False # pragma: no cover 

1770 use_insertmanyvalues = False 

1771 use_sentinel_columns = None 

1772 

1773 if should_implicit_return_defaults: 

1774 if not stmt._return_defaults_columns: 

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

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

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

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

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

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

1781 implicit_return_defaults = set(stmt.table.c) 

1782 else: 

1783 implicit_return_defaults = set(stmt._return_defaults_columns) 

1784 else: 

1785 implicit_return_defaults = None 

1786 

1787 return ( 

1788 need_pks, 

1789 implicit_returning or should_implicit_return_defaults, 

1790 implicit_return_defaults, 

1791 postfetch_lastrowid, 

1792 use_insertmanyvalues, 

1793 use_sentinel_columns, 

1794 ) 

1795 

1796 

1797def _warn_pk_with_no_anticipated_value(c): 

1798 msg = ( 

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

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

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

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

1803 "and no explicit value is passed. " 

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

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

1806 ) 

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

1808 msg += ( 

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

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

1811 "keys if AUTO_INCREMENT/SERIAL/IDENTITY " 

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

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

1814 "most backends." 

1815 ) 

1816 util.warn(msg)