Skip to content

Support "RETURNING INTO" clause for INSERT/UPDATE/DELETE in Oracle database#3669

Open
radovanradic wants to merge 32 commits into5.0.xfrom
radovanradic/oracle-returning
Open

Support "RETURNING INTO" clause for INSERT/UPDATE/DELETE in Oracle database#3669
radovanradic wants to merge 32 commits into5.0.xfrom
radovanradic/oracle-returning

Conversation

@radovanradic
Copy link
Contributor

Implementation for issue #2669

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pls remove lines

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed

@radovanradic radovanradic requested a review from Copilot March 18, 2026 15:12
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds support for Oracle RETURNING ... INTO semantics across INSERT/UPDATE/DELETE by propagating OUT parameter metadata from query building/processing into runtime JDBC execution.

Changes:

  • Introduces builder-time and runtime QueryOutParameterBinding metadata and wires it through annotation processing (DataMethodQueryOutParameter) into StoredQuery.
  • Updates SQL builders and raw @Query parsing to generate Oracle PL/SQL blocks (BEGIN ... RETURNING ... INTO ...; END;) and capture OUT parameter ordering/types.
  • Extends JDBC operations to execute Oracle returning statements via CallableStatement and map OUT parameters back to entities / scalar results, with new tests.

Reviewed changes

Copilot reviewed 26 out of 26 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
data-runtime/.../QueryResultStoredQuery.java Adds runtime OUT parameter bindings mapped from builder metadata.
data-runtime/.../DelegateStoredQuery.java Delegates new getOutParameterBindings() API.
data-runtime/.../DefaultStoredQuery.java Reads OUT parameter metadata from generated annotations.
data-runtime/.../DefaultSqlStoredQuery.java Pass-through for OUT parameter bindings.
data-processor/.../RawQueryMethodMatcher.java Parses Oracle RETURNING in raw queries and synthesizes OUT bindings/PLSQL wrapper.
data-processor/.../RepositoryTypeElementVisitor.java Emits DataMethodQueryOutParameter annotations based on QueryResult OUT bindings.
data-model/.../StoredQuery.java Adds new getOutParameterBindings() default API.
data-model/.../QueryResult.java Supports OUT bindings on QueryResult with new factory overload.
data-model/.../sql/SqlQueryBuilder.java Emits Oracle RETURNING ... INTO for INSERT and collects OUT binding metadata.
data-model/.../sql/AbstractSqlLikeQueryBuilder.java Adds RETURNING visitor plumbing and Oracle RETURNING handling for UPDATE/DELETE.
data-jdbc/.../DefaultJdbcRepositoryOperations.java Executes Oracle returning via CallableStatement and maps OUT params to entities/scalars.
data-jdbc/.../ColumnNameByIndexCallableResultReader.java Adds name-based OUT param reader backed by index mapping.
data-processor tests + data-jdbc tests Adds compilation/runtime regression tests for Oracle RETURNING behavior.
config/checkstyle/custom-suppressions.xml Suppresses file length for SqlQueryBuilder.

Comment on lines +315 to +322
String cleanLower = SQL_COMMENT_PATTERN.matcher(finalQueryString).replaceAll("").trim().toLowerCase(Locale.ENGLISH);
boolean hasReturning = RETURNING_PATTERN.matcher(cleanLower).find();
if (hasReturning) {
Dialect dialect = matchContext.getRepositoryClass().enumValue(Repository.class, "dialect", Dialect.class)
.orElse(Dialect.ANSI);
if (dialect == Dialect.ORACLE) {
SourcePersistentEntity entity = persistentEntity != null ? persistentEntity : matchContext.getRootEntity();
int returningIdx = cleanLower.lastIndexOf("returning");
Comment on lines +488 to +489
}
return QueryResult.of("", queryParts, parameterBindings, outBindings, Map.of());
.orElse(identity.getAnnotationMetadata().stringValue(JSON_PROPERTY_ANNOTATION)
.orElse(identity.getName()));
resultColumns.add(identityName);
resultColumnTypes.add(identity.getDataType());
Comment on lines +699 to +704
if (StringUtils.isNotEmpty(b.getName())) {
outBuilder.member(DataMethodQueryOutParameter.META_MEMBER_NAME, b.getName());
}
if (b.getDataType() != null) {
outBuilder.member(DataMethodQueryOutParameter.META_MEMBER_DATA_TYPE, b.getDataType());
}
boolean isEntityResult = preparedQuery.getResultDataType() == DataType.ENTITY;
if (isEntityResult) {
SqlResultEntityTypeMapper mapper = getSqlResultEntityTypeMapper(preparedQuery.getPersistentEntity(), columnNames, inCount);
return List.of((R) mapper.readEntity(cs));

<suppressions>
<suppress checks="FileLength" files=".*AbstractSqlLikeQueryBuilder.*" />
<suppress checks="FileLength" files="SqlQueryBuilder.java" />
Comment on lines +207 to +217
public String name() {
return delegate.getName();
}

@Override
public DataType dataType() {
return delegate.getDataType();
}

}

@radovanradic
Copy link
Contributor Author

@copilot open a new pull request to apply changes based on the comments in this thread

Copy link
Contributor

Copilot AI commented Mar 18, 2026

@radovanradic I've opened a new pull request, #3762, to work on those changes. Once the pull request is ready, I'll request review from you.

* Initial plan

* Apply PR review feedback for Oracle RETURNING INTO support

Co-authored-by: radovanradic <10271067+radovanradic@users.noreply.github.com>

* Use DEFAULT_POSITIONAL_PARAMETER_MARKER constant and clarify assembledSql comment

Co-authored-by: radovanradic <10271067+radovanradic@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: radovanradic <10271067+radovanradic@users.noreply.github.com>
@sonarqubecloud
Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
6 New Critical Issues (required ≤ 0)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants