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

495 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._dict_parameters: 

235 spd = compile_state._dict_parameters 

236 stmt_parameter_tuples = list(spd.items()) 

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

238 else: 

239 stmt_parameter_tuples = spd_str_key = None 

240 

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

242 # compiled params 

243 if compiler.column_keys is None: 

244 parameters = {} 

245 elif stmt_parameter_tuples: 

246 assert spd_str_key is not None 

247 parameters = { 

248 _column_as_key(key): REQUIRED 

249 for key in compiler.column_keys 

250 if key not in spd_str_key 

251 } 

252 else: 

253 parameters = { 

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

255 } 

256 

257 # create a list of column assignment clauses as tuples 

258 values: List[_CrudParamElement] = [] 

259 

260 if stmt_parameter_tuples is not None: 

261 _get_stmt_parameter_tuples_params( 

262 compiler, 

263 compile_state, 

264 parameters, 

265 stmt_parameter_tuples, 

266 _column_as_key, 

267 values, 

268 kw, 

269 ) 

270 

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

272 

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

274 # statements 

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

276 _get_update_multitable_params( 

277 compiler, 

278 stmt, 

279 compile_state, 

280 stmt_parameter_tuples, 

281 check_columns, 

282 _col_bind_name, 

283 _getattr_col_key, 

284 values, 

285 kw, 

286 ) 

287 

288 if _compile_state_isinsert(compile_state) and stmt._select_names: 

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

290 

291 assert not compile_state._has_multi_parameters 

292 

293 _scan_insert_from_select_cols( 

294 compiler, 

295 stmt, 

296 compile_state, 

297 parameters, 

298 _getattr_col_key, 

299 _column_as_key, 

300 _col_bind_name, 

301 check_columns, 

302 values, 

303 toplevel, 

304 kw, 

305 ) 

306 use_insertmanyvalues = False 

307 use_sentinel_columns = None 

308 else: 

309 use_insertmanyvalues, use_sentinel_columns = _scan_cols( 

310 compiler, 

311 stmt, 

312 compile_state, 

313 parameters, 

314 _getattr_col_key, 

315 _column_as_key, 

316 _col_bind_name, 

317 check_columns, 

318 values, 

319 toplevel, 

320 kw, 

321 ) 

322 

323 if parameters and stmt_parameter_tuples: 

324 check = ( 

325 set(parameters) 

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

327 .difference(check_columns) 

328 ) 

329 if check: 

330 

331 if dml.isupdate(compile_state): 

332 tables_mentioned = set( 

333 c.table 

334 for c, v in stmt_parameter_tuples 

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

336 ).difference([compile_state.dml_table]) 

337 

338 multi_not_in_from = tables_mentioned.difference( 

339 compile_state._extra_froms 

340 ) 

341 

342 if tables_mentioned and ( 

343 not compile_state.is_multitable 

344 or not compiler.render_table_with_column_in_update_from 

345 ): 

346 if not compiler.render_table_with_column_in_update_from: 

347 preamble = ( 

348 "Backend does not support additional " 

349 "tables in the SET clause" 

350 ) 

351 else: 

352 preamble = ( 

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

354 ) 

355 

356 raise exc.CompileError( 

357 f"{preamble}; cannot " 

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

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

360 for t in tables_mentioned) 

361 } in SET clause""" 

362 ) 

363 

364 elif multi_not_in_from: 

365 assert compiler.render_table_with_column_in_update_from 

366 raise exc.CompileError( 

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

368 "table(s) " 

369 f"""{ 

370 ", ".join( 

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

372 t in multi_not_in_from) 

373 }""" 

374 ) 

375 

376 raise exc.CompileError( 

377 "Unconsumed column names: %s" 

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

379 ) 

380 

381 is_default_metavalue_only = False 

382 

383 if ( 

384 _compile_state_isinsert(compile_state) 

385 and compile_state._has_multi_parameters 

386 ): 

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

388 assert not stmt._select_names 

389 multi_extended_values = _extend_values_for_multiparams( 

390 compiler, 

391 stmt, 

392 compile_state, 

393 cast( 

394 "Sequence[_CrudParamElementStr]", 

395 values, 

396 ), 

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

398 kw, 

399 ) 

400 return _CrudParams(values, multi_extended_values) 

401 elif ( 

402 not values 

403 and compiler.for_executemany 

404 and compiler.dialect.supports_default_metavalue 

405 ): 

406 # convert an "INSERT DEFAULT VALUES" 

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

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

409 # insert_executemany_returning mode :) 

410 values = [ 

411 ( 

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

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

414 compiler.dialect.default_metavalue_token, 

415 (), 

416 ) 

417 ] 

418 is_default_metavalue_only = True 

419 

420 return _CrudParams( 

421 values, 

422 [], 

423 is_default_metavalue_only=is_default_metavalue_only, 

424 use_insertmanyvalues=use_insertmanyvalues, 

425 use_sentinel_columns=use_sentinel_columns, 

426 ) 

427 

428 

429@overload 

430def _create_bind_param( 

431 compiler: SQLCompiler, 

432 col: ColumnElement[Any], 

433 value: Any, 

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

435 required: bool = False, 

436 name: Optional[str] = None, 

437 force_anonymous: bool = False, 

438 **kw: Any, 

439) -> str: ... 

440 

441 

442@overload 

443def _create_bind_param( 

444 compiler: SQLCompiler, 

445 col: ColumnElement[Any], 

446 value: Any, 

447 **kw: Any, 

448) -> str: ... 

449 

450 

451def _create_bind_param( 

452 compiler: SQLCompiler, 

453 col: ColumnElement[Any], 

454 value: Any, 

455 process: bool = True, 

456 required: bool = False, 

457 name: Optional[str] = None, 

458 force_anonymous: bool = False, 

459 **kw: Any, 

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

461 if force_anonymous: 

462 name = None 

463 elif name is None: 

464 name = col.key 

465 

466 bindparam = elements.BindParameter( 

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

468 ) 

469 bindparam._is_crud = True 

470 if process: 

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

472 else: 

473 return bindparam 

474 

475 

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

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

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

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

480 # produce bound parameters in deterministic order without invoking any 

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

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

483 # right now). 

484 # 

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

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

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

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

489 # rather than having 

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

491 # name. Saves on call counts also. 

492 

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

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

495 # multiple insert/update are combined together using CTEs 

496 is_cte = "visiting_cte" in kw 

497 

498 if ( 

499 not is_cte 

500 and value.unique 

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

502 ): 

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

504 

505 if value.type._isnull: 

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

507 # passed in directly 

508 # set type to that of the column unconditionally 

509 value = value._with_binary_element_type(col.type) 

510 

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

512 

513 

514def _key_getters_for_crud_column( 

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

516) -> Tuple[ 

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

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

519 _BindNameForColProtocol, 

520]: 

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

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

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

524 # dictionaries and when rendering bind param names. 

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

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

527 # statement. 

528 _et = set(compile_state._extra_froms) 

529 

530 c_key_role = functools.partial( 

531 coercions.expect_as_key, roles.DMLColumnRole 

532 ) 

533 

534 def _column_as_key( 

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

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

537 str_key = c_key_role(key) 

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

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

540 else: 

541 return str_key 

542 

543 def _getattr_col_key( 

544 col: ColumnClause[Any], 

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

546 if col.table in _et: 

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

548 else: 

549 return col.key 

550 

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

552 if col.table in _et: 

553 if TYPE_CHECKING: 

554 assert isinstance(col.table, TableClause) 

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

556 else: 

557 return col.key 

558 

559 else: 

560 _column_as_key = functools.partial( 

561 coercions.expect_as_key, roles.DMLColumnRole 

562 ) 

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

564 

565 return _column_as_key, _getattr_col_key, _col_bind_name 

566 

567 

568def _scan_insert_from_select_cols( 

569 compiler, 

570 stmt, 

571 compile_state, 

572 parameters, 

573 _getattr_col_key, 

574 _column_as_key, 

575 _col_bind_name, 

576 check_columns, 

577 values, 

578 toplevel, 

579 kw, 

580): 

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

582 

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

584 

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

586 

587 add_select_cols: List[_CrudParamElementSQLExpr] = [] 

588 if stmt.include_insert_from_select_defaults: 

589 col_set = set(cols) 

590 for col in stmt.table.columns: 

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

592 # this will omit columns marked as omit_from_statements naturally, 

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

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

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

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

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

598 # here so we again omit it. 

599 if ( 

600 col not in col_set 

601 and col.default 

602 and not col.default.is_sentinel 

603 ): 

604 cols.append(col) 

605 

606 for c in cols: 

607 col_key = _getattr_col_key(c) 

608 if col_key in parameters and col_key not in check_columns: 

609 parameters.pop(col_key) 

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

611 else: 

612 _append_param_insert_select_hasdefault( 

613 compiler, stmt, c, add_select_cols, kw 

614 ) 

615 

616 if add_select_cols: 

617 values.extend(add_select_cols) 

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

619 if not isinstance(ins_from_select, Select): 

620 raise exc.CompileError( 

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

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

623 f"""{ 

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

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

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

627 "columns." 

628 ) 

629 ins_from_select = ins_from_select._generate() 

630 # copy raw_columns 

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

632 expr for _, _, expr, _ in add_select_cols 

633 ] 

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

635 

636 

