Fix Oracle MERGE ORA-02012 error - invalid syntax#85
Conversation
…heses Co-authored-by: PhenX <42170+PhenX@users.noreply.github.com>
Co-authored-by: PhenX <42170+PhenX@users.noreply.github.com>
|
@copilot With Oracle, the InsertEntities_MultipleTimes fails with this error : Oracle.ManagedDataAccess.Client.OracleException : ORA-00904: "EXCLUDED"."Id": invalid identifier |
…updates Co-authored-by: PhenX <42170+PhenX@users.noreply.github.com>
Fixed in 0548cf5. The
The fix adds validation for Oracle MERGE limitations:
Note: There are still some behavioral issues with MERGE (incorrect row counts) that I'm investigating. Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
Co-authored-by: PhenX <42170+PhenX@users.noreply.github.com>
Co-authored-by: PhenX <42170+PhenX@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This pull request fixes Oracle MERGE (UPSERT) syntax issues that were causing ORA-02012 and other Oracle-specific errors. The implementation now properly handles Oracle's specific MERGE syntax requirements and adds comprehensive validation and error handling.
- Corrected Oracle MERGE statement syntax by removing AS keywords and wrapping ON clause in parentheses
- Added validation to ensure match columns are present in source data and excluded from UPDATE SET clause
- Added proper test coverage with skip conditions for Oracle-specific limitations
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| MergeTestsOracle.cs | Adds Oracle-specific test class inheriting from base merge tests |
| MergeTestsBase.cs | Adds Skip conditions for Oracle in tests that use InsertReturn/InsertReturnAsync strategies or auto-generated IDs for matching |
| OracleDialectBuilder.cs | Fixes MERGE syntax (removes AS keywords, adds parentheses to ON clause), validates match columns are in source data, excludes match columns from UPDATE SET, and adds NotSupportedException for returning entities with MERGE |
| OracleBulkInsertProvider.cs | Fixes bulk copy destination to use the provided tableName parameter (temp table) instead of tableInfo.QuotedTableName |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
All Oracle MERGE tests pass (6 passed, 18 skipped for expected reasons).
Original prompt
The oracle provider gives this error :
ORA-02012: missing USING keyword when performing UPSERT on Oracle
When using conflict resolution like :
await dbContext.ExecuteBulkInsertAsync(entities, onConflict: new OnConflictOptions
{
Match = e => new { e.Name },
Update = (inserted, excluded) => new TestCostType
{
CostType = inserted.CostType,
Amount = inserted.Amount,
CreatedAt = inserted.CreatedAt
}
});
The oracle merge SQL command is invalid.
When you fix it, please update tests, and if the feature is really not available in Oracle, ignore the related tests, and throw a comprehensive exception in the provider.
The project https://github.com/artiomchi/FlexLabs.Upsert/ seems to be able to achieve this, like that (see https://github.com/artiomchi/FlexLabs.Upsert/blob/main/src/FlexLabs.EntityFrameworkCore.Upsert/Runners/OracleUpsertCommandRunner.cs ) :
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using FlexLabs.EntityFrameworkCore.Upsert.Internal.Expressions;
namespace FlexLabs.EntityFrameworkCore.Upsert.Runners
{
///
/// Upsert command runner for the Oracle.EntityFrameworkCore provider
///
public class OracleUpsertCommandRunner : RelationalUpsertCommandRunner
{
///
public override bool Supports(string providerName) => providerName == "Oracle.EntityFrameworkCore";
///
protected override string EscapeName([NotNull] string name) => $""{name}"";
///
protected override string? SourcePrefix => "s.";
///
protected override string? TargetPrefix => "t.";
///
protected override string Parameter(int index) => $":p{index}";
///
protected override int? MaxQueryParams => 1000;
💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.