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

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

481 statements  

1# sql/crud.py 

2# Copyright (C) 2005-2024 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 = 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 **kw: Any, 

397) -> str: ... 

398 

399 

400@overload 

401def _create_bind_param( 

402 compiler: SQLCompiler, 

403 col: ColumnElement[Any], 

404 value: Any, 

405 **kw: Any, 

406) -> str: ... 

407 

408 

409def _create_bind_param( 

410 compiler: SQLCompiler, 

411 col: ColumnElement[Any], 

412 value: Any, 

413 process: bool = True, 

414 required: bool = False, 

415 name: Optional[str] = None, 

416 **kw: Any, 

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

418 if name is None: 

419 name = col.key 

420 bindparam = elements.BindParameter( 

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

422 ) 

423 bindparam._is_crud = True 

424 if process: 

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

426 else: 

427 return bindparam 

428 

429 

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

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

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

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

434 # produce bound parameters in deterministic order without invoking any 

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

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

437 # right now). 

438 # 

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

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

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

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

443 # rather than having 

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

445 # name. Saves on call counts also. 

446 

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

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

449 # multiple insert/update are combined together using CTEs 

450 is_cte = "visiting_cte" in kw 

451 

452 if ( 

453 not is_cte 

454 and value.unique 

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

456 ): 

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

458 

459 if value.type._isnull: 

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

461 # passed in directly 

462 # set type to that of the column unconditionally 

463 value = value._with_binary_element_type(col.type) 

464 

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

466 

467 

468def _key_getters_for_crud_column( 

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

470) -> Tuple[ 

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

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

473 _BindNameForColProtocol, 

474]: 

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

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

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

478 # dictionaries and when rendering bind param names. 

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

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

481 # statement. 

482 _et = set(compile_state._extra_froms) 

483 

484 c_key_role = functools.partial( 

485 coercions.expect_as_key, roles.DMLColumnRole 

486 ) 

487 

488 def _column_as_key( 

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

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

491 str_key = c_key_role(key) 

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

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

494 else: 

495 return str_key 

496 

497 def _getattr_col_key( 

498 col: ColumnClause[Any], 

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

500 if col.table in _et: 

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

502 else: 

503 return col.key 

504 

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

506 if col.table in _et: 

507 if TYPE_CHECKING: 

508 assert isinstance(col.table, TableClause) 

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

510 else: 

511 return col.key 

512 

513 else: 

514 _column_as_key = functools.partial( 

515 coercions.expect_as_key, roles.DMLColumnRole 

516 ) 

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

518 

519 return _column_as_key, _getattr_col_key, _col_bind_name 

520 

521 

522def _scan_insert_from_select_cols( 

523 compiler, 

524 stmt, 

525 compile_state, 

526 parameters, 

527 _getattr_col_key, 

528 _column_as_key, 

529 _col_bind_name, 

530 check_columns, 

531 values, 

532 toplevel, 

533 kw, 

534): 

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

536 

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

538 

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

540 

541 add_select_cols: List[_CrudParamElementSQLExpr] = [] 

542 if stmt.include_insert_from_select_defaults: 

543 col_set = set(cols) 

544 for col in stmt.table.columns: 

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

546 # this will omit columns marked as omit_from_statements naturally, 

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

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

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

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

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

552 # here so we again omit it. 

553 if ( 

554 col not in col_set 

555 and col.default 

556 and not col.default.is_sentinel 

557 ): 

558 cols.append(col) 

559 

560 for c in cols: 

561 col_key = _getattr_col_key(c) 

562 if col_key in parameters and col_key not in check_columns: 

563 parameters.pop(col_key) 

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

565 else: 

566 _append_param_insert_select_hasdefault( 

567 compiler, stmt, c, add_select_cols, kw 

568 ) 

569 

570 if add_select_cols: 

571 values.extend(add_select_cols) 

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

573 if not isinstance(ins_from_select, Select): 

574 raise exc.CompileError( 

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

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

577 f"""{ 

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

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

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

581 "columns." 

582 ) 

583 ins_from_select = ins_from_select._generate() 

584 # copy raw_columns 

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

586 expr for _, _, expr, _ in add_select_cols 

587 ] 

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

589 

590 

591def _scan_cols( 

592 compiler, 

593 stmt, 

594 compile_state, 

595 parameters, 

596 _getattr_col_key, 

597 _column_as_key, 

598 _col_bind_name, 

599 check_columns, 

600 values, 

601 toplevel, 

602 kw, 

603): 

604 ( 

605 need_pks, 

606 implicit_returning, 

607 implicit_return_defaults, 

608 postfetch_lastrowid, 

609 use_insertmanyvalues, 

610 use_sentinel_columns, 

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

612 

613 assert compile_state.isupdate or compile_state.isinsert 

614 

615 if compile_state._parameter_ordering: 

616 parameter_ordering = [ 

617 _column_as_key(key) for key in compile_state._parameter_ordering 

618 ] 

619 ordered_keys = set(parameter_ordering) 

620 cols = [ 

621 stmt.table.c[key] 

622 for key in parameter_ordering 

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

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

625 

626 else: 

627 cols = stmt.table.columns 

628 

629 isinsert = _compile_state_isinsert(compile_state) 

630 if isinsert and not compile_state._has_multi_parameters: 

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

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

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

634 autoincrement_col = stmt.table._autoincrement_column 

635 insert_null_pk_still_autoincrements = ( 

636 compiler.dialect.insert_null_pk_still_autoincrements 

637 ) 

638 else: 

639 autoincrement_col = insert_null_pk_still_autoincrements = None 

640 

641 if stmt._supplemental_returning: 

642 supplemental_returning = set(stmt._supplemental_returning) 

643 else: 

644 supplemental_returning = set() 

645 

646 compiler_implicit_returning = compiler.implicit_returning 

647 

648 # TODO - see TODO(return_defaults_columns) below 

649 # cols_in_params = set() 

650 

651 for c in cols: 

652 # scan through every column in the target table 

653 

654 col_key = _getattr_col_key(c) 

655 

656 if col_key in parameters and col_key not in check_columns: 

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

658 

659 _append_param_parameter( 

660 compiler, 

661 stmt, 

662 compile_state, 

663 c, 

664 col_key, 

665 parameters, 

666 _col_bind_name, 

667 implicit_returning, 

668 implicit_return_defaults, 

669 postfetch_lastrowid, 

670 values, 

671 autoincrement_col, 

672 insert_null_pk_still_autoincrements, 

673 kw, 

674 ) 

675 

676 # TODO - see TODO(return_defaults_columns) below 

677 # cols_in_params.add(c) 

678 

679 elif isinsert: 

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

681 

682 if c.primary_key and need_pks: 

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

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

685 # inserted_primary_key to be available. 

686 

687 if implicit_returning: 

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

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

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

691 

692 _append_param_insert_pk_returning( 

693 compiler, stmt, c, values, kw 

694 ) 

695 else: 

696 # otherwise, find out how to invoke this column 

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

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

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

700 # autoincrement column and the dialect supports it 

701 # we can use cursor.lastrowid. 

702 

703 _append_param_insert_pk_no_returning( 

704 compiler, stmt, c, values, kw 

705 ) 

706 

707 elif c.default is not None: 

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

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

710 if not c.default.is_sentinel or ( 

711 use_sentinel_columns is not None 

712 ): 

713 _append_param_insert_hasdefault( 

714 compiler, stmt, c, implicit_return_defaults, values, kw 

715 ) 

716 

717 elif c.server_default is not None: 

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

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

720 if implicit_return_defaults and c in implicit_return_defaults: 

721 compiler_implicit_returning.append(c) 

722 elif not c.primary_key: 

723 compiler.postfetch.append(c) 

724 

725 elif implicit_return_defaults and c in implicit_return_defaults: 

726 compiler_implicit_returning.append(c) 

727 

728 elif ( 

729 c.primary_key 

730 and c is not stmt.table._autoincrement_column 

731 and not c.nullable 

732 ): 

733 _warn_pk_with_no_anticipated_value(c) 

734 

735 elif compile_state.isupdate: 

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

737 

738 _append_param_update( 

739 compiler, 

740 compile_state, 

741 stmt, 

742 c, 

743 implicit_return_defaults, 

744 values, 

745 kw, 

746 ) 

747 

748 # adding supplemental cols to implicit_returning in table 

749 # order so that order is maintained between multiple INSERT 

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

751 # have the same RETURNING clause 

752 if ( 

753 c in supplemental_returning 

754 and c not in compiler_implicit_returning 

755 ): 

756 compiler_implicit_returning.append(c) 

757 

758 if supplemental_returning: 

759 # we should have gotten every col into implicit_returning, 

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

761 # in it 

762 remaining_supplemental = supplemental_returning.difference( 

763 compiler_implicit_returning 

764 ) 

765 compiler_implicit_returning.extend( 

766 c 

767 for c in stmt._supplemental_returning 

768 if c in remaining_supplemental 

769 ) 

770 

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

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

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

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

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

776 

777 # if stmt._return_defaults_columns: 

778 # compiler_implicit_returning.extend( 

779 # set(stmt._return_defaults_columns) 

780 # .difference(compiler_implicit_returning) 

781 # .difference(cols_in_params) 

782 # ) 

783 

784 return (use_insertmanyvalues, use_sentinel_columns) 

785 

786 

787def _setup_delete_return_defaults( 

788 compiler, 

789 stmt, 

790 compile_state, 

791 parameters, 

792 _getattr_col_key, 

793 _column_as_key, 

794 _col_bind_name, 

795 check_columns, 

796 values, 

797 toplevel, 

798 kw, 

799): 

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

801 compiler, stmt, compile_state, toplevel 

802 ) 

803 

804 if not implicit_return_defaults: 

805 return 

806 

807 if stmt._return_defaults_columns: 

808 compiler.implicit_returning.extend(implicit_return_defaults) 

809 

810 if stmt._supplemental_returning: 

811 ir_set = set(compiler.implicit_returning) 

812 compiler.implicit_returning.extend( 

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

814 ) 

815 

816 

817def _append_param_parameter( 

818 compiler, 

819 stmt, 

820 compile_state, 

821 c, 

822 col_key, 

823 parameters, 

824 _col_bind_name, 

825 implicit_returning, 

826 implicit_return_defaults, 

827 postfetch_lastrowid, 

828 values, 

829 autoincrement_col, 

830 insert_null_pk_still_autoincrements, 

831 kw, 

832): 

833 value = parameters.pop(col_key) 

834 

835 col_value = compiler.preparer.format_column( 

836 c, use_table=compile_state.include_table_with_column_exprs 

837 ) 

838 

839 accumulated_bind_names: Set[str] = set() 

840 

841 if coercions._is_literal(value): 

842 if ( 

843 insert_null_pk_still_autoincrements 

844 and c.primary_key 

845 and c is autoincrement_col 

846 ): 

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

848 # even if value was given. 

849 

850 if postfetch_lastrowid: 

851 compiler.postfetch_lastrowid = True 

852 elif implicit_returning: 

853 compiler.implicit_returning.append(c) 

854 

855 value = _create_bind_param( 

856 compiler, 

857 c, 

858 value, 

859 required=value is REQUIRED, 

860 name=( 

861 _col_bind_name(c) 

862 if not _compile_state_isinsert(compile_state) 

863 or not compile_state._has_multi_parameters 

864 else "%s_m0" % _col_bind_name(c) 

865 ), 

866 accumulate_bind_names=accumulated_bind_names, 

867 **kw, 

868 ) 

869 elif value._is_bind_parameter: 

870 if ( 

871 insert_null_pk_still_autoincrements 

872 and value.value is None 

873 and c.primary_key 

874 and c is autoincrement_col 

875 ): 

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

877 # even if value was given 

878 if implicit_returning: 

879 compiler.implicit_returning.append(c) 

880 elif compiler.dialect.postfetch_lastrowid: 

881 compiler.postfetch_lastrowid = True 

882 

883 value = _handle_values_anonymous_param( 

884 compiler, 

885 c, 

886 value, 

887 name=( 

888 _col_bind_name(c) 

889 if not _compile_state_isinsert(compile_state) 

890 or not compile_state._has_multi_parameters 

891 else "%s_m0" % _col_bind_name(c) 

892 ), 

893 accumulate_bind_names=accumulated_bind_names, 

894 **kw, 

895 ) 

896 else: 

897 # value is a SQL expression 

898 value = compiler.process( 

899 value.self_group(), 

900 accumulate_bind_names=accumulated_bind_names, 

901 **kw, 

902 ) 

903 

904 if compile_state.isupdate: 

905 if implicit_return_defaults and c in implicit_return_defaults: 

906 compiler.implicit_returning.append(c) 

907 

908 else: 

909 compiler.postfetch.append(c) 

910 else: 

911 if c.primary_key: 

912 if implicit_returning: 

913 compiler.implicit_returning.append(c) 

914 elif compiler.dialect.postfetch_lastrowid: 

915 compiler.postfetch_lastrowid = True 

916 

917 elif implicit_return_defaults and (c in implicit_return_defaults): 

918 compiler.implicit_returning.append(c) 

919 

920 else: 

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

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

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

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

925 # time. 

926 

927 compiler.postfetch.append(c) 

928 

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

930 

931 

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

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

934 we want to populate result.inserted_primary_key and RETURNING 

935 is available. 

936 

937 """ 

938 if c.default is not None: 

939 if c.default.is_sequence: 

940 if compiler.dialect.supports_sequences and ( 

941 not c.default.optional 

942 or not compiler.dialect.sequences_optional 

943 ): 

944 accumulated_bind_names: Set[str] = set() 

945 values.append( 

946 ( 

947 c, 

948 compiler.preparer.format_column(c), 

949 compiler.process( 

950 c.default, 

951 accumulate_bind_names=accumulated_bind_names, 

952 **kw, 

953 ), 

954 accumulated_bind_names, 

955 ) 

956 ) 

957 compiler.implicit_returning.append(c) 

958 elif c.default.is_clause_element: 

959 accumulated_bind_names = set() 

960 values.append( 

961 ( 

962 c, 

963 compiler.preparer.format_column(c), 

964 compiler.process( 

965 c.default.arg.self_group(), 

966 accumulate_bind_names=accumulated_bind_names, 

967 **kw, 

968 ), 

969 accumulated_bind_names, 

970 ) 

971 ) 

972 compiler.implicit_returning.append(c) 

973 else: 

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

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

976 # on the Python side 

977 values.append( 

978 ( 

979 c, 

980 compiler.preparer.format_column(c), 

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

982 (c.key,), 

983 ) 

984 ) 

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

986 compiler.implicit_returning.append(c) 

987 elif not c.nullable: 

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

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

990 _warn_pk_with_no_anticipated_value(c) 

991 

992 

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

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

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

996 RETURNING. 

997 

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

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

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

1001 

1002 

1003 """ 

1004 

1005 if ( 

1006 # column has a Python-side default 

1007 c.default is not None 

1008 and ( 

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

1010 # sequences and want to invoke it 

1011 not c.default.is_sequence 

1012 or ( 

1013 compiler.dialect.supports_sequences 

1014 and ( 

1015 not c.default.optional 

1016 or not compiler.dialect.sequences_optional 

1017 ) 

1018 ) 

1019 ) 

1020 ) or ( 

1021 # column is the "autoincrement column" 

1022 c is stmt.table._autoincrement_column 

1023 and ( 

1024 # dialect can't use cursor.lastrowid 

1025 not compiler.dialect.postfetch_lastrowid 

1026 and ( 

1027 # column has a Sequence and we support those 

1028 ( 

1029 c.default is not None 

1030 and c.default.is_sequence 

1031 and compiler.dialect.supports_sequences 

1032 ) 

1033 or 

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

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

1036 # SERIAL we know the sequence name 

1037 ( 

1038 c.default is None 

1039 and compiler.dialect.preexecute_autoincrement_sequences 

1040 ) 

1041 ) 

1042 ) 

1043 ): 

1044 # do a pre-execute of the default 

1045 values.append( 

1046 ( 

1047 c, 

1048 compiler.preparer.format_column(c), 

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

1050 (c.key,), 

1051 ) 

1052 ) 

1053 elif ( 

1054 c.default is None 

1055 and c.server_default is None 

1056 and not c.nullable 

1057 and c is not stmt.table._autoincrement_column 

1058 ): 

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

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

1061 _warn_pk_with_no_anticipated_value(c) 

1062 elif compiler.dialect.postfetch_lastrowid: 

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

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

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

1066 # that the DefaultExecutionContext calls upon cursor.lastrowid 

1067 compiler.postfetch_lastrowid = True 

1068 

1069 

1070def _append_param_insert_hasdefault( 

1071 compiler, stmt, c, implicit_return_defaults, values, kw 

1072): 

1073 if c.default.is_sequence: 

1074 if compiler.dialect.supports_sequences and ( 

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

1076 ): 

1077 accumulated_bind_names: Set[str] = set() 

1078 values.append( 

1079 ( 

1080 c, 

1081 compiler.preparer.format_column(c), 

1082 compiler.process( 

1083 c.default, 

1084 accumulate_bind_names=accumulated_bind_names, 

1085 **kw, 

1086 ), 

1087 accumulated_bind_names, 

1088 ) 

1089 ) 

1090 if implicit_return_defaults and c in implicit_return_defaults: 

1091 compiler.implicit_returning.append(c) 

1092 elif not c.primary_key: 

1093 compiler.postfetch.append(c) 

1094 elif c.default.is_clause_element: 

1095 accumulated_bind_names = set() 

1096 values.append( 

1097 ( 

1098 c, 

1099 compiler.preparer.format_column(c), 

1100 compiler.process( 

1101 c.default.arg.self_group(), 

1102 accumulate_bind_names=accumulated_bind_names, 

1103 **kw, 

1104 ), 

1105 accumulated_bind_names, 

1106 ) 

1107 ) 

1108 

1109 if implicit_return_defaults and c in implicit_return_defaults: 

1110 compiler.implicit_returning.append(c) 

1111 elif not c.primary_key: 

1112 # don't add primary key column to postfetch 

1113 compiler.postfetch.append(c) 

1114 else: 

1115 values.append( 

1116 ( 

1117 c, 

1118 compiler.preparer.format_column(c), 

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

1120 (c.key,), 

1121 ) 

1122 ) 

1123 

1124 

1125def _append_param_insert_select_hasdefault( 

1126 compiler: SQLCompiler, 

1127 stmt: ValuesBase, 

1128 c: ColumnClause[Any], 

1129 values: List[_CrudParamElementSQLExpr], 

1130 kw: Dict[str, Any], 

1131) -> None: 

1132 if default_is_sequence(c.default): 

1133 if compiler.dialect.supports_sequences and ( 

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

1135 ): 

1136 values.append( 

1137 ( 

1138 c, 

1139 compiler.preparer.format_column(c), 

1140 c.default.next_value(), 

1141 (), 

1142 ) 

1143 ) 

1144 elif default_is_clause_element(c.default): 

1145 values.append( 

1146 ( 

1147 c, 

1148 compiler.preparer.format_column(c), 

1149 c.default.arg.self_group(), 

1150 (), 

1151 ) 

1152 ) 

1153 else: 

1154 values.append( 

1155 ( 

1156 c, 

1157 compiler.preparer.format_column(c), 

1158 _create_insert_prefetch_bind_param( 

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

1160 ), 

1161 (c.key,), 

1162 ) 

1163 ) 

1164 

1165 

1166def _append_param_update( 

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

1168): 

1169 include_table = compile_state.include_table_with_column_exprs 

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

1171 if c.onupdate.is_clause_element: 

1172 values.append( 

1173 ( 

1174 c, 

1175 compiler.preparer.format_column( 

1176 c, 

1177 use_table=include_table, 

1178 ), 

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

1180 (), 

1181 ) 

1182 ) 

1183 if implicit_return_defaults and c in implicit_return_defaults: 

1184 compiler.implicit_returning.append(c) 

1185 else: 

1186 compiler.postfetch.append(c) 

1187 else: 

1188 values.append( 

1189 ( 

1190 c, 

1191 compiler.preparer.format_column( 

1192 c, 

1193 use_table=include_table, 

1194 ), 

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

1196 (c.key,), 

1197 ) 

1198 ) 

1199 elif c.server_onupdate is not None: 

1200 if implicit_return_defaults and c in implicit_return_defaults: 

1201 compiler.implicit_returning.append(c) 

1202 else: 

1203 compiler.postfetch.append(c) 

1204 elif ( 

1205 implicit_return_defaults 

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

1207 and c in implicit_return_defaults 

1208 ): 

1209 compiler.implicit_returning.append(c) 

1210 

1211 

1212@overload 

1213def _create_insert_prefetch_bind_param( 

1214 compiler: SQLCompiler, 

1215 c: ColumnElement[Any], 

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

1217 **kw: Any, 

1218) -> str: ... 

1219 

1220 

1221@overload 

1222def _create_insert_prefetch_bind_param( 

1223 compiler: SQLCompiler, 

1224 c: ColumnElement[Any], 

1225 process: Literal[False], 

1226 **kw: Any, 

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

1228 

1229 

1230def _create_insert_prefetch_bind_param( 

1231 compiler: SQLCompiler, 

1232 c: ColumnElement[Any], 

1233 process: bool = True, 

1234 name: Optional[str] = None, 

1235 **kw: Any, 

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

1237 param = _create_bind_param( 

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

1239 ) 

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

1241 return param 

1242 

1243 

1244@overload 

1245def _create_update_prefetch_bind_param( 

1246 compiler: SQLCompiler, 

1247 c: ColumnElement[Any], 

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

1249 **kw: Any, 

1250) -> str: ... 

1251 

1252 

1253@overload 

1254def _create_update_prefetch_bind_param( 

1255 compiler: SQLCompiler, 

1256 c: ColumnElement[Any], 

1257 process: Literal[False], 

1258 **kw: Any, 

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

1260 

1261 

1262def _create_update_prefetch_bind_param( 

1263 compiler: SQLCompiler, 

1264 c: ColumnElement[Any], 

1265 process: bool = True, 

1266 name: Optional[str] = None, 

1267 **kw: Any, 

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

1269 param = _create_bind_param( 

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

1271 ) 

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

1273 return param 

1274 

1275 

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

1277 _is_multiparam_column = True 

1278 

1279 def __init__(self, original, index): 

1280 self.index = index 

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

1282 self.original = original 

1283 self.default = original.default 

1284 self.type = original.type 

1285 

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

1287 raise NotImplementedError() 

1288 

1289 def _copy_internals(self, **kw): 

1290 raise NotImplementedError() 

1291 

1292 def __eq__(self, other): 

1293 return ( 

1294 isinstance(other, _multiparam_column) 

1295 and other.key == self.key 

1296 and other.original == self.original 

1297 ) 

1298 

1299 @util.memoized_property 

1300 def _default_description_tuple(self) -> _DefaultDescriptionTuple: 

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

1302 

1303 return _DefaultDescriptionTuple._from_column_default(self.default) 

1304 

1305 @util.memoized_property 

1306 def _onupdate_description_tuple(self) -> _DefaultDescriptionTuple: 

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

1308 

1309 return _DefaultDescriptionTuple._from_column_default(self.onupdate) 

1310 

1311 

1312def _process_multiparam_default_bind( 

1313 compiler: SQLCompiler, 

1314 stmt: ValuesBase, 

1315 c: KeyedColumnElement[Any], 

1316 index: int, 

1317 kw: Dict[str, Any], 

1318) -> str: 

1319 if not c.default: 

1320 raise exc.CompileError( 

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

1322 "parameter in the VALUES clause; " 

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

1324 ) 

1325 elif default_is_clause_element(c.default): 

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

1327 elif c.default.is_sequence: 

1328 # these conditions would have been established 

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

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

1331 # checked 

1332 # assert compiler.dialect.supports_sequences and ( 

1333 # not c.default.optional 

1334 # or not compiler.dialect.sequences_optional 

1335 # ) 

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

1337 else: 

1338 col = _multiparam_column(c, index) 

1339 assert isinstance(stmt, dml.Insert) 

1340 return _create_insert_prefetch_bind_param( 

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

1342 ) 

1343 

1344 

1345def _get_update_multitable_params( 

1346 compiler, 

1347 stmt, 

1348 compile_state, 

1349 stmt_parameter_tuples, 

1350 check_columns, 

1351 _col_bind_name, 

1352 _getattr_col_key, 

1353 values, 

1354 kw, 

1355): 

1356 normalized_params = { 

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

1358 for c, param in stmt_parameter_tuples or () 

1359 } 

1360 

1361 include_table = compile_state.include_table_with_column_exprs 

1362 

1363 affected_tables = set() 

1364 for t in compile_state._extra_froms: 

1365 for c in t.c: 

1366 if c in normalized_params: 

1367 affected_tables.add(t) 

1368 check_columns[_getattr_col_key(c)] = c 

1369 value = normalized_params[c] 

1370 

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

1372 if coercions._is_literal(value): 

1373 value = _create_bind_param( 

1374 compiler, 

1375 c, 

1376 value, 

1377 required=value is REQUIRED, 

1378 name=_col_bind_name(c), 

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

1380 ) 

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

1382 elif value._is_bind_parameter: 

1383 cbn = _col_bind_name(c) 

1384 value = _handle_values_anonymous_param( 

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

1386 ) 

1387 accumulated_bind_names = (cbn,) 

1388 else: 

1389 compiler.postfetch.append(c) 

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

1391 accumulated_bind_names = () 

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

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

1394 # and server_onupdate for these 

1395 for t in affected_tables: 

1396 for c in t.c: 

1397 if c in normalized_params: 

1398 continue 

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

1400 if c.onupdate.is_clause_element: 

1401 values.append( 

1402 ( 

1403 c, 

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

1405 compiler.process( 

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

1407 ), 

1408 (), 

1409 ) 

1410 ) 

1411 compiler.postfetch.append(c) 

1412 else: 

1413 values.append( 

1414 ( 

1415 c, 

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

1417 _create_update_prefetch_bind_param( 

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

1419 ), 

1420 (c.key,), 

1421 ) 

1422 ) 

1423 elif c.server_onupdate is not None: 

1424 compiler.postfetch.append(c) 

1425 

1426 

1427def _extend_values_for_multiparams( 

1428 compiler: SQLCompiler, 

1429 stmt: ValuesBase, 

1430 compile_state: DMLState, 

1431 initial_values: Sequence[_CrudParamElementStr], 

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

1433 kw: Dict[str, Any], 

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

1435 values_0 = initial_values 

1436 values = [initial_values] 

1437 

1438 mp = compile_state._multi_parameters 

1439 assert mp is not None 

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

1441 extension: List[_CrudParamElementStr] = [] 

1442 

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

1444 

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

1446 if col.key in row: 

1447 key = col.key 

1448 

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

1450 new_param = _create_bind_param( 

1451 compiler, 

1452 col, 

1453 row[key], 

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

1455 **kw, 

1456 ) 

1457 else: 

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

1459 else: 

1460 new_param = _process_multiparam_default_bind( 

1461 compiler, stmt, col, i, kw 

1462 ) 

1463 

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

1465 

1466 values.append(extension) 

1467 

1468 return values 

1469 

1470 

1471def _get_stmt_parameter_tuples_params( 

1472 compiler, 

1473 compile_state, 

1474 parameters, 

1475 stmt_parameter_tuples, 

1476 _column_as_key, 

1477 values, 

1478 kw, 

1479): 

1480 for k, v in stmt_parameter_tuples: 

1481 colkey = _column_as_key(k) 

1482 if colkey is not None: 

1483 parameters.setdefault(colkey, v) 

1484 else: 

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

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

1487 # coercing right side to bound param 

1488 

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

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

1491 

1492 col_expr = compiler.process( 

1493 k, include_table=compile_state.include_table_with_column_exprs 

1494 ) 

1495 

1496 if coercions._is_literal(v): 

1497 v = compiler.process( 

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

1499 ) 

1500 else: 

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

1502 # either unique parameter, or other bound parameters that 

1503 # were passed in directly 

1504 # set type to that of the column unconditionally 

1505 v = v._with_binary_element_type(k.type) 

1506 

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

1508 

1509 # TODO: not sure if accumulated_bind_names applies here 

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

1511 

1512 

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

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

1515 

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

1517 INSERT or UPDATE statement after it's invoked. 

1518 

1519 """ 

1520 

1521 dialect = compiler.dialect 

1522 

1523 need_pks = ( 

1524 toplevel 

1525 and _compile_state_isinsert(compile_state) 

1526 and not stmt._inline 

1527 and ( 

1528 not compiler.for_executemany 

1529 or (dialect.insert_executemany_returning and stmt._return_defaults) 

1530 ) 

1531 and not stmt._returning 

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

1533 and not compile_state._has_multi_parameters 

1534 ) 

1535 

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

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

1538 postfetch_lastrowid = ( 

1539 need_pks 

1540 and dialect.postfetch_lastrowid 

1541 and stmt.table._autoincrement_column is not None 

1542 ) 

1543 

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

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

1546 # if that's set. 

1547 implicit_returning = ( 

1548 # statement itself can veto it 

1549 need_pks 

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

1551 # with INSERT 

1552 and dialect.insert_returning 

1553 # user-defined implicit_returning on Table can veto it 

1554 and compile_state._primary_table.implicit_returning 

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

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

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

1558 and compile_state._supports_implicit_returning 

1559 and ( 

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

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

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

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

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

1565 # SQLite lastrowid times 3x faster than returning, 

1566 # Mariadb lastrowid 2x faster than returning 

1567 (not postfetch_lastrowid or dialect.favor_returning_over_lastrowid) 

1568 or compile_state._has_multi_parameters 

1569 or stmt._return_defaults 

1570 ) 

1571 ) 

1572 if implicit_returning: 

1573 postfetch_lastrowid = False 

1574 

1575 if _compile_state_isinsert(compile_state): 

1576 should_implicit_return_defaults = ( 

1577 implicit_returning and stmt._return_defaults 

1578 ) 

1579 explicit_returning = ( 

1580 should_implicit_return_defaults 

1581 or stmt._returning 

1582 or stmt._supplemental_returning 

1583 ) 

1584 use_insertmanyvalues = ( 

1585 toplevel 

1586 and compiler.for_executemany 

1587 and dialect.use_insertmanyvalues 

1588 and ( 

1589 explicit_returning or dialect.use_insertmanyvalues_wo_returning 

1590 ) 

1591 ) 

1592 

1593 use_sentinel_columns = None 

1594 if ( 

1595 use_insertmanyvalues 

1596 and explicit_returning 

1597 and stmt._sort_by_parameter_order 

1598 ): 

1599 use_sentinel_columns = compiler._get_sentinel_column_for_table( 

1600 stmt.table 

1601 ) 

1602 

1603 elif compile_state.isupdate: 

1604 should_implicit_return_defaults = ( 

1605 stmt._return_defaults 

1606 and compile_state._primary_table.implicit_returning 

1607 and compile_state._supports_implicit_returning 

1608 and dialect.update_returning 

1609 ) 

1610 use_insertmanyvalues = False 

1611 use_sentinel_columns = None 

1612 elif compile_state.isdelete: 

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

1618 ) 

1619 use_insertmanyvalues = False 

1620 use_sentinel_columns = None 

1621 else: 

1622 should_implicit_return_defaults = False # pragma: no cover 

1623 use_insertmanyvalues = False 

1624 use_sentinel_columns = None 

1625 

1626 if should_implicit_return_defaults: 

1627 if not stmt._return_defaults_columns: 

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

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

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

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

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

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

1634 implicit_return_defaults = set(stmt.table.c) 

1635 else: 

1636 implicit_return_defaults = set(stmt._return_defaults_columns) 

1637 else: 

1638 implicit_return_defaults = None 

1639 

1640 return ( 

1641 need_pks, 

1642 implicit_returning or should_implicit_return_defaults, 

1643 implicit_return_defaults, 

1644 postfetch_lastrowid, 

1645 use_insertmanyvalues, 

1646 use_sentinel_columns, 

1647 ) 

1648 

1649 

1650def _warn_pk_with_no_anticipated_value(c): 

1651 msg = ( 

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

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

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

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

1656 "and no explicit value is passed. " 

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

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

1659 ) 

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

1661 msg += ( 

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

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

1664 "keys if AUTO_INCREMENT/SERIAL/IDENTITY " 

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

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

1667 "most backends." 

1668 ) 

1669 util.warn(msg)