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

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

500 statements  

1# sql/crud.py 

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

17from typing import Any 

18from typing import Callable 

19from typing import cast 

20from typing import Dict 

21from typing import Iterable 

22from typing import List 

23from typing import MutableMapping 

24from typing import NamedTuple 

25from typing import Optional 

26from typing import overload 

27from typing import Sequence 

28from typing import Set 

29from typing import Tuple 

30from typing import TYPE_CHECKING 

31from typing import Union 

32 

33from . import coercions 

34from . import dml 

35from . import elements 

36from . import roles 

37from .base import _DefaultDescriptionTuple 

38from .dml import isinsert as _compile_state_isinsert 

39from .elements import ColumnClause 

40from .schema import default_is_clause_element 

41from .schema import default_is_sequence 

42from .selectable import Select 

43from .selectable import TableClause 

44from .. import exc 

45from .. import util 

46from ..util.typing import Literal 

47 

48if TYPE_CHECKING: 

49 from .compiler import _BindNameForColProtocol 

50 from .compiler import SQLCompiler 

51 from .dml import _DMLColumnElement 

52 from .dml import DMLState 

53 from .dml import ValuesBase 

54 from .elements import ColumnElement 

55 from .elements import KeyedColumnElement 

56 from .schema import _SQLExprDefault 

57 from .schema import Column 

58 

59REQUIRED = util.symbol( 

60 "REQUIRED", 

61 """ 

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

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

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

65 

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

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

68values present. 

69 

70""", 

71) 

72 

73 

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

75 if not isinstance(c, ColumnClause): 

76 raise exc.CompileError( 

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

78 ) 

79 return c 

80 

81 

