Extend multi-row INSERT (addRow) to execute() and loop-friendly call shapes (#1825)#1826
Open
zio0911 wants to merge 2 commits into
Open
Extend multi-row INSERT (addRow) to execute() and loop-friendly call shapes (#1825)#1826zio0911 wants to merge 2 commits into
zio0911 wants to merge 2 commits into
Conversation
Previously addRow() only produced a multi-row INSERT when keys were returned via executeWithKeys(); a plain execute() ignored the accumulated rows and inserted only the trailing row. - execute() now emits a single native INSERT INTO t (...) VALUES (..),(..),... when rows were accumulated via addRow(), in both JPAInsertClause and HibernateInsertClause; a trailing un-flushed row is treated as the last row (loop-friendly, no first-row bookkeeping). - Add JpaInsertNativeHelper.requireSqlModule(): the native insert paths depend on the optional querydsl-sql module, so guard them with an actionable IllegalStateException instead of a bare NoClassDefFoundError when querydsl-sql is absent from the classpath. - Clarify addRow() Javadoc: it builds a single multi-row VALUES statement, not JDBC batching.
…penFeign#1825) set()-style + a trailing addRow() at the end of every loop iteration left both the inserts map and the columns list empty after the loop, so executors threw "No columns specified for insert". Callers had to keep a "first row" flag and intentionally leave the last row in the buffer to recover the column list from inserts.keySet(). addRow() now captures the effective column paths on its first call. executeMultiRow() and executeWithKeys() fall back to those captured paths when the current-state inserts/columns are empty. Combined with the prior change that routes execute() to a native multi-row INSERT when rows were accumulated, the loop-friendly shape for (var r : rows) { insert.set(...).set(...).addRow(); } insert.execute(); // or executeWithKeys(...) when keys are needed now works for both JPAInsertClause and HibernateInsertClause with no first-row bookkeeping and no buffer-retention trick.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes #1825. Two related improvements to multi-row INSERT support via
addRow()onJPAInsertClause/HibernateInsertClause:execute()now emits a single nativeINSERT INTO t (...) VALUES (..),(..),...when rows were accumulated viaaddRow(), returning the affected row count. Previously this only worked throughexecuteWithKeys(...), forcing callers to use a key-returning method even when keys were not needed.addRow()now captures effective column paths on its first call.execute()(multi-row path) andexecuteWithKeys(...)fall back to those captured paths when the current-stateinserts/columnsare empty. This makes the natural for-loop withset(...).addRow()at the end of every iteration work, without a "first row" flag and without keeping the last row in the buffer.Call site shapes that now work
Behavioral changes
JPAInsertClause.execute()/HibernateInsertClause.execute():rows(accumulated viaaddRow()) is non-empty and nosubQueryis set, emits a single native multi-rowINSERT INTO t (...) VALUES (..),(..),...and returns the affected row count.INSERT ... SELECT, template-value INSERTs already routed through native) keep their existing path.addRow():inserts/columnsare both empty (i.e. the trailing iteration was also closed withaddRow()).JpaInsertNativeHelper.requireSqlModule()(added): native insert paths depend on the optionalquerydsl-sqlmodule; guards them with an actionableIllegalStateExceptioninstead of an opaqueNoClassDefFoundErrorwhenquerydsl-sqlis absent from the classpath.addRow()Javadoc clarified: builds a single multi-rowVALUESstatement, not JDBC batching.Out of scope / clarifications
addRow()builds a single SQL statement with multipleVALUEStuples. It is not JDBC batching (PreparedStatement.addBatch()/executeBatch()).addRow()are unchanged.INSERT ... SELECT(select(SubQueryExpression)) is unchanged and still rejectsaddRow().Test plan
JPAExecuteWithKeyTestandHibernateExecuteWithKeyTestcovering both new shapes:execute_multi_row_set_style_with_trailing_addRow—set()+ trailingaddRow()+execute()(no keys)executeWithKeys_multi_row_set_style_with_trailing_addRow— same shape + key returnexecute_multi_row_without_keys_inserts_all_rows—columns()/values()+ addRow +execute()execute_multi_row_in_a_loop_with_trailing_addRow— loop-friendly form withcolumns()/values()./mvnw -pl querydsl-libraries/querydsl-jpa -Pno-databases test— 414 tests pass, 0 failures.