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

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

486 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 raise exc.CompileError( 

336 "Unconsumed column names: %s" 

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

338 ) 

339 

340 is_default_metavalue_only = False 

341 

342 if ( 

343 _compile_state_isinsert(compile_state) 

344 and compile_state._has_multi_parameters 

345 ): 

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

347 assert not stmt._select_names 

348 multi_extended_values = _extend_values_for_multiparams( 

349 compiler, 

350 stmt, 

351 compile_state, 

352 cast( 

353 "Sequence[_CrudParamElementStr]", 

354 values, 

355 ), 

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

357 kw, 

358 ) 

359 return _CrudParams(values, multi_extended_values) 

360 elif ( 

361 not values 

362 and compiler.for_executemany 

363 and compiler.dialect.supports_default_metavalue 

364 ): 

365 # convert an "INSERT DEFAULT VALUES" 

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

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

368 # insert_executemany_returning mode :) 

369 values = [ 

370 ( 

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

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

373 compiler.dialect.default_metavalue_token, 

374 (), 

375 ) 

376 ] 

377 is_default_metavalue_only = True 

378 

379 return _CrudParams( 

380 values, 

381 [], 

382 is_default_metavalue_only=is_default_metavalue_only, 

383 use_insertmanyvalues=use_insertmanyvalues, 

384 use_sentinel_columns=use_sentinel_columns, 

385 ) 

386 

387 

388@overload 

389def _create_bind_param( 

390 compiler: SQLCompiler, 

391 col: ColumnElement[Any], 

392 value: Any, 

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

394 required: bool = False, 

395 name: Optional[str] = None, 

396 force_anonymous: bool = False, 

397 **kw: Any, 

398) -> str: ... 

399 

400 

401@overload 

402def _create_bind_param( 

403 compiler: SQLCompiler, 

404 col: ColumnElement[Any], 

405 value: Any, 

406 **kw: Any, 

407) -> str: ... 

408 

409 