82_CrudParamElement = Tuple[ 

83 "ColumnElement[Any]", 

84 str, # column name 

85 Optional[ 

86 Union[str, "_SQLExprDefault"] 

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

88 Iterable[str], 

89] 

90_CrudParamElementStr = Tuple[ 

91 "KeyedColumnElement[Any]", 

92 str, # column name 

93 str, # bound parameter string 

94 Iterable[str], 

95] 

96_CrudParamElementSQLExpr = Tuple[ 

97 "ColumnClause[Any]", 

98 str, 

99 "_SQLExprDefault", # SQL expression to apply 

100 Iterable[str], 

101] 

102 

103_CrudParamSequence = List[_CrudParamElement] 

104 

105 

106class _CrudParams(NamedTuple): 

107 single_params: _CrudParamSequence 

108 all_multi_params: List[Sequence[_CrudParamElementStr]] 

109 is_default_metavalue_only: bool = False 

110 use_insertmanyvalues: bool = False 

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

112 

113 

114def _get_crud_params( 

115 compiler: SQLCompiler, 

116 stmt: ValuesBase, 

117 compile_state: DMLState, 

118 toplevel: bool, 

119 **kw: Any, 

120) -> _CrudParams: 

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

122 in an INSERT or UPDATE statement. 

123 

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

125 returning column collections, used for default handling and ultimately 

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

127 collections. 

128 

129 """ 

130 

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

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

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

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

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

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

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

138 

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

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

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

142 

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

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

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

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

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

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

149 

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

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

152 # as well as here. 

153 

154 compiler.postfetch = [] 

155 compiler.insert_prefetch = [] 

156 compiler.update_prefetch = [] 

157 compiler.implicit_returning = [] 

158 

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

160 if visiting_cte is not None: 

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

162 # _crud_accumulate_bind_names collection; the INSERT we process here 

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

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

165 kw.pop("accumulate_bind_names", None) 

166 assert ( 

167 "accumulate_bind_names" not in kw 

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

169 

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

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

172 # .key must conditionally take tablename into account 

173 ( 

174 _column_as_key, 

175 _getattr_col_key, 

176 _col_bind_name, 

177 ) = _key_getters_for_crud_column(compiler, stmt, compile_state) 

178 

179 compiler._get_bind_name_for_col = _col_bind_name 

180 

181 if stmt._returning and stmt._return_defaults: 

182 raise exc.CompileError( 

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

184 "return_defaults() simultaneously" 

185 ) 

186 

187 if compile_state.isdelete: 

188 _setup_delete_return_defaults( 

189 compiler, 

190 stmt, 

191 compile_state, 

192 (), 

193 _getattr_col_key, 

194 _column_as_key, 

195 _col_bind_name, 

196 (), 

197 (), 

198 toplevel, 

199 kw, 

200 ) 

201 return _CrudParams([], []) 

202 

203 # no parameters in the statement, no parameters in the 

204 # compiled params - return binds for all columns 

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

206 return _CrudParams( 

207 [ 

208 ( 

209 c, 

210 compiler.preparer.format_column(c), 

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

212 (c.key,), 

213 ) 

214 for c in stmt.table.columns 

215 if not c._omit_from_statements 

216 ], 

217 [], 

218 ) 

219 

220 stmt_parameter_tuples: Optional[ 

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

222 ] 

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

224 

225 if ( 

226 _compile_state_isinsert(compile_state) 

227 and compile_state._has_multi_parameters 

228 ): 

229 mp = compile_state._multi_parameters 

230 assert mp is not None 

231 spd = mp[0] 

232 stmt_parameter_tuples = list(spd.items()) 

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

234 elif compile_state._ordered_values: 

235 spd = compile_state._dict_parameters 

236 stmt_parameter_tuples = compile_state._ordered_values 

237 assert spd is not None 

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

239 elif compile_state._dict_parameters: 

240 spd = compile_state._dict_parameters 

241 stmt_parameter_tuples = list(spd.items()) 

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

243 else: 

244 stmt_parameter_tuples = spd_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 return _CrudParams(values, multi_extended_values) 

406 elif ( 

407 not values 

408 and compiler.for_executemany 

409 and compiler.dialect.supports_default_metavalue 

410 ): 

411 # convert an "INSERT DEFAULT VALUES" 

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

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

414 # insert_executemany_returning mode :) 

415 values = [ 

416 ( 

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

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

419 compiler.dialect.default_metavalue_token, 

420 (), 

421 ) 

422 ] 

423 is_default_metavalue_only = True 

424 

425 return _CrudParams( 

426 values, 

427 [], 

428 is_default_metavalue_only=is_default_metavalue_only, 

429 use_insertmanyvalues=use_insertmanyvalues, 

430 use_sentinel_columns=use_sentinel_columns, 

431 ) 

432 

433 

434@overload 

435def _create_bind_param( 

436 compiler: SQLCompiler, 

437 col: ColumnElement[Any], 

438 value: Any, 

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

440 required: bool = False, 

441 name: Optional[str] = None, 

442 force_anonymous: bool = False, 

443 **kw: Any, 

444) -> str: ... 

445 

446 

447@overload 

448def _create_bind_param( 

449 compiler: SQLCompiler, 

450 col: ColumnElement[Any], 

451 value: Any, 

452 **kw: Any, 

453) -> str: ... 

454 

455 

456def _create_bind_param( 

457 compiler: SQLCompiler, 

458 col: ColumnElement[Any], 

459 value: Any, 

460 process: bool = True, 

461 required: bool = False, 

462 name: Optional[str] = None, 

463 force_anonymous: bool = False, 

464 **kw: Any, 

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

466 if force_anonymous: 

467 name = None 

468 elif name is None: 

469 name = col.key 

470 

471 bindparam = elements.BindParameter( 

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

473 ) 

474 bindparam._is_crud = True 

475 if process: 

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

477 else: 

478 return bindparam 

479 

480 

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

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

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

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

485 # produce bound parameters in deterministic order without invoking any 

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

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

488 # right now). 

489 # 

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

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

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

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

494 # rather than having 

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

496 # name. Saves on call counts also. 

497 

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

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

500 # multiple insert/update are combined together using CTEs 

501 is_cte = "visiting_cte" in kw 

502 

503 if ( 

504 not is_cte 

505 and value.unique 

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

507 ): 

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

509 

510 if value.type._isnull: 

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

512 # passed in directly 

513 # set type to that of the column unconditionally 

514 value = value._with_binary_element_type(col.type) 

515 

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

517 

518 

519def _key_getters_for_crud_column( 

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

521) -> Tuple[ 

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

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

524 _BindNameForColProtocol, 

525]: 

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

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

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

529 # dictionaries and when rendering bind param names. 

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

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

532 # statement. 

533 _et = set(compile_state._extra_froms) 

534 

535 c_key_role = functools.partial( 

536 coercions.expect_as_key, roles.DMLColumnRole 

537 ) 

538 

539 def _column_as_key( 

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

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

542 str_key = c_key_role(key) 

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

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

545 else: 

546 return str_key 

547 

548 def _getattr_col_key( 

549 col: ColumnClause[Any], 

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

551 if col.table in _et: 

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

553 else: 

554 return col.key 

555 

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

557 if col.table in _et: 

558 if TYPE_CHECKING: 

559 assert isinstance(col.table, TableClause) 

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

561 else: 

562 return col.key 

563 

564 else: 

565 _column_as_key = functools.partial( 

566 coercions.expect_as_key, roles.DMLColumnRole 

567 ) 

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

569 

570 return _column_as_key, _getattr_col_key, _col_bind_name 

571 

572 

573def _scan_insert_from_select_cols( 

574 compiler, 

575 stmt, 

576 compile_state, 

577 parameters, 

578 _getattr_col_key, 

579 _column_as_key, 

580 _col_bind_name, 

581 check_columns, 

582 values, 

583 toplevel, 

584 kw, 

585): 

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

587 

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

589 

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

591 

592 add_select_cols: List[_CrudParamElementSQLExpr] = [] 

593 if stmt.include_insert_from_select_defaults: 

594 col_set = set(cols) 

595 for col in stmt.table.columns: 

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

597 # this will omit columns marked as omit_from_statements naturally, 

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

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

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

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

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

603 # here so we again omit it. 

604 if ( 

605 col not in col_set 

606 and col.default 

607 and not col.default.is_sentinel 

608 ): 

609 cols.append(col) 

610 

611 for c in cols: 

612 col_key = _getattr_col_key(c) 

613 if col_key in parameters and col_key not in check_columns: 

614 parameters.pop(col_key) 

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

616 else: 

617 _append_param_insert_select_hasdefault( 

618 compiler, stmt, c, add_select_cols, kw 

619 ) 

620 

621 if add_select_cols: 

622 values.extend(add_select_cols) 

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

624 if not isinstance(ins_from_select, Select): 

625 raise exc.CompileError( 

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

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

628 f"""{ 

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

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

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

632 "columns." 

633 ) 

634 ins_from_select = ins_from_select._generate() 

635 # copy raw_columns 

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

637 expr for _, _, expr, _ in add_select_cols 

638 ] 

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