637def _scan_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 ( 

651 need_pks, 

652 implicit_returning, 

653 implicit_return_defaults, 

654 postfetch_lastrowid, 

655 use_insertmanyvalues, 

656 use_sentinel_columns, 

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

658 

659 assert compile_state.isupdate or compile_state.isinsert 

660 

661 if compile_state._maintain_values_ordering: 

662 parameter_ordering = [ 

663 _column_as_key(key) for key in compile_state._dict_parameters 

664 ] 

665 ordered_keys = set(parameter_ordering) 

666 cols = [ 

667 stmt.table.c[key] 

668 for key in parameter_ordering 

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

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

671 

672 else: 

673 cols = stmt.table.columns 

674 

675 isinsert = _compile_state_isinsert(compile_state) 

676 if isinsert and not compile_state._has_multi_parameters: 

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

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

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

680 autoincrement_col = stmt.table._autoincrement_column 

681 insert_null_pk_still_autoincrements = ( 

682 compiler.dialect.insert_null_pk_still_autoincrements 

683 ) 

684 else: 

685 autoincrement_col = insert_null_pk_still_autoincrements = None 

686 

687 if stmt._supplemental_returning: 

688 supplemental_returning = set(stmt._supplemental_returning) 

689 else: 

690 supplemental_returning = set() 

691 

692 compiler_implicit_returning = compiler.implicit_returning 

693 

694 # TODO - see TODO(return_defaults_columns) below 

695 # cols_in_params = set() 

696 

697 for c in cols: 

698 # scan through every column in the target table 

699 

700 col_key = _getattr_col_key(c) 

701 

702 if col_key in parameters and col_key not in check_columns: 

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

704 

705 _append_param_parameter( 

706 compiler, 

707 stmt, 

708 compile_state, 

709 c, 

710 col_key, 

711 parameters, 

712 _col_bind_name, 

713 implicit_returning, 

714 implicit_return_defaults, 

715 postfetch_lastrowid, 

716 values, 

717 autoincrement_col, 

718 insert_null_pk_still_autoincrements, 

719 kw, 

720 ) 

721 

722 # TODO - see TODO(return_defaults_columns) below 

723 # cols_in_params.add(c) 

724 

725 elif isinsert: 

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

727 

728 if c.primary_key and need_pks: 

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

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

731 # inserted_primary_key to be available. 

732 

733 if implicit_returning: 

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

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

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

737 

738 _append_param_insert_pk_returning( 

739 compiler, stmt, c, values, kw 

740 ) 

741 else: 

742 # otherwise, find out how to invoke this column 

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

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

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

746 # autoincrement column and the dialect supports it 

747 # we can use cursor.lastrowid. 

748 

749 _append_param_insert_pk_no_returning( 

750 compiler, stmt, c, values, kw 

751 ) 

752 

753 elif c.default is not None: 

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

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

756 if not c.default.is_sentinel or ( 

757 use_sentinel_columns is not None 

758 ): 

759 _append_param_insert_hasdefault( 

760 compiler, stmt, c, implicit_return_defaults, values, kw 

761 ) 

762 

763 elif c.server_default is not None: 

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

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

766 if implicit_return_defaults and c in implicit_return_defaults: 

767 compiler_implicit_returning.append(c) 

768 elif not c.primary_key: 

769 compiler.postfetch.append(c) 

770 

771 elif implicit_return_defaults and c in implicit_return_defaults: 

772 compiler_implicit_returning.append(c) 

773 

774 elif ( 

775 c.primary_key 

776 and c is not stmt.table._autoincrement_column 

777 and not c.nullable 

778 ): 

779 _warn_pk_with_no_anticipated_value(c) 

780 

781 elif compile_state.isupdate: 

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

783 

784 _append_param_update( 

785 compiler, 

786 compile_state, 

787 stmt, 

788 c, 

789 implicit_return_defaults, 

790 values, 

791 kw, 

792 ) 

793 

794 # adding supplemental cols to implicit_returning in table 

795 # order so that order is maintained between multiple INSERT 

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

797 # have the same RETURNING clause 

798 if ( 

799 c in supplemental_returning 

800 and c not in compiler_implicit_returning 

801 ): 

802 compiler_implicit_returning.append(c) 

803 

804 if supplemental_returning: 

805 # we should have gotten every col into implicit_returning, 

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

807 # in it 

808 remaining_supplemental = supplemental_returning.difference( 

809 compiler_implicit_returning 

810 ) 

811 compiler_implicit_returning.extend( 

812 c 

813 for c in stmt._supplemental_returning 

814 if c in remaining_supplemental 

815 ) 

816 

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

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

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

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

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

822 

823 # if stmt._return_defaults_columns: 

824 # compiler_implicit_returning.extend( 

825 # set(stmt._return_defaults_columns) 

826 # .difference(compiler_implicit_returning) 

827 # .difference(cols_in_params) 

828 # ) 

829 

830 return (use_insertmanyvalues, use_sentinel_columns) 

831 

832 

833def _setup_delete_return_defaults( 

834 compiler, 

835 stmt, 

836 compile_state, 

837 parameters, 

838 _getattr_col_key, 

839 _column_as_key, 

840 _col_bind_name, 

841 check_columns, 

842 values, 

843 toplevel, 

844 kw, 

845): 

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

847 compiler, stmt, compile_state, toplevel 

848 ) 

849 

850 if not implicit_return_defaults: 

851 return 

852 

853 if stmt._return_defaults_columns: 

854 compiler.implicit_returning.extend(implicit_return_defaults) 

855 

856 if stmt._supplemental_returning: 

857 ir_set = set(compiler.implicit_returning) 

858 compiler.implicit_returning.extend( 

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

860 ) 

861 

862 

863def _append_param_parameter( 

864 compiler, 

865 stmt, 

866 compile_state, 

867 c, 

868 col_key, 

869 parameters, 

870 _col_bind_name, 

871 implicit_returning, 

872 implicit_return_defaults, 

873 postfetch_lastrowid, 

874 values, 

875 autoincrement_col, 

876 insert_null_pk_still_autoincrements, 

877 kw, 

878): 

879 value = parameters.pop(col_key) 

880 

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

882 col_value = compiler.preparer.format_column( 

883 c, use_table=compile_state.include_table_with_column_exprs 

884 ) 

885 

886 accumulated_bind_names: Set[str] = set() 

887 

888 if coercions._is_literal(value): 

889 if ( 

890 insert_null_pk_still_autoincrements 

891 and c.primary_key 

892 and c is autoincrement_col 

893 ): 

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

895 # even if value was given. 

896 

897 if postfetch_lastrowid: 

898 compiler.postfetch_lastrowid = True 

899 elif implicit_returning: 

900 compiler.implicit_returning.append(c) 

901 

902 value = _create_bind_param( 

903 compiler, 

904 c, 

905 value, 

906 required=value is REQUIRED, 

907 name=( 

908 _col_bind_name(c) 

909 if not _compile_state_isinsert(compile_state) 

910 or not compile_state._has_multi_parameters 

911 else "%s_m0" % _col_bind_name(c) 

912 ), 

913 accumulate_bind_names=accumulated_bind_names, 

914 force_anonymous=has_visiting_cte, 

915 **kw, 

916 ) 

917 elif value._is_bind_parameter: 

918 if ( 

919 insert_null_pk_still_autoincrements 

920 and value.value is None 

921 and c.primary_key 

922 and c is autoincrement_col 

923 ): 

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

925 # even if value was given 

926 if implicit_returning: 

927 compiler.implicit_returning.append(c) 

928 elif compiler.dialect.postfetch_lastrowid: 

929 compiler.postfetch_lastrowid = True 

930 

931 value = _handle_values_anonymous_param( 

932 compiler, 

933 c, 

934 value, 

935 name=( 

936 _col_bind_name(c) 

937 if not _compile_state_isinsert(compile_state) 

938 or not compile_state._has_multi_parameters 

939 else "%s_m0" % _col_bind_name(c) 

940 ), 

941 accumulate_bind_names=accumulated_bind_names, 

942 **kw, 

943 ) 

944 else: 

945 # value is a SQL expression 

946 value = compiler.process( 

947 value.self_group(), 

948 accumulate_bind_names=accumulated_bind_names, 

949 **kw, 

950 ) 

951 

952 if compile_state.isupdate: 

953 if implicit_return_defaults and c in implicit_return_defaults: 

954 compiler.implicit_returning.append(c) 

955 

956 else: 

957 compiler.postfetch.append(c) 

958 else: 

959 if c.primary_key: 

960 if implicit_returning: 

961 compiler.implicit_returning.append(c) 

962 elif compiler.dialect.postfetch_lastrowid: 

963 compiler.postfetch_lastrowid = True 

964 

965 elif implicit_return_defaults and (c in implicit_return_defaults): 

966 compiler.implicit_returning.append(c) 

967 

968 else: 

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

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

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

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

973 # time. 

974 

975 compiler.postfetch.append(c) 

976 

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

978 

979 

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

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

982 we want to populate result.inserted_primary_key and RETURNING 

983 is available. 

984 

985 """ 

986 if c.default is not None: 

987 if c.default.is_sequence: 

988 if compiler.dialect.supports_sequences and ( 

989 not c.default.optional 

990 or not compiler.dialect.sequences_optional 

991 ): 

992 accumulated_bind_names: Set[str] = set() 

993 values.append( 

994 ( 

995 c, 

996 compiler.preparer.format_column(c), 

997 compiler.process( 

998 c.default, 

999 accumulate_bind_names=accumulated_bind_names, 

1000 **kw, 

1001 ), 

1002 accumulated_bind_names, 

1003 ) 

1004 ) 

1005 compiler.implicit_returning.append(c) 

1006 elif c.default.is_clause_element: 

1007 accumulated_bind_names = set() 

1008 values.append( 

1009 ( 

1010 c, 

1011 compiler.preparer.format_column(c), 

1012 compiler.process( 

1013 c.default.arg.self_group(), 

1014 accumulate_bind_names=accumulated_bind_names, 

1015 **kw, 

1016 ), 

1017 accumulated_bind_names, 

1018 ) 

1019 ) 

1020 compiler.implicit_returning.append(c) 

1021 else: 

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

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

1024 # on the Python side 

1025 values.append( 

1026 ( 

1027 c, 

1028 compiler.preparer.format_column(c), 

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

1030 (c.key,), 

1031 ) 

1032 ) 

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

1034 compiler.implicit_returning.append(c) 

1035 elif not c.nullable: 

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

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

1038 _warn_pk_with_no_anticipated_value(c) 

1039 

1040 

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

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

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

1044 RETURNING. 

1045 

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

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

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

1049 

1050 

1051 """ 

1052 

1053 if ( 

1054 # column has a Python-side default 

1055 c.default is not None 

1056 and ( 

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

1058 # sequences and want to invoke it 

1059 not c.default.is_sequence 

1060 or ( 

1061 compiler.dialect.supports_sequences 

1062 and ( 

1063 not c.default.optional 

1064 or not compiler.dialect.sequences_optional 

1065 ) 

1066 ) 

1067 ) 

1068 ) or ( 

1069 # column is the "autoincrement column" 

1070 c is stmt.table._autoincrement_column 

1071 and ( 

1072 # dialect can't use cursor.lastrowid 

1073 not compiler.dialect.postfetch_lastrowid 

1074 and ( 

1075 # column has a Sequence and we support those 

1076 ( 

1077 c.default is not None 

1078 and c.default.is_sequence 

1079 and compiler.dialect.supports_sequences 

1080 ) 

1081 or 

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

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

1084 # SERIAL we know the sequence name 

1085 ( 

1086 c.default is None 

1087 and compiler.dialect.preexecute_autoincrement_sequences 

1088 ) 

1089 ) 

1090 ) 

1091 ): 

1092 # do a pre-execute of the default 

1093 values.append( 

1094 ( 

1095 c, 

1096 compiler.preparer.format_column(c), 

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

1098 (c.key,), 

1099 ) 

1100 ) 

1101 elif ( 

1102 c.default is None 

1103 and c.server_default is None 

1104 and not c.nullable 

1105 and c is not stmt.table._autoincrement_column 

1106 ): 

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

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

1109 _warn_pk_with_no_anticipated_value(c) 

1110 elif compiler.dialect.postfetch_lastrowid: 

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

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

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

1114 # that the DefaultExecutionContext calls upon cursor.lastrowid 

1115 compiler.postfetch_lastrowid = True 

1116 

1117 

1118def _append_param_insert_hasdefault( 

1119 compiler, stmt, c, implicit_return_defaults, values, kw 

1120): 

1121 if c.default.is_sequence: 

1122 if compiler.dialect.supports_sequences and ( 

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

1124 ): 

1125 accumulated_bind_names: Set[str] = set() 

1126 values.append( 

1127 ( 

1128 c, 

1129 compiler.preparer.format_column(c), 

1130 compiler.process( 

1131 c.default, 

1132 accumulate_bind_names=accumulated_bind_names, 

1133 **kw, 

1134 ), 

1135 accumulated_bind_names, 

1136 ) 

1137 ) 

1138 if implicit_return_defaults and c in implicit_return_defaults: 

1139 compiler.implicit_returning.append(c) 

1140 elif not c.primary_key: 

1141 compiler.postfetch.append(c) 

1142 elif c.default.is_clause_element: 

1143 accumulated_bind_names = set() 

1144 values.append( 

1145 ( 

1146 c, 

1147 compiler.preparer.format_column(c), 

1148 compiler.process( 

1149 c.default.arg.self_group(), 

1150 accumulate_bind_names=accumulated_bind_names, 

1151 **kw, 

1152 ), 

1153 accumulated_bind_names, 

1154 ) 

1155 ) 

1156 

1157 if implicit_return_defaults and c in implicit_return_defaults: 

1158 compiler.implicit_returning.append(c) 

1159 elif not c.primary_key: 

1160 # don't add primary key column to postfetch 

1161 compiler.postfetch.append(c) 

1162 else: 

1163 values.append( 

1164 ( 

1165 c, 

1166 compiler.preparer.format_column(c), 

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

1168 (c.key,), 

1169 ) 

1170 ) 

1171 

1172 

1173def _append_param_insert_select_hasdefault( 

1174 compiler: SQLCompiler, 

1175 stmt: ValuesBase, 

1176 c: ColumnClause[Any], 

1177 values: List[_CrudParamElementSQLExpr], 

1178 kw: Dict[str, Any], 

1179) -> None: 

1180 if default_is_sequence(c.default): 

1181 if compiler.dialect.supports_sequences and ( 

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

1183 ): 

1184 values.append( 

1185 ( 

1186 c, 

1187 compiler.preparer.format_column(c), 

1188 c.default.next_value(), 

1189 (), 

1190 ) 

1191 ) 

1192 elif default_is_clause_element(c.default): 

1193 values.append( 

1194 ( 

1195 c, 

1196 compiler.preparer.format_column(c), 

1197 c.default.arg.self_group(), 

1198 (), 

1199 ) 

1200 ) 

1201 else: 

1202 values.append( 

1203 ( 

1204 c, 

1205 compiler.preparer.format_column(c), 

1206 _create_insert_prefetch_bind_param( 

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

1208 ), 

1209 (c.key,), 

1210 ) 

1211 ) 

1212 

1213 

1214def _append_param_update( 

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

1216): 

1217 include_table = compile_state.include_table_with_column_exprs 

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

1219 if c.onupdate.is_clause_element: 

1220 values.append( 

1221 ( 

1222 c, 

1223 compiler.preparer.format_column( 

1224 c, 

1225 use_table=include_table, 

1226 ), 

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

1228 (), 

1229 ) 

1230 ) 

1231 if implicit_return_defaults and c in implicit_return_defaults: 

1232 compiler.implicit_returning.append(c) 

1233 else: 

1234 compiler.postfetch.append(c) 

1235 else: 

1236 values.append( 

1237 ( 

1238 c, 

1239 compiler.preparer.format_column( 

1240 c, 

1241 use_table=include_table, 

1242 ), 

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

1244 (c.key,), 

1245 ) 

1246 ) 

1247 elif c.server_onupdate is not None: 

1248 if implicit_return_defaults and c in implicit_return_defaults: 

1249 compiler.implicit_returning.append(c) 

1250 else: 

1251 compiler.postfetch.append(c) 

1252 elif ( 

1253 implicit_return_defaults 

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

1255 and c in implicit_return_defaults 

1256 ): 

1257 compiler.implicit_returning.append(c) 

1258 

1259 

1260@overload 

1261def _create_insert_prefetch_bind_param( 

1262 compiler: SQLCompiler, 

1263 c: ColumnElement[Any], 

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

1265 **kw: Any, 

1266) -> str: ... 

1267 

1268 

1269@overload 

1270def _create_insert_prefetch_bind_param( 

1271 compiler: SQLCompiler, 

1272 c: ColumnElement[Any], 

1273 process: Literal[False], 

1274 **kw: Any, 

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

1276 

1277 

1278def _create_insert_prefetch_bind_param( 

1279 compiler: SQLCompiler, 

1280 c: ColumnElement[Any], 

1281 process: bool = True, 

1282 name: Optional[str] = None, 

1283 **kw: Any, 

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

1285 param = _create_bind_param( 

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

1287 ) 

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

1289 return param 

1290 

1291 

1292@overload 

1293def _create_update_prefetch_bind_param( 

1294 compiler: SQLCompiler, 

1295 c: ColumnElement[Any], 

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

1297 **kw: Any, 

1298) -> str: ... 

1299 

1300 

1301@overload 

1302def _create_update_prefetch_bind_param( 

1303 compiler: SQLCompiler, 

1304 c: ColumnElement[Any], 

1305 process: Literal[False], 

1306 **kw: Any, 

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

1308 

1309 

1310def _create_update_prefetch_bind_param( 

1311 compiler: SQLCompiler, 

1312 c: ColumnElement[Any], 

1313 process: bool = True, 

1314 name: Optional[str] = None, 

1315 **kw: Any, 

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

1317 param = _create_bind_param( 

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

1319 ) 

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

1321 return param 

1322 

1323 

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

1325 _is_multiparam_column = True 

1326 

1327 def __init__(self, original, index): 

1328 self.index = index 

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

1330 self.original = original 

1331 self.default = original.default 

1332 self.type = original.type 

1333 

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

1335 raise NotImplementedError() 

1336 

1337 def _copy_internals(self, **kw): 

1338 raise NotImplementedError() 

1339 

1340 def __eq__(self, other): 

1341 return ( 

1342 isinstance(other, _multiparam_column) 

1343 and other.key == self.key 

1344 and other.original == self.original 

1345 ) 

1346 

1347 @util.memoized_property 

1348 def _default_description_tuple(self) -> _DefaultDescriptionTuple: 

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

1350 

1351 return _DefaultDescriptionTuple._from_column_default(self.default) 

1352 

1353 @util.memoized_property 

1354 def _onupdate_description_tuple(self) -> _DefaultDescriptionTuple: 

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

1356 

1357 return _DefaultDescriptionTuple._from_column_default(self.onupdate) 

1358 

1359 

1360def _process_multiparam_default_bind( 

1361 compiler: SQLCompiler, 

1362 stmt: ValuesBase, 

1363 c: KeyedColumnElement[Any], 

1364 index: int, 

1365 kw: Dict[str, Any], 

1366) -> str: 

1367 if not c.default: 

1368 raise exc.CompileError( 

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

1370 "parameter in the VALUES clause; " 

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

1372 ) 

1373 elif default_is_clause_element(c.default): 

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

1375 elif c.default.is_sequence: 

1376 # these conditions would have been established 

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

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

1379 # checked 

1380 # assert compiler.dialect.supports_sequences and ( 

1381 # not c.default.optional 

1382 # or not compiler.dialect.sequences_optional 

1383 # ) 

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

1385 else: 

1386 col = _multiparam_column(c, index) 

1387 assert isinstance(stmt, dml.Insert) 

1388 return _create_insert_prefetch_bind_param( 

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

1390 ) 

1391 

1392 

1393def _get_update_multitable_params( 

1394 compiler, 

1395 stmt, 

1396 compile_state, 

1397 stmt_parameter_tuples, 

1398 check_columns, 

1399 _col_bind_name, 

1400 _getattr_col_key, 

1401 values, 

1402 kw, 

1403): 

1404 normalized_params = { 

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

1406 for c, param in stmt_parameter_tuples or () 

1407 } 

1408 

1409 include_table = compile_state.include_table_with_column_exprs 

1410 

1411 affected_tables = set() 

1412 for t in compile_state._extra_froms: 

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

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

1415 # supported 

1416 we_shouldnt_be_here_if_columns_found = ( 

1417 not include_table 

1418 and not compile_state.dml_table.is_derived_from(t) 

1419 ) 

1420 

1421 for c in t.c: 

1422 if c in normalized_params: 

1423 

1424 if we_shouldnt_be_here_if_columns_found: 

1425 raise exc.CompileError( 

1426 "Backend does not support additional tables " 

1427 "in the SET " 

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

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

1430 "SET clause" 

1431 ) 

1432 

1433 affected_tables.add(t) 

1434 

1435 check_columns[_getattr_col_key(c)] = c 

1436 value = normalized_params[c] 

1437 

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

1439 if coercions._is_literal(value): 

1440 value = _create_bind_param( 

1441 compiler, 

1442 c, 

1443 value, 

1444 required=value is REQUIRED, 

1445 name=_col_bind_name(c), 

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

1447 ) 

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

1449 elif value._is_bind_parameter: 

1450 cbn = _col_bind_name(c) 

1451 value = _handle_values_anonymous_param( 

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

1453 ) 

1454 accumulated_bind_names = (cbn,) 

1455 else: 

1456 compiler.postfetch.append(c) 

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

1458 accumulated_bind_names = () 

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

1460 

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

1462 # and server_onupdate for these 

1463 for t in affected_tables: 

1464 for c in t.c: 

1465 if c in normalized_params: 

1466 continue 

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

1468 if c.onupdate.is_clause_element: 

1469 values.append( 

1470 ( 

1471 c, 

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

1473 compiler.process( 

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

1475 ), 

1476 (), 

1477 ) 

1478 ) 

1479 compiler.postfetch.append(c) 

1480 else: 

1481 values.append( 

1482 ( 

1483 c, 

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

1485 _create_update_prefetch_bind_param( 

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

1487 ), 

1488 (c.key,), 

1489 ) 

1490 ) 

1491 elif c.server_onupdate is not None: 

1492 compiler.postfetch.append(c) 

1493 

1494 

1495def _extend_values_for_multiparams( 

1496 compiler: SQLCompiler, 

1497 stmt: ValuesBase, 

1498 compile_state: DMLState, 

1499 initial_values: Sequence[_CrudParamElementStr], 

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

1501 kw: Dict[str, Any], 

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

1503 values_0 = initial_values 

1504 values = [initial_values] 

1505 

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

1507 mp = compile_state._multi_parameters 

1508 assert mp is not None 

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

1510 extension: List[_CrudParamElementStr] = [] 

1511 

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

1513 

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

1515 if col.key in row: 

1516 key = col.key 

1517 

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

1519 new_param = _create_bind_param( 

1520 compiler, 

1521 col, 

1522 row[key], 

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

1524 force_anonymous=has_visiting_cte, 

1525 **kw, 

1526 ) 

1527 else: 

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

1529 else: 

1530 new_param = _process_multiparam_default_bind( 

1531 compiler, stmt, col, i, kw 

1532 ) 

1533 

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

1535 

1536 values.append(extension) 

1537 

1538 return values 

1539 

1540 

1541def _get_stmt_parameter_tuples_params( 

1542 compiler, 

1543 compile_state, 

1544 parameters, 

1545 stmt_parameter_tuples, 

1546 _column_as_key, 

1547 values, 

1548 kw, 

1549): 

1550 for k, v in stmt_parameter_tuples: 

1551 colkey = _column_as_key(k) 

1552 if colkey is not None: 

1553 parameters.setdefault(colkey, v) 

1554 else: 

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

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

1557 # coercing right side to bound param 

1558 

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

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

1561 

1562 col_expr = compiler.process( 

1563 k, include_table=compile_state.include_table_with_column_exprs 

1564 ) 

1565 

1566 if coercions._is_literal(v): 

1567 v = compiler.process( 

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

1569 ) 

1570 else: 

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

1572 # either unique parameter, or other bound parameters that 

1573 # were passed in directly 

1574 # set type to that of the column unconditionally 

1575 v = v._with_binary_element_type(k.type) 

1576 

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

1578 

1579 # TODO: not sure if accumulated_bind_names applies here 

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

1581 

1582 

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

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

1585 

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

1587 INSERT or UPDATE statement after it's invoked. 

1588 

1589 """ 

1590 

1591 dialect = compiler.dialect 

1592 

1593 need_pks = ( 

1594 toplevel 

1595 and _compile_state_isinsert(compile_state) 

1596 and not stmt._inline 

1597 and ( 

1598 not compiler.for_executemany 

1599 or (dialect.insert_executemany_returning and stmt._return_defaults) 

1600 ) 

1601 and not stmt._returning 

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

1603 and not compile_state._has_multi_parameters 

1604 ) 

1605 

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

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

1608 postfetch_lastrowid = ( 

1609 need_pks 

1610 and dialect.postfetch_lastrowid 

1611 and stmt.table._autoincrement_column is not None 

1612 ) 

1613 

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

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

1616 # if that's set. 

1617 implicit_returning = ( 

1618 # statement itself can veto it 

1619 need_pks 

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

1621 # with INSERT 

1622 and dialect.insert_returning 

1623 # user-defined implicit_returning on Table can veto it 

1624 and compile_state._primary_table.implicit_returning 

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

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

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

1628 and compile_state._supports_implicit_returning 

1629 and ( 

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

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

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

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

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

1635 # SQLite lastrowid times 3x faster than returning, 

1636 # Mariadb lastrowid 2x faster than returning 

1637 (not postfetch_lastrowid or dialect.favor_returning_over_lastrowid) 

1638 or compile_state._has_multi_parameters 

1639 or stmt._return_defaults 

1640 ) 

1641 ) 

1642 if implicit_returning: 

1643 postfetch_lastrowid = False 

1644 

1645 if _compile_state_isinsert(compile_state): 

1646 should_implicit_return_defaults = ( 

1647 implicit_returning and stmt._return_defaults 

1648 ) 

1649 explicit_returning = ( 

1650 should_implicit_return_defaults 

1651 or stmt._returning 

1652 or stmt._supplemental_returning 

1653 ) 

1654 use_insertmanyvalues = ( 

1655 toplevel 

1656 and compiler.for_executemany 

1657 and dialect.use_insertmanyvalues 

1658 and ( 

1659 explicit_returning or dialect.use_insertmanyvalues_wo_returning 

1660 ) 

1661 ) 

1662 

1663 use_sentinel_columns = None 

1664 if ( 

1665 use_insertmanyvalues 

1666 and explicit_returning 

1667 and stmt._sort_by_parameter_order 

1668 ): 

1669 use_sentinel_columns = compiler._get_sentinel_column_for_table( 

1670 stmt.table 

1671 ) 

1672 

1673 elif compile_state.isupdate: 

1674 should_implicit_return_defaults = ( 

1675 stmt._return_defaults 

1676 and compile_state._primary_table.implicit_returning 

1677 and compile_state._supports_implicit_returning 

1678 and dialect.update_returning 

1679 ) 

1680 use_insertmanyvalues = False 

1681 use_sentinel_columns = None 

1682 elif compile_state.isdelete: 

1683 should_implicit_return_defaults = ( 

1684 stmt._return_defaults 

1685 and compile_state._primary_table.implicit_returning 

1686 and compile_state._supports_implicit_returning 

1687 and dialect.delete_returning 

1688 ) 

1689 use_insertmanyvalues = False 

1690 use_sentinel_columns = None 

1691 else: 

1692 should_implicit_return_defaults = False # pragma: no cover 

1693 use_insertmanyvalues = False 

1694 use_sentinel_columns = None 

1695 

1696 if should_implicit_return_defaults: 

1697 if not stmt._return_defaults_columns: 

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

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

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

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

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

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

1704 implicit_return_defaults = set(stmt.table.c) 

1705 else: 

1706 implicit_return_defaults = set(stmt._return_defaults_columns) 

1707 else: 

1708 implicit_return_defaults = None 

1709 

1710 return ( 

1711 need_pks, 

1712 implicit_returning or should_implicit_return_defaults, 

1713 implicit_return_defaults, 

1714 postfetch_lastrowid, 

1715 use_insertmanyvalues, 

1716 use_sentinel_columns, 

1717 ) 

1718 

1719 

1720def _warn_pk_with_no_anticipated_value(c): 

1721 msg = ( 

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

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

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

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

1726 "and no explicit value is passed. " 

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

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

1729 ) 

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

1731 msg += ( 

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

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

1734 "keys if AUTO_INCREMENT/SERIAL/IDENTITY " 

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

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

1737 "most backends." 

1738 ) 

1739 util.warn(msg)