410def _create_bind_param( 

411 compiler: SQLCompiler, 

412 col: ColumnElement[Any], 

413 value: Any, 

414 process: bool = True, 

415 required: bool = False, 

416 name: Optional[str] = None, 

417 force_anonymous: bool = False, 

418 **kw: Any, 

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

420 if force_anonymous: 

421 name = None 

422 elif name is None: 

423 name = col.key 

424 

425 bindparam = elements.BindParameter( 

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

427 ) 

428 bindparam._is_crud = True 

429 if process: 

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

431 else: 

432 return bindparam 

433 

434 

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

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

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

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

439 # produce bound parameters in deterministic order without invoking any 

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

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

442 # right now). 

443 # 

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

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

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

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

448 # rather than having 

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

450 # name. Saves on call counts also. 

451 

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

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

454 # multiple insert/update are combined together using CTEs 

455 is_cte = "visiting_cte" in kw 

456 

457 if ( 

458 not is_cte 

459 and value.unique 

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

461 ): 

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

463 

464 if value.type._isnull: 

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

466 # passed in directly 

467 # set type to that of the column unconditionally 

468 value = value._with_binary_element_type(col.type) 

469 

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

471 

472 

473def _key_getters_for_crud_column( 

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

475) -> Tuple[ 

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

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

478 _BindNameForColProtocol, 

479]: 

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

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

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

483 # dictionaries and when rendering bind param names. 

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

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

486 # statement. 

487 _et = set(compile_state._extra_froms) 

488 

489 c_key_role = functools.partial( 

490 coercions.expect_as_key, roles.DMLColumnRole 

491 ) 

492 

493 def _column_as_key( 

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

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

496 str_key = c_key_role(key) 

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

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

499 else: 

500 return str_key 

501 

502 def _getattr_col_key( 

503 col: ColumnClause[Any], 

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

505 if col.table in _et: 

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

507 else: 

508 return col.key 

509 

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

511 if col.table in _et: 

512 if TYPE_CHECKING: 

513 assert isinstance(col.table, TableClause) 

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

515 else: 

516 return col.key 

517 

518 else: 

519 _column_as_key = functools.partial( 

520 coercions.expect_as_key, roles.DMLColumnRole 

521 ) 

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

523 

524 return _column_as_key, _getattr_col_key, _col_bind_name 

525 

526 

527def _scan_insert_from_select_cols( 

528 compiler, 

529 stmt, 

530 compile_state, 

531 parameters, 

532 _getattr_col_key, 

533 _column_as_key, 

534 _col_bind_name, 

535 check_columns, 

536 values, 

537 toplevel, 

538 kw, 

539): 

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

541 

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

543 

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

545 

546 add_select_cols: List[_CrudParamElementSQLExpr] = [] 

547 if stmt.include_insert_from_select_defaults: 

548 col_set = set(cols) 

549 for col in stmt.table.columns: 

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

551 # this will omit columns marked as omit_from_statements naturally, 

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

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

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

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

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

557 # here so we again omit it. 

558 if ( 

559 col not in col_set 

560 and col.default 

561 and not col.default.is_sentinel 

562 ): 

563 cols.append(col) 

564 

565 for c in cols: 

566 col_key = _getattr_col_key(c) 

567 if col_key in parameters and col_key not in check_columns: 

568 parameters.pop(col_key) 

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

570 else: 

571 _append_param_insert_select_hasdefault( 

572 compiler, stmt, c, add_select_cols, kw 

573 ) 

574 

575 if add_select_cols: 

576 values.extend(add_select_cols) 

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

578 if not isinstance(ins_from_select, Select): 

579 raise exc.CompileError( 

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

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

582 f"""{ 

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

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

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

586 "columns." 

587 ) 

588 ins_from_select = ins_from_select._generate() 

589 # copy raw_columns 

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

591 expr for _, _, expr, _ in add_select_cols 

592 ] 

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

594 

595 

596def _scan_cols( 

597 compiler, 

598 stmt, 

599 compile_state, 

600 parameters, 

601 _getattr_col_key, 

602 _column_as_key, 

603 _col_bind_name, 

604 check_columns, 

605 values, 

606 toplevel, 

607 kw, 

608): 

609 ( 

610 need_pks, 

611 implicit_returning, 

612 implicit_return_defaults, 

613 postfetch_lastrowid, 

614 use_insertmanyvalues, 

615 use_sentinel_columns, 

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

617 

618 assert compile_state.isupdate or compile_state.isinsert 

619 

620 if compile_state._parameter_ordering: 

621 parameter_ordering = [ 

622 _column_as_key(key) for key in compile_state._parameter_ordering 

623 ] 

624 ordered_keys = set(parameter_ordering) 

625 cols = [ 

626 stmt.table.c[key] 

627 for key in parameter_ordering 

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

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

630 

631 else: 

632 cols = stmt.table.columns 

633 

634 isinsert = _compile_state_isinsert(compile_state) 

635 if isinsert and not compile_state._has_multi_parameters: 

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

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

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

639 autoincrement_col = stmt.table._autoincrement_column 

640 insert_null_pk_still_autoincrements = ( 

641 compiler.dialect.insert_null_pk_still_autoincrements 

642 ) 

643 else: 

644 autoincrement_col = insert_null_pk_still_autoincrements = None 

645 

646 if stmt._supplemental_returning: 

647 supplemental_returning = set(stmt._supplemental_returning) 

648 else: 

649 supplemental_returning = set() 

650 

651 compiler_implicit_returning = compiler.implicit_returning 

652 

653 # TODO - see TODO(return_defaults_columns) below 

654 # cols_in_params = set() 

655 

656 for c in cols: 

657 # scan through every column in the target table 

658 

659 col_key = _getattr_col_key(c) 

660 

661 if col_key in parameters and col_key not in check_columns: 

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

663 

664 _append_param_parameter( 

665 compiler, 

666 stmt, 

667 compile_state, 

668 c, 

669 col_key, 

670 parameters, 

671 _col_bind_name, 

672 implicit_returning, 

673 implicit_return_defaults, 

674 postfetch_lastrowid, 

675 values, 

676 autoincrement_col, 

677 insert_null_pk_still_autoincrements, 

678 kw, 

679 ) 

680 

681 # TODO - see TODO(return_defaults_columns) below 

682 # cols_in_params.add(c) 

683 

684 elif isinsert: 

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

686 

687 if c.primary_key and need_pks: 

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

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

690 # inserted_primary_key to be available. 

691 

692 if implicit_returning: 

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

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

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

696 

697 _append_param_insert_pk_returning( 

698 compiler, stmt, c, values, kw 

699 ) 

700 else: 

701 # otherwise, find out how to invoke this column 

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

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

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

705 # autoincrement column and the dialect supports it 

706 # we can use cursor.lastrowid. 

707 

708 _append_param_insert_pk_no_returning( 

709 compiler, stmt, c, values, kw 

710 ) 

711 

712 elif c.default is not None: 

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

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

715 if not c.default.is_sentinel or ( 

716 use_sentinel_columns is not None 

717 ): 

718 _append_param_insert_hasdefault( 

719 compiler, stmt, c, implicit_return_defaults, values, kw 

720 ) 

721 

722 elif c.server_default is not None: 

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

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

725 if implicit_return_defaults and c in implicit_return_defaults: 

726 compiler_implicit_returning.append(c) 

727 elif not c.primary_key: 

728 compiler.postfetch.append(c) 

729 

730 elif implicit_return_defaults and c in implicit_return_defaults: 

731 compiler_implicit_returning.append(c) 

732 

733 elif ( 

734 c.primary_key 

735 and c is not stmt.table._autoincrement_column 

736 and not c.nullable 

737 ): 

738 _warn_pk_with_no_anticipated_value(c) 

739 

740 elif compile_state.isupdate: 

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

742 

743 _append_param_update( 

744 compiler, 

745 compile_state, 

746 stmt, 

747 c, 

748 implicit_return_defaults, 

749 values, 

750 kw, 

751 ) 

752 

753 # adding supplemental cols to implicit_returning in table 

754 # order so that order is maintained between multiple INSERT 

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

756 # have the same RETURNING clause 

757 if ( 

758 c in supplemental_returning 

759 and c not in compiler_implicit_returning 

760 ): 

761 compiler_implicit_returning.append(c) 

762 

763 if supplemental_returning: 

764 # we should have gotten every col into implicit_returning, 

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

766 # in it 

767 remaining_supplemental = supplemental_returning.difference( 

768 compiler_implicit_returning 

769 ) 

770 compiler_implicit_returning.extend( 

771 c 

772 for c in stmt._supplemental_returning 

773 if c in remaining_supplemental 

774 ) 

775 

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

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

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

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

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

781 

782 # if stmt._return_defaults_columns: 

783 # compiler_implicit_returning.extend( 

784 # set(stmt._return_defaults_columns) 

785 # .difference(compiler_implicit_returning) 

786 # .difference(cols_in_params) 

787 # ) 

788 

789 return (use_insertmanyvalues, use_sentinel_columns) 

790 

791 

792def _setup_delete_return_defaults( 

793 compiler, 

794 stmt, 

795 compile_state, 

796 parameters, 

797 _getattr_col_key, 

798 _column_as_key, 

799 _col_bind_name, 

800 check_columns, 

801 values, 

802 toplevel, 

803 kw, 

804): 

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

806 compiler, stmt, compile_state, toplevel 

807 ) 

808 

809 if not implicit_return_defaults: 

810 return 

811 

812 if stmt._return_defaults_columns: 

813 compiler.implicit_returning.extend(implicit_return_defaults) 

814 

815 if stmt._supplemental_returning: 

816 ir_set = set(compiler.implicit_returning) 

817 compiler.implicit_returning.extend( 

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

819 ) 

820 

821 

822def _append_param_parameter( 

823 compiler, 

824 stmt, 

825 compile_state, 

826 c, 

827 col_key, 

828 parameters, 

829 _col_bind_name, 

830 implicit_returning, 

831 implicit_return_defaults, 

832 postfetch_lastrowid, 

833 values, 

834 autoincrement_col, 

835 insert_null_pk_still_autoincrements, 

836 kw, 

837): 

838 value = parameters.pop(col_key) 

839 

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

841 col_value = compiler.preparer.format_column( 

842 c, use_table=compile_state.include_table_with_column_exprs 

843 ) 

844 

845 accumulated_bind_names: Set[str] = set() 

846 

847 if coercions._is_literal(value): 

848 if ( 

849 insert_null_pk_still_autoincrements 

850 and c.primary_key 

851 and c is autoincrement_col 

852 ): 

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

854 # even if value was given. 

855 

856 if postfetch_lastrowid: 

857 compiler.postfetch_lastrowid = True 

858 elif implicit_returning: 

859 compiler.implicit_returning.append(c) 

860 

861 value = _create_bind_param( 

862 compiler, 

863 c, 

864 value, 

865 required=value is REQUIRED, 

866 name=( 

867 _col_bind_name(c) 

868 if not _compile_state_isinsert(compile_state) 

869 or not compile_state._has_multi_parameters 

870 else "%s_m0" % _col_bind_name(c) 

871 ), 

872 accumulate_bind_names=accumulated_bind_names, 

873 force_anonymous=has_visiting_cte, 

874 **kw, 

875 ) 

876 elif value._is_bind_parameter: 

877 if ( 

878 insert_null_pk_still_autoincrements 

879 and value.value is None 

880 and c.primary_key 

881 and c is autoincrement_col 

882 ): 

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

884 # even if value was given 

885 if implicit_returning: 

886 compiler.implicit_returning.append(c) 

887 elif compiler.dialect.postfetch_lastrowid: 

888 compiler.postfetch_lastrowid = True 

889 

890 value = _handle_values_anonymous_param( 

891 compiler, 

892 c, 

893 value, 

894 name=( 

895 _col_bind_name(c) 

896 if not _compile_state_isinsert(compile_state) 

897 or not compile_state._has_multi_parameters 

898 else "%s_m0" % _col_bind_name(c) 

899 ), 

900 accumulate_bind_names=accumulated_bind_names, 

901 **kw, 

902 ) 

903 else: 

904 # value is a SQL expression 

905 value = compiler.process( 

906 value.self_group(), 

907 accumulate_bind_names=accumulated_bind_names, 

908 **kw, 

909 ) 

910 

911 if compile_state.isupdate: 

912 if implicit_return_defaults and c in implicit_return_defaults: 

913 compiler.implicit_returning.append(c) 

914 

915 else: 

916 compiler.postfetch.append(c) 

917 else: 

918 if c.primary_key: 

919 if implicit_returning: 

920 compiler.implicit_returning.append(c) 

921 elif compiler.dialect.postfetch_lastrowid: 

922 compiler.postfetch_lastrowid = True 

923 

924 elif implicit_return_defaults and (c in implicit_return_defaults): 

925 compiler.implicit_returning.append(c) 

926 

927 else: 

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

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

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

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

932 # time. 

933 

934 compiler.postfetch.append(c) 

935 

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

937 

938 

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

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

941 we want to populate result.inserted_primary_key and RETURNING 

942 is available. 

943 

944 """ 

945 if c.default is not None: 

946 if c.default.is_sequence: 

947 if compiler.dialect.supports_sequences and ( 

948 not c.default.optional 

949 or not compiler.dialect.sequences_optional 

950 ): 

951 accumulated_bind_names: Set[str] = set() 

952 values.append( 

953 ( 

954 c, 

955 compiler.preparer.format_column(c), 

956 compiler.process( 

957 c.default, 

958 accumulate_bind_names=accumulated_bind_names, 

959 **kw, 

960 ), 

961 accumulated_bind_names, 

962 ) 

963 ) 

964 compiler.implicit_returning.append(c) 

965 elif c.default.is_clause_element: 

966 accumulated_bind_names = set() 

967 values.append( 

968 ( 

969 c, 

970 compiler.preparer.format_column(c), 

971 compiler.process( 

972 c.default.arg.self_group(), 

973 accumulate_bind_names=accumulated_bind_names, 

974 **kw, 

975 ), 

976 accumulated_bind_names, 

977 ) 

978 ) 

979 compiler.implicit_returning.append(c) 

980 else: 

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

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

983 # on the Python side 

984 values.append( 

985 ( 

986 c, 

987 compiler.preparer.format_column(c), 

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

989 (c.key,), 

990 ) 

991 ) 

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

993 compiler.implicit_returning.append(c) 

994 elif not c.nullable: 

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

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

997 _warn_pk_with_no_anticipated_value(c) 

998 

999 

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

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

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

1003 RETURNING. 

1004 

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

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

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

1008 

1009 

1010 """ 

1011 

1012 if ( 

1013 # column has a Python-side default 

1014 c.default is not None 

1015 and ( 

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

1017 # sequences and want to invoke it 

1018 not c.default.is_sequence 

1019 or ( 

1020 compiler.dialect.supports_sequences 

1021 and ( 

1022 not c.default.optional 

1023 or not compiler.dialect.sequences_optional 

1024 ) 

1025 ) 

1026 ) 

1027 ) or ( 

1028 # column is the "autoincrement column" 

1029 c is stmt.table._autoincrement_column 

1030 and ( 

1031 # dialect can't use cursor.lastrowid 

1032 not compiler.dialect.postfetch_lastrowid 

1033 and ( 

1034 # column has a Sequence and we support those 

1035 ( 

1036 c.default is not None 

1037 and c.default.is_sequence 

1038 and compiler.dialect.supports_sequences 

1039 ) 

1040 or 

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

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

1043 # SERIAL we know the sequence name 

1044 ( 

1045 c.default is None 

1046 and compiler.dialect.preexecute_autoincrement_sequences 

1047 ) 

1048 ) 

1049 ) 

1050 ): 

1051 # do a pre-execute of the default 

1052 values.append( 

1053 ( 

1054 c, 

1055 compiler.preparer.format_column(c), 

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

1057 (c.key,), 

1058 ) 

1059 ) 

1060 elif ( 

1061 c.default is None 

1062 and c.server_default is None 

1063 and not c.nullable 

1064 and c is not stmt.table._autoincrement_column 

1065 ): 

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

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

1068 _warn_pk_with_no_anticipated_value(c) 

1069 elif compiler.dialect.postfetch_lastrowid: 

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

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

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

1073 # that the DefaultExecutionContext calls upon cursor.lastrowid 

1074 compiler.postfetch_lastrowid = True 

1075 

1076 

1077def _append_param_insert_hasdefault( 

1078 compiler, stmt, c, implicit_return_defaults, values, kw 

1079): 

1080 if c.default.is_sequence: 

1081 if compiler.dialect.supports_sequences and ( 

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

1083 ): 

1084 accumulated_bind_names: Set[str] = set() 

1085 values.append( 

1086 ( 

1087 c, 

1088 compiler.preparer.format_column(c), 

1089 compiler.process( 

1090 c.default, 

1091 accumulate_bind_names=accumulated_bind_names, 

1092 **kw, 

1093 ), 

1094 accumulated_bind_names, 

1095 ) 

1096 ) 

1097 if implicit_return_defaults and c in implicit_return_defaults: 

1098 compiler.implicit_returning.append(c) 

1099 elif not c.primary_key: 

1100 compiler.postfetch.append(c) 

1101 elif c.default.is_clause_element: 

1102 accumulated_bind_names = set() 

1103 values.append( 

1104 ( 

1105 c, 

1106 compiler.preparer.format_column(c), 

1107 compiler.process( 

1108 c.default.arg.self_group(), 

1109 accumulate_bind_names=accumulated_bind_names, 

1110 **kw, 

1111 ), 

1112 accumulated_bind_names, 

1113 ) 

1114 ) 

1115 

1116 if implicit_return_defaults and c in implicit_return_defaults: 

1117 compiler.implicit_returning.append(c) 

1118 elif not c.primary_key: 

1119 # don't add primary key column to postfetch 

1120 compiler.postfetch.append(c) 

1121 else: 

1122 values.append( 

1123 ( 

1124 c, 

1125 compiler.preparer.format_column(c), 

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

1127 (c.key,), 

1128 ) 

1129 ) 

1130 

1131 

1132def _append_param_insert_select_hasdefault( 

1133 compiler: SQLCompiler, 

1134 stmt: ValuesBase, 

1135 c: ColumnClause[Any], 

1136 values: List[_CrudParamElementSQLExpr], 

1137 kw: Dict[str, Any], 

1138) -> None: 

1139 if default_is_sequence(c.default): 

1140 if compiler.dialect.supports_sequences and ( 

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

1142 ): 

1143 values.append( 

1144 ( 

1145 c, 

1146 compiler.preparer.format_column(c), 

1147 c.default.next_value(), 

1148 (), 

1149 ) 

1150 ) 

1151 elif default_is_clause_element(c.default): 

1152 values.append( 

1153 ( 

1154 c, 

1155 compiler.preparer.format_column(c), 

1156 c.default.arg.self_group(), 

1157 (), 

1158 ) 

1159 ) 

1160 else: 

1161 values.append( 

1162 ( 

1163 c, 

1164 compiler.preparer.format_column(c), 

1165 _create_insert_prefetch_bind_param( 

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

1167 ), 

1168 (c.key,), 

1169 ) 

1170 ) 

1171 

1172 

1173def _append_param_update( 

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

1175): 

1176 include_table = compile_state.include_table_with_column_exprs 

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

1178 if c.onupdate.is_clause_element: 

1179 values.append( 

1180 ( 

1181 c, 

1182 compiler.preparer.format_column( 

1183 c, 

1184 use_table=include_table, 

1185 ), 

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

1187 (), 

1188 ) 

1189 ) 

1190 if implicit_return_defaults and c in implicit_return_defaults: 

1191 compiler.implicit_returning.append(c) 

1192 else: 

1193 compiler.postfetch.append(c) 

1194 else: 

1195 values.append( 

1196 ( 

1197 c, 

1198 compiler.preparer.format_column( 

1199 c, 

1200 use_table=include_table, 

1201 ), 

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

1203 (c.key,), 

1204 ) 

1205 ) 

1206 elif c.server_onupdate is not None: 

1207 if implicit_return_defaults and c in implicit_return_defaults: 

1208 compiler.implicit_returning.append(c) 

1209 else: 

1210 compiler.postfetch.append(c) 

1211 elif ( 

1212 implicit_return_defaults 

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

1214 and c in implicit_return_defaults 

1215 ): 

1216 compiler.implicit_returning.append(c) 

1217 

1218 

1219@overload 

1220def _create_insert_prefetch_bind_param( 

1221 compiler: SQLCompiler, 

1222 c: ColumnElement[Any], 

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

1224 **kw: Any, 

1225) -> str: ... 

1226 

1227 

1228@overload 

1229def _create_insert_prefetch_bind_param( 

1230 compiler: SQLCompiler, 

1231 c: ColumnElement[Any], 

1232 process: Literal[False], 

1233 **kw: Any, 

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

1235 

1236 

1237def _create_insert_prefetch_bind_param( 

1238 compiler: SQLCompiler, 

1239 c: ColumnElement[Any], 

1240 process: bool = True, 

1241 name: Optional[str] = None, 

1242 **kw: Any, 

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

1244 param = _create_bind_param( 

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

1246 ) 

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

1248 return param 

1249 

1250 

1251@overload 

1252def _create_update_prefetch_bind_param( 

1253 compiler: SQLCompiler, 

1254 c: ColumnElement[Any], 

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

1256 **kw: Any, 

1257) -> str: ... 

1258 

1259 

1260@overload 

1261def _create_update_prefetch_bind_param( 

1262 compiler: SQLCompiler, 

1263 c: ColumnElement[Any], 

1264 process: Literal[False], 

1265 **kw: Any, 

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

1267 

1268 

1269def _create_update_prefetch_bind_param( 

1270 compiler: SQLCompiler, 

1271 c: ColumnElement[Any], 

1272 process: bool = True, 

1273 name: Optional[str] = None, 

1274 **kw: Any, 

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

1276 param = _create_bind_param( 

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

1278 ) 

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

1280 return param 

1281 

1282 

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

1284 _is_multiparam_column = True 

1285 

1286 def __init__(self, original, index): 

1287 self.index = index 

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

1289 self.original = original 

1290 self.default = original.default 

1291 self.type = original.type 

1292 

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

1294 raise NotImplementedError() 

1295 

1296 def _copy_internals(self, **kw): 

1297 raise NotImplementedError() 

1298 

1299 def __eq__(self, other): 

1300 return ( 

1301 isinstance(other, _multiparam_column) 

1302 and other.key == self.key 

1303 and other.original == self.original 

1304 ) 

1305 

1306 @util.memoized_property 

1307 def _default_description_tuple(self) -> _DefaultDescriptionTuple: 

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

1309 

1310 return _DefaultDescriptionTuple._from_column_default(self.default) 

1311 

1312 @util.memoized_property 

1313 def _onupdate_description_tuple(self) -> _DefaultDescriptionTuple: 

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

1315 

1316 return _DefaultDescriptionTuple._from_column_default(self.onupdate) 

1317 

1318 

1319def _process_multiparam_default_bind( 

1320 compiler: SQLCompiler, 

1321 stmt: ValuesBase, 

1322 c: KeyedColumnElement[Any], 

1323 index: int, 

1324 kw: Dict[str, Any], 

1325) -> str: 

1326 if not c.default: 

1327 raise exc.CompileError( 

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

1329 "parameter in the VALUES clause; " 

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

1331 ) 

1332 elif default_is_clause_element(c.default): 

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

1334 elif c.default.is_sequence: 

1335 # these conditions would have been established 

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

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

1338 # checked 

1339 # assert compiler.dialect.supports_sequences and ( 

1340 # not c.default.optional 

1341 # or not compiler.dialect.sequences_optional 

1342 # ) 

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

1344 else: 

1345 col = _multiparam_column(c, index) 

1346 assert isinstance(stmt, dml.Insert) 

1347 return _create_insert_prefetch_bind_param( 

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

1349 ) 

1350 

1351 

1352def _get_update_multitable_params( 

1353 compiler, 

1354 stmt, 

1355 compile_state, 

1356 stmt_parameter_tuples, 

1357 check_columns, 

1358 _col_bind_name, 

1359 _getattr_col_key, 

1360 values, 

1361 kw, 

1362): 

1363 normalized_params = { 

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

1365 for c, param in stmt_parameter_tuples or () 

1366 } 

1367 

1368 include_table = compile_state.include_table_with_column_exprs 

1369 

1370 affected_tables = set() 

1371 for t in compile_state._extra_froms: 

1372 for c in t.c: 

1373 if c in normalized_params: 

1374 affected_tables.add(t) 

1375 check_columns[_getattr_col_key(c)] = c 

1376 value = normalized_params[c] 

1377 

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

1379 if coercions._is_literal(value): 

1380 value = _create_bind_param( 

1381 compiler, 

1382 c, 

1383 value, 

1384 required=value is REQUIRED, 

1385 name=_col_bind_name(c), 

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

1387 ) 

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

1389 elif value._is_bind_parameter: 

1390 cbn = _col_bind_name(c) 

1391 value = _handle_values_anonymous_param( 

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

1393 ) 

1394 accumulated_bind_names = (cbn,) 

1395 else: 

1396 compiler.postfetch.append(c) 

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

1398 accumulated_bind_names = () 

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

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

1401 # and server_onupdate for these 

1402 for t in affected_tables: 

1403 for c in t.c: 

1404 if c in normalized_params: 

1405 continue 

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

1407 if c.onupdate.is_clause_element: 

1408 values.append( 

1409 ( 

1410 c, 

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

1412 compiler.process( 

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

1414 ), 

1415 (), 

1416 ) 

1417 ) 

1418 compiler.postfetch.append(c) 

1419 else: 

1420 values.append( 

1421 ( 

1422 c, 

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

1424 _create_update_prefetch_bind_param( 

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

1426 ), 

1427 (c.key,), 

1428 ) 

1429 ) 

1430 elif c.server_onupdate is not None: 

1431 compiler.postfetch.append(c) 

1432 

1433 

1434def _extend_values_for_multiparams( 

1435 compiler: SQLCompiler, 

1436 stmt: ValuesBase, 

1437 compile_state: DMLState, 

1438 initial_values: Sequence[_CrudParamElementStr], 

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

1440 kw: Dict[str, Any], 

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

1442 values_0 = initial_values 

1443 values = [initial_values] 

1444 

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

1446 mp = compile_state._multi_parameters 

1447 assert mp is not None 

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

1449 extension: List[_CrudParamElementStr] = [] 

1450 

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

1452 

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

1454 if col.key in row: 

1455 key = col.key 

1456 

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

1458 new_param = _create_bind_param( 

1459 compiler, 

1460 col, 

1461 row[key], 

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

1463 force_anonymous=has_visiting_cte, 

1464 **kw, 

1465 ) 

1466 else: 

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

1468 else: 

1469 new_param = _process_multiparam_default_bind( 

1470 compiler, stmt, col, i, kw 

1471 ) 

1472 

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

1474 

1475 values.append(extension) 

1476 

1477 return values 

1478 

1479 

1480def _get_stmt_parameter_tuples_params( 

1481 compiler, 

1482 compile_state, 

1483 parameters, 

1484 stmt_parameter_tuples, 

1485 _column_as_key, 

1486 values, 

1487 kw, 

1488): 

1489 for k, v in stmt_parameter_tuples: 

1490 colkey = _column_as_key(k) 

1491 if colkey is not None: 

1492 parameters.setdefault(colkey, v) 

1493 else: 

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

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

1496 # coercing right side to bound param 

1497 

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

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

1500 

1501 col_expr = compiler.process( 

1502 k, include_table=compile_state.include_table_with_column_exprs 

1503 ) 

1504 

1505 if coercions._is_literal(v): 

1506 v = compiler.process( 

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

1508 ) 

1509 else: 

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

1511 # either unique parameter, or other bound parameters that 

1512 # were passed in directly 

1513 # set type to that of the column unconditionally 

1514 v = v._with_binary_element_type(k.type) 

1515 

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

1517 

1518 # TODO: not sure if accumulated_bind_names applies here 

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

1520 

1521 

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

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

1524 

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

1526 INSERT or UPDATE statement after it's invoked. 

1527 

1528 """ 

1529 

1530 dialect = compiler.dialect 

1531 

1532 need_pks = ( 

1533 toplevel 

1534 and _compile_state_isinsert(compile_state) 

1535 and not stmt._inline 

1536 and ( 

1537 not compiler.for_executemany 

1538 or (dialect.insert_executemany_returning and stmt._return_defaults) 

1539 ) 

1540 and not stmt._returning 

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

1542 and not compile_state._has_multi_parameters 

1543 ) 

1544 

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

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

1547 postfetch_lastrowid = ( 

1548 need_pks 

1549 and dialect.postfetch_lastrowid 

1550 and stmt.table._autoincrement_column is not None 

1551 ) 

1552 

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

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

1555 # if that's set. 

1556 implicit_returning = ( 

1557 # statement itself can veto it 

1558 need_pks 

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

1560 # with INSERT 

1561 and dialect.insert_returning 

1562 # user-defined implicit_returning on Table can veto it 

1563 and compile_state._primary_table.implicit_returning 

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

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

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

1567 and compile_state._supports_implicit_returning 

1568 and ( 

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

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

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

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

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

1574 # SQLite lastrowid times 3x faster than returning, 

1575 # Mariadb lastrowid 2x faster than returning 

1576 (not postfetch_lastrowid or dialect.favor_returning_over_lastrowid) 

1577 or compile_state._has_multi_parameters 

1578 or stmt._return_defaults 

1579 ) 

1580 ) 

1581 if implicit_returning: 

1582 postfetch_lastrowid = False 

1583 

1584 if _compile_state_isinsert(compile_state): 

1585 should_implicit_return_defaults = ( 

1586 implicit_returning and stmt._return_defaults 

1587 ) 

1588 explicit_returning = ( 

1589 should_implicit_return_defaults 

1590 or stmt._returning 

1591 or stmt._supplemental_returning 

1592 ) 

1593 use_insertmanyvalues = ( 

1594 toplevel 

1595 and compiler.for_executemany 

1596 and dialect.use_insertmanyvalues 

1597 and ( 

1598 explicit_returning or dialect.use_insertmanyvalues_wo_returning 

1599 ) 

1600 ) 

1601 

1602 use_sentinel_columns = None 

1603 if ( 

1604 use_insertmanyvalues 

1605 and explicit_returning 

1606 and stmt._sort_by_parameter_order 

1607 ): 

1608 use_sentinel_columns = compiler._get_sentinel_column_for_table( 

1609 stmt.table 

1610 ) 

1611 

1612 elif compile_state.isupdate: 

1613 should_implicit_return_defaults = ( 

1614 stmt._return_defaults 

1615 and compile_state._primary_table.implicit_returning 

1616 and compile_state._supports_implicit_returning 

1617 and dialect.update_returning 

1618 ) 

1619 use_insertmanyvalues = False 

1620 use_sentinel_columns = None 

1621 elif compile_state.isdelete: 

1622 should_implicit_return_defaults = ( 

1623 stmt._return_defaults 

1624 and compile_state._primary_table.implicit_returning 

1625 and compile_state._supports_implicit_returning 

1626 and dialect.delete_returning 

1627 ) 

1628 use_insertmanyvalues = False 

1629 use_sentinel_columns = None 

1630 else: 

1631 should_implicit_return_defaults = False # pragma: no cover 

1632 use_insertmanyvalues = False 

1633 use_sentinel_columns = None 

1634 

1635 if should_implicit_return_defaults: 

1636 if not stmt._return_defaults_columns: 

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

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

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

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

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

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

1643 implicit_return_defaults = set(stmt.table.c) 

1644 else: 

1645 implicit_return_defaults = set(stmt._return_defaults_columns) 

1646 else: 

1647 implicit_return_defaults = None 

1648 

1649 return ( 

1650 need_pks, 

1651 implicit_returning or should_implicit_return_defaults, 

1652 implicit_return_defaults, 

1653 postfetch_lastrowid, 

1654 use_insertmanyvalues, 

1655 use_sentinel_columns, 

1656 ) 

1657 

1658 

1659def _warn_pk_with_no_anticipated_value(c): 

1660 msg = ( 

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

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

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

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

1665 "and no explicit value is passed. " 

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

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

1668 ) 

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

1670 msg += ( 

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

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

1673 "keys if AUTO_INCREMENT/SERIAL/IDENTITY " 

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

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

1676 "most backends." 

1677 ) 

1678 util.warn(msg)