640 

641 

642def _scan_cols( 

643 compiler, 

644 stmt, 

645 compile_state, 

646 parameters, 

647 _getattr_col_key, 

648 _column_as_key, 

649 _col_bind_name, 

650 check_columns, 

651 values, 

652 toplevel, 

653 kw, 

654): 

655 ( 

656 need_pks, 

657 implicit_returning, 

658 implicit_return_defaults, 

659 postfetch_lastrowid, 

660 use_insertmanyvalues, 

661 use_sentinel_columns, 

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

663 

664 assert compile_state.isupdate or compile_state.isinsert 

665 

666 if compile_state._parameter_ordering: 

667 parameter_ordering = [ 

668 _column_as_key(key) for key in compile_state._parameter_ordering 

669 ] 

670 ordered_keys = set(parameter_ordering) 

671 cols = [ 

672 stmt.table.c[key] 

673 for key in parameter_ordering 

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

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

676 

677 else: 

678 cols = stmt.table.columns 

679 

680 isinsert = _compile_state_isinsert(compile_state) 

681 if isinsert and not compile_state._has_multi_parameters: 

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

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

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

685 autoincrement_col = stmt.table._autoincrement_column 

686 insert_null_pk_still_autoincrements = ( 

687 compiler.dialect.insert_null_pk_still_autoincrements 

688 ) 

689 else: 

690 autoincrement_col = insert_null_pk_still_autoincrements = None 

691 

692 if stmt._supplemental_returning: 

693 supplemental_returning = set(stmt._supplemental_returning) 

694 else: 

695 supplemental_returning = set() 

696 

697 compiler_implicit_returning = compiler.implicit_returning 

698 

699 # TODO - see TODO(return_defaults_columns) below 

700 # cols_in_params = set() 

701 

702 for c in cols: 

703 # scan through every column in the target table 

704 

705 col_key = _getattr_col_key(c) 

706 

707 if col_key in parameters and col_key not in check_columns: 

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

709 

710 _append_param_parameter( 

711 compiler, 

712 stmt, 

713 compile_state, 

714 c, 

715 col_key, 

716 parameters, 

717 _col_bind_name, 

718 implicit_returning, 

719 implicit_return_defaults, 

720 postfetch_lastrowid, 

721 values, 

722 autoincrement_col, 

723 insert_null_pk_still_autoincrements, 

724 kw, 

725 ) 

726 

727 # TODO - see TODO(return_defaults_columns) below 

728 # cols_in_params.add(c) 

729 

730 elif isinsert: 

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

732 

733 if c.primary_key and need_pks: 

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

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

736 # inserted_primary_key to be available. 

737 

738 if implicit_returning: 

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

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

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

742 

743 _append_param_insert_pk_returning( 

744 compiler, stmt, c, values, kw 

745 ) 

746 else: 

747 # otherwise, find out how to invoke this column 

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

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

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

751 # autoincrement column and the dialect supports it 

752 # we can use cursor.lastrowid. 

753 

754 _append_param_insert_pk_no_returning( 

755 compiler, stmt, c, values, kw 

756 ) 

757 

758 elif c.default is not None: 

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

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

761 if not c.default.is_sentinel or ( 

762 use_sentinel_columns is not None 

763 ): 

764 _append_param_insert_hasdefault( 

765 compiler, stmt, c, implicit_return_defaults, values, kw 

766 ) 

767 

768 elif c.server_default is not None: 

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

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

771 if implicit_return_defaults and c in implicit_return_defaults: 

772 compiler_implicit_returning.append(c) 

773 elif not c.primary_key: 

774 compiler.postfetch.append(c) 

775 

776 elif implicit_return_defaults and c in implicit_return_defaults: 

777 compiler_implicit_returning.append(c) 

778 

779 elif ( 

780 c.primary_key 

781 and c is not stmt.table._autoincrement_column 

782 and not c.nullable 

783 ): 

784 _warn_pk_with_no_anticipated_value(c) 

785 

786 elif compile_state.isupdate: 

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

788 

789 _append_param_update( 

790 compiler, 

791 compile_state, 

792 stmt, 

793 c, 

794 implicit_return_defaults, 

795 values, 

796 kw, 

797 ) 

798 

799 # adding supplemental cols to implicit_returning in table 

800 # order so that order is maintained between multiple INSERT 

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

802 # have the same RETURNING clause 

803 if ( 

804 c in supplemental_returning 

805 and c not in compiler_implicit_returning 

806 ): 

807 compiler_implicit_returning.append(c) 

808 

809 if supplemental_returning: 

810 # we should have gotten every col into implicit_returning, 

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

812 # in it 

813 remaining_supplemental = supplemental_returning.difference( 

814 compiler_implicit_returning 

815 ) 

816 compiler_implicit_returning.extend( 

817 c 

818 for c in stmt._supplemental_returning 

819 if c in remaining_supplemental 

820 ) 

821 

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

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

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

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

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

827 

828 # if stmt._return_defaults_columns: 

829 # compiler_implicit_returning.extend( 

830 # set(stmt._return_defaults_columns) 

831 # .difference(compiler_implicit_returning) 

832 # .difference(cols_in_params) 

833 # ) 

834 

835 return (use_insertmanyvalues, use_sentinel_columns) 

836 

837 

838def _setup_delete_return_defaults( 

839 compiler, 

840 stmt, 

841 compile_state, 

842 parameters, 

843 _getattr_col_key, 

844 _column_as_key, 

845 _col_bind_name, 

846 check_columns, 

847 values, 

848 toplevel, 

849 kw, 

850): 

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

852 compiler, stmt, compile_state, toplevel 

853 ) 

854 

855 if not implicit_return_defaults: 

856 return 

857 

858 if stmt._return_defaults_columns: 

859 compiler.implicit_returning.extend(implicit_return_defaults) 

860 

861 if stmt._supplemental_returning: 

862 ir_set = set(compiler.implicit_returning) 

863 compiler.implicit_returning.extend( 

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

865 ) 

866 

867 

868def _append_param_parameter( 

869 compiler, 

870 stmt, 

871 compile_state, 

872 c, 

873 col_key, 

874 parameters, 

875 _col_bind_name, 

876 implicit_returning, 

877 implicit_return_defaults, 

878 postfetch_lastrowid, 

879 values, 

880 autoincrement_col, 

881 insert_null_pk_still_autoincrements, 

882 kw, 

883): 

884 value = parameters.pop(col_key) 

885 

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

887 col_value = compiler.preparer.format_column( 

888 c, use_table=compile_state.include_table_with_column_exprs 

889 ) 

890 

891 accumulated_bind_names: Set[str] = set() 

892 

893 if coercions._is_literal(value): 

894 if ( 

895 insert_null_pk_still_autoincrements 

896 and c.primary_key 

897 and c is autoincrement_col 

898 ): 

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

900 # even if value was given. 

901 

902 if postfetch_lastrowid: 

903 compiler.postfetch_lastrowid = True 

904 elif implicit_returning: 

905 compiler.implicit_returning.append(c) 

906 

907 value = _create_bind_param( 

908 compiler, 

909 c, 

910 value, 

911 required=value is REQUIRED, 

912 name=( 

913 _col_bind_name(c) 

914 if not _compile_state_isinsert(compile_state) 

915 or not compile_state._has_multi_parameters 

916 else "%s_m0" % _col_bind_name(c) 

917 ), 

918 accumulate_bind_names=accumulated_bind_names, 

919 force_anonymous=has_visiting_cte, 

920 **kw, 

921 ) 

922 elif value._is_bind_parameter: 

923 if ( 

924 insert_null_pk_still_autoincrements 

925 and value.value is None 

926 and c.primary_key 

927 and c is autoincrement_col 

928 ): 

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

930 # even if value was given 

931 if implicit_returning: 

932 compiler.implicit_returning.append(c) 

933 elif compiler.dialect.postfetch_lastrowid: 

934 compiler.postfetch_lastrowid = True 

935 

936 value = _handle_values_anonymous_param( 

937 compiler, 

938 c, 

939 value, 

940 name=( 

941 _col_bind_name(c) 

942 if not _compile_state_isinsert(compile_state) 

943 or not compile_state._has_multi_parameters 

944 else "%s_m0" % _col_bind_name(c) 

945 ), 

946 accumulate_bind_names=accumulated_bind_names, 

947 **kw, 

948 ) 

949 else: 

950 # value is a SQL expression 

951 value = compiler.process( 

952 value.self_group(), 

953 accumulate_bind_names=accumulated_bind_names, 

954 **kw, 

955 ) 

956 

957 if compile_state.isupdate: 

958 if implicit_return_defaults and c in implicit_return_defaults: 

959 compiler.implicit_returning.append(c) 

960 

961 else: 

962 compiler.postfetch.append(c) 

963 else: 

964 if c.primary_key: 

965 if implicit_returning: 

966 compiler.implicit_returning.append(c) 

967 elif compiler.dialect.postfetch_lastrowid: 

968 compiler.postfetch_lastrowid = True 

969 

970 elif implicit_return_defaults and (c in implicit_return_defaults): 

971 compiler.implicit_returning.append(c) 

972 

973 else: 

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

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

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

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

978 # time. 

979 

980 compiler.postfetch.append(c) 

981 

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

983 

984 

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

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

987 we want to populate result.inserted_primary_key and RETURNING 

988 is available. 

989 

990 """ 

991 if c.default is not None: 

992 if c.default.is_sequence: 

993 if compiler.dialect.supports_sequences and ( 

994 not c.default.optional 

995 or not compiler.dialect.sequences_optional 

996 ): 

997 accumulated_bind_names: Set[str] = set() 

998 values.append( 

999 ( 

1000 c, 

1001 compiler.preparer.format_column(c), 

1002 compiler.process( 

1003 c.default, 

1004 accumulate_bind_names=accumulated_bind_names, 

1005 **kw, 

1006 ), 

1007 accumulated_bind_names, 

1008 ) 

1009 ) 

1010 compiler.implicit_returning.append(c) 

1011 elif c.default.is_clause_element: 

1012 accumulated_bind_names = set() 

1013 values.append( 

1014 ( 

1015 c, 

1016 compiler.preparer.format_column(c), 

1017 compiler.process( 

1018 c.default.arg.self_group(), 

1019 accumulate_bind_names=accumulated_bind_names, 

1020 **kw, 

1021 ), 

1022 accumulated_bind_names, 

1023 ) 

1024 ) 

1025 compiler.implicit_returning.append(c) 

1026 else: 

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

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

1029 # on the Python side 

1030 values.append( 

1031 ( 

1032 c, 

1033 compiler.preparer.format_column(c), 

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

1035 (c.key,), 

1036 ) 

1037 ) 

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

1039 compiler.implicit_returning.append(c) 

1040 elif not c.nullable: 

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

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

1043 _warn_pk_with_no_anticipated_value(c) 

1044 

1045 

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

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

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

1049 RETURNING. 

1050 

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

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

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

1054 

1055 

1056 """ 

1057 

1058 if ( 

1059 # column has a Python-side default 

1060 c.default is not None 

1061 and ( 

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

1063 # sequences and want to invoke it 

1064 not c.default.is_sequence 

1065 or ( 

1066 compiler.dialect.supports_sequences 

1067 and ( 

1068 not c.default.optional 

1069 or not compiler.dialect.sequences_optional 

1070 ) 

1071 ) 

1072 ) 

1073 ) or ( 

1074 # column is the "autoincrement column" 

1075 c is stmt.table._autoincrement_column 

1076 and ( 

1077 # dialect can't use cursor.lastrowid 

1078 not compiler.dialect.postfetch_lastrowid 

1079 and ( 

1080 # column has a Sequence and we support those 

1081 ( 

1082 c.default is not None 

1083 and c.default.is_sequence 

1084 and compiler.dialect.supports_sequences 

1085 ) 

1086 or 

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

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

1089 # SERIAL we know the sequence name 

1090 ( 

1091 c.default is None 

1092 and compiler.dialect.preexecute_autoincrement_sequences 

1093 ) 

1094 ) 

1095 ) 

1096 ): 

1097 # do a pre-execute of the default 

1098 values.append( 

1099 ( 

1100 c, 

1101 compiler.preparer.format_column(c), 

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

1103 (c.key,), 

1104 ) 

1105 ) 

1106 elif ( 

1107 c.default is None 

1108 and c.server_default is None 

1109 and not c.nullable 

1110 and c is not stmt.table._autoincrement_column 

1111 ): 

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

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

1114 _warn_pk_with_no_anticipated_value(c) 

1115 elif compiler.dialect.postfetch_lastrowid: 

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

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

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

1119 # that the DefaultExecutionContext calls upon cursor.lastrowid 

1120 compiler.postfetch_lastrowid = True 

1121 

1122 

1123def _append_param_insert_hasdefault( 

1124 compiler, stmt, c, implicit_return_defaults, values, kw 

1125): 

1126 if c.default.is_sequence: 

1127 if compiler.dialect.supports_sequences and ( 

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

1129 ): 

1130 accumulated_bind_names: Set[str] = set() 

1131 values.append( 

1132 ( 

1133 c, 

1134 compiler.preparer.format_column(c), 

1135 compiler.process( 

1136 c.default, 

1137 accumulate_bind_names=accumulated_bind_names, 

1138 **kw, 

1139 ), 

1140 accumulated_bind_names, 

1141 ) 

1142 ) 

1143 if implicit_return_defaults and c in implicit_return_defaults: 

1144 compiler.implicit_returning.append(c) 

1145 elif not c.primary_key: 

1146 compiler.postfetch.append(c) 

1147 elif c.default.is_clause_element: 

1148 accumulated_bind_names = set() 

1149 values.append( 

1150 ( 

1151 c, 

1152 compiler.preparer.format_column(c), 

1153 compiler.process( 

1154 c.default.arg.self_group(), 

1155 accumulate_bind_names=accumulated_bind_names, 

1156 **kw, 

1157 ), 

1158 accumulated_bind_names, 

1159 ) 

1160 ) 

1161 

1162 if implicit_return_defaults and c in implicit_return_defaults: 

1163 compiler.implicit_returning.append(c) 

1164 elif not c.primary_key: 

1165 # don't add primary key column to postfetch 

1166 compiler.postfetch.append(c) 

1167 else: 

1168 values.append( 

1169 ( 

1170 c, 

1171 compiler.preparer.format_column(c), 

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

1173 (c.key,), 

1174 ) 

1175 ) 

1176 

1177 

1178def _append_param_insert_select_hasdefault( 

1179 compiler: SQLCompiler, 

1180 stmt: ValuesBase, 

1181 c: ColumnClause[Any], 

1182 values: List[_CrudParamElementSQLExpr], 

1183 kw: Dict[str, Any], 

1184) -> None: 

1185 if default_is_sequence(c.default): 

1186 if compiler.dialect.supports_sequences and ( 

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

1188 ): 

1189 values.append( 

1190 ( 

1191 c, 

1192 compiler.preparer.format_column(c), 

1193 c.default.next_value(), 

1194 (), 

1195 ) 

1196 ) 

1197 elif default_is_clause_element(c.default): 

1198 values.append( 

1199 ( 

1200 c, 

1201 compiler.preparer.format_column(c), 

1202 c.default.arg.self_group(), 

1203 (), 

1204 ) 

1205 ) 

1206 else: 

1207 values.append( 

1208 ( 

1209 c, 

1210 compiler.preparer.format_column(c), 

1211 _create_insert_prefetch_bind_param( 

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

1213 ), 

1214 (c.key,), 

1215 ) 

1216 ) 

1217 

1218 

1219def _append_param_update( 

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

1221): 

1222 include_table = compile_state.include_table_with_column_exprs 

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

1224 if c.onupdate.is_clause_element: 

1225 values.append( 

1226 ( 

1227 c, 

1228 compiler.preparer.format_column( 

1229 c, 

1230 use_table=include_table, 

1231 ), 

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

1233 (), 

1234 ) 

1235 ) 

1236 if implicit_return_defaults and c in implicit_return_defaults: 

1237 compiler.implicit_returning.append(c) 

1238 else: 

1239 compiler.postfetch.append(c) 

1240 else: 

1241 values.append( 

1242 ( 

1243 c, 

1244 compiler.preparer.format_column( 

1245 c, 

1246 use_table=include_table, 

1247 ), 

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

1249 (c.key,), 

1250 ) 

1251 ) 

1252 elif c.server_onupdate is not None: 

1253 if implicit_return_defaults and c in implicit_return_defaults: 

1254 compiler.implicit_returning.append(c) 

1255 else: 

1256 compiler.postfetch.append(c) 

1257 elif ( 

1258 implicit_return_defaults 

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

1260 and c in implicit_return_defaults 

1261 ): 

1262 compiler.implicit_returning.append(c) 

1263 

1264 

1265@overload 

1266def _create_insert_prefetch_bind_param( 

1267 compiler: SQLCompiler, 

1268 c: ColumnElement[Any], 

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

1270 **kw: Any, 

1271) -> str: ... 

1272 

1273 

1274@overload 

1275def _create_insert_prefetch_bind_param( 

1276 compiler: SQLCompiler, 

1277 c: ColumnElement[Any], 

1278 process: Literal[False], 

1279 **kw: Any, 

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

1281 

1282 

1283def _create_insert_prefetch_bind_param( 

1284 compiler: SQLCompiler, 

1285 c: ColumnElement[Any], 

1286 process: bool = True, 

1287 name: Optional[str] = None, 

1288 **kw: Any, 

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

1290 param = _create_bind_param( 

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

1292 ) 

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

1294 return param 

1295 

1296 

1297@overload 

1298def _create_update_prefetch_bind_param( 

1299 compiler: SQLCompiler, 

1300 c: ColumnElement[Any], 

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

1302 **kw: Any, 

1303) -> str: ... 

1304 

1305 

1306@overload 

1307def _create_update_prefetch_bind_param( 

1308 compiler: SQLCompiler, 

1309 c: ColumnElement[Any], 

1310 process: Literal[False], 

1311 **kw: Any, 

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

1313 

1314 

1315def _create_update_prefetch_bind_param( 

1316 compiler: SQLCompiler, 

1317 c: ColumnElement[Any], 

1318 process: bool = True, 

1319 name: Optional[str] = None, 

1320 **kw: Any, 

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

1322 param = _create_bind_param( 

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

1324 ) 

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

1326 return param 

1327 

1328 

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

1330 _is_multiparam_column = True 

1331 

1332 def __init__(self, original, index): 

1333 self.index = index 

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

1335 self.original = original 

1336 self.default = original.default 

1337 self.type = original.type 

1338 

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

1340 raise NotImplementedError() 

1341 

1342 def _copy_internals(self, **kw): 

1343 raise NotImplementedError() 

1344 

1345 def __eq__(self, other): 

1346 return ( 

1347 isinstance(other, _multiparam_column) 

1348 and other.key == self.key 

1349 and other.original == self.original 

1350 ) 

1351 

1352 @util.memoized_property 

1353 def _default_description_tuple(self) -> _DefaultDescriptionTuple: 

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

1355 

1356 return _DefaultDescriptionTuple._from_column_default(self.default) 

1357 

1358 @util.memoized_property 

1359 def _onupdate_description_tuple(self) -> _DefaultDescriptionTuple: 

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

1361 

1362 return _DefaultDescriptionTuple._from_column_default(self.onupdate) 

1363 

1364 

1365def _process_multiparam_default_bind( 

1366 compiler: SQLCompiler, 

1367 stmt: ValuesBase, 

1368 c: KeyedColumnElement[Any], 

1369 index: int, 

1370 kw: Dict[str, Any], 

1371) -> str: 

1372 if not c.default: 

1373 raise exc.CompileError( 

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

1375 "parameter in the VALUES clause; " 

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

1377 ) 

1378 elif default_is_clause_element(c.default): 

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

1380 elif c.default.is_sequence: 

1381 # these conditions would have been established 

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

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

1384 # checked 

1385 # assert compiler.dialect.supports_sequences and ( 

1386 # not c.default.optional 

1387 # or not compiler.dialect.sequences_optional 

1388 # ) 

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

1390 else: 

1391 col = _multiparam_column(c, index) 

1392 assert isinstance(stmt, dml.Insert) 

1393 return _create_insert_prefetch_bind_param( 

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

1395 ) 

1396 

1397 

1398def _get_update_multitable_params( 

1399 compiler, 

1400 stmt, 

1401 compile_state, 

1402 stmt_parameter_tuples, 

1403 check_columns, 

1404 _col_bind_name, 

1405 _getattr_col_key, 

1406 values, 

1407 kw, 

1408): 

1409 normalized_params = { 

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

1411 for c, param in stmt_parameter_tuples or () 

1412 } 

1413 

1414 include_table = compile_state.include_table_with_column_exprs 

1415 

1416 affected_tables = set() 

1417 for t in compile_state._extra_froms: 

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

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

1420 # supported 

1421 we_shouldnt_be_here_if_columns_found = ( 

1422 not include_table 

1423 and not compile_state.dml_table.is_derived_from(t) 

1424 ) 

1425 

1426 for c in t.c: 

1427 if c in normalized_params: 

1428 

1429 if we_shouldnt_be_here_if_columns_found: 

1430 raise exc.CompileError( 

1431 "Backend does not support additional tables " 

1432 "in the SET " 

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

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

1435 "SET clause" 

1436 ) 

1437 

1438 affected_tables.add(t) 

1439 

1440 check_columns[_getattr_col_key(c)] = c 

1441 value = normalized_params[c] 

1442 

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

1444 if coercions._is_literal(value): 

1445 value = _create_bind_param( 

1446 compiler, 

1447 c, 

1448 value, 

1449 required=value is REQUIRED, 

1450 name=_col_bind_name(c), 

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

1452 ) 

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

1454 elif value._is_bind_parameter: 

1455 cbn = _col_bind_name(c) 

1456 value = _handle_values_anonymous_param( 

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

1458 ) 

1459 accumulated_bind_names = (cbn,) 

1460 else: 

1461 compiler.postfetch.append(c) 

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

1463 accumulated_bind_names = () 

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

1465 

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

1467 # and server_onupdate for these 

1468 for t in affected_tables: 

1469 for c in t.c: 

1470 if c in normalized_params: 

1471 continue 

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

1473 if c.onupdate.is_clause_element: 

1474 values.append( 

1475 ( 

1476 c, 

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

1478 compiler.process( 

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

1480 ), 

1481 (), 

1482 ) 

1483 ) 

1484 compiler.postfetch.append(c) 

1485 else: 

1486 values.append( 

1487 ( 

1488 c, 

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

1490 _create_update_prefetch_bind_param( 

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

1492 ), 

1493 (c.key,), 

1494 ) 

1495 ) 

1496 elif c.server_onupdate is not None: 

1497 compiler.postfetch.append(c) 

1498 

1499 

1500def _extend_values_for_multiparams( 

1501 compiler: SQLCompiler, 

1502 stmt: ValuesBase, 

1503 compile_state: DMLState, 

1504 initial_values: Sequence[_CrudParamElementStr], 

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

1506 kw: Dict[str, Any], 

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

1508 values_0 = initial_values 

1509 values = [initial_values] 

1510 

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

1512 mp = compile_state._multi_parameters 

1513 assert mp is not None 

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

1515 extension: List[_CrudParamElementStr] = [] 

1516 

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

1518 

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

1520 if col.key in row: 

1521 key = col.key 

1522 

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

1524 new_param = _create_bind_param( 

1525 compiler, 

1526 col, 

1527 row[key], 

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

1529 force_anonymous=has_visiting_cte, 

1530 **kw, 

1531 ) 

1532 else: 

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

1534 else: 

1535 new_param = _process_multiparam_default_bind( 

1536 compiler, stmt, col, i, kw 

1537 ) 

1538 

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

1540 

1541 values.append(extension) 

1542 

1543 return values 

1544 

1545 

1546def _get_stmt_parameter_tuples_params( 

1547 compiler, 

1548 compile_state, 

1549 parameters, 

1550 stmt_parameter_tuples, 

1551 _column_as_key, 

1552 values, 

1553 kw, 

1554): 

1555 for k, v in stmt_parameter_tuples: 

1556 colkey = _column_as_key(k) 

1557 if colkey is not None: 

1558 parameters.setdefault(colkey, v) 

1559 else: 

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

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

1562 # coercing right side to bound param 

1563 

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

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

1566 

1567 col_expr = compiler.process( 

1568 k, include_table=compile_state.include_table_with_column_exprs 

1569 ) 

1570 

1571 if coercions._is_literal(v): 

1572 v = compiler.process( 

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

1574 ) 

1575 else: 

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

1577 # either unique parameter, or other bound parameters that 

1578 # were passed in directly 

1579 # set type to that of the column unconditionally 

1580 v = v._with_binary_element_type(k.type) 

1581 

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

1583 

1584 # TODO: not sure if accumulated_bind_names applies here 

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

1586 

1587 

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

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

1590 

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

1592 INSERT or UPDATE statement after it's invoked. 

1593 

1594 """ 

1595 

1596 dialect = compiler.dialect 

1597 

1598 need_pks = ( 

1599 toplevel 

1600 and _compile_state_isinsert(compile_state) 

1601 and not stmt._inline 

1602 and ( 

1603 not compiler.for_executemany 

1604 or (dialect.insert_executemany_returning and stmt._return_defaults) 

1605 ) 

1606 and not stmt._returning 

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

1608 and not compile_state._has_multi_parameters 

1609 ) 

1610 

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

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

1613 postfetch_lastrowid = ( 

1614 need_pks 

1615 and dialect.postfetch_lastrowid 

1616 and stmt.table._autoincrement_column is not None 

1617 ) 

1618 

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

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

1621 # if that's set. 

1622 implicit_returning = ( 

1623 # statement itself can veto it 

1624 need_pks 

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

1626 # with INSERT 

1627 and dialect.insert_returning 

1628 # user-defined implicit_returning on Table can veto it 

1629 and compile_state._primary_table.implicit_returning 

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

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

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

1633 and compile_state._supports_implicit_returning 

1634 and ( 

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

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

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

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

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

1640 # SQLite lastrowid times 3x faster than returning, 

1641 # Mariadb lastrowid 2x faster than returning 

1642 (not postfetch_lastrowid or dialect.favor_returning_over_lastrowid) 

1643 or compile_state._has_multi_parameters 

1644 or stmt._return_defaults 

1645 ) 

1646 ) 

1647 if implicit_returning: 

1648 postfetch_lastrowid = False 

1649 

1650 if _compile_state_isinsert(compile_state): 

1651 should_implicit_return_defaults = ( 

1652 implicit_returning and stmt._return_defaults 

1653 ) 

1654 explicit_returning = ( 

1655 should_implicit_return_defaults 

1656 or stmt._returning 

1657 or stmt._supplemental_returning 

1658 ) 

1659 use_insertmanyvalues = ( 

1660 toplevel 

1661 and compiler.for_executemany 

1662 and dialect.use_insertmanyvalues 

1663 and ( 

1664 explicit_returning or dialect.use_insertmanyvalues_wo_returning 

1665 ) 

1666 ) 

1667 

1668 use_sentinel_columns = None 

1669 if ( 

1670 use_insertmanyvalues 

1671 and explicit_returning 

1672 and stmt._sort_by_parameter_order 

1673 ): 

1674 use_sentinel_columns = compiler._get_sentinel_column_for_table( 

1675 stmt.table 

1676 ) 

1677 

1678 elif compile_state.isupdate: 

1679 should_implicit_return_defaults = ( 

1680 stmt._return_defaults 

1681 and compile_state._primary_table.implicit_returning 

1682 and compile_state._supports_implicit_returning 

1683 and dialect.update_returning 

1684 ) 

1685 use_insertmanyvalues = False 

1686 use_sentinel_columns = None 

1687 elif compile_state.isdelete: 

1688 should_implicit_return_defaults = ( 

1689 stmt._return_defaults 

1690 and compile_state._primary_table.implicit_returning 

1691 and compile_state._supports_implicit_returning 

1692 and dialect.delete_returning 

1693 ) 

1694 use_insertmanyvalues = False 

1695 use_sentinel_columns = None 

1696 else: 

1697 should_implicit_return_defaults = False # pragma: no cover 

1698 use_insertmanyvalues = False 

1699 use_sentinel_columns = None 

1700 

1701 if should_implicit_return_defaults: 

1702 if not stmt._return_defaults_columns: 

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

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

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

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

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

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

1709 implicit_return_defaults = set(stmt.table.c) 

1710 else: 

1711 implicit_return_defaults = set(stmt._return_defaults_columns) 

1712 else: 

1713 implicit_return_defaults = None 

1714 

1715 return ( 

1716 need_pks, 

1717 implicit_returning or should_implicit_return_defaults, 

1718 implicit_return_defaults, 

1719 postfetch_lastrowid, 

1720 use_insertmanyvalues, 

1721 use_sentinel_columns, 

1722 ) 

1723 

1724 

1725def _warn_pk_with_no_anticipated_value(c): 

1726 msg = ( 

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

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

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

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

1731 "and no explicit value is passed. " 

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

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

1734 ) 

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

1736 msg += ( 

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

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

1739 "keys if AUTO_INCREMENT/SERIAL/IDENTITY " 

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

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

1742 "most backends." 

1743 ) 

1744 util.warn(msg)