Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions oracle/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,22 @@ import (
"gorm.io/gorm/schema"
)

// Create overrides GORM's create callback for Oracle.
//
// Behavior:
// - If the schema has fields with default DB values and only one row is
// being inserted, it builds an INSERT ... RETURNING statement.
// - If no RETURNING is needed, it emits a standard INSERT.
// - If multiple rows require RETURNING, it builds a PL/SQL block using
// FORALL and BULK COLLECT; if an ON CONFLICT clause is present and
// resolvable, it emits a MERGE.
// - For that last case, it validates Dest (non-nil, non-empty slice with
// no nil elements), normalizes bind variables for Oracle, and populates
// destinations from OUT parameters.
//
// Register with:
//
// db.Callback().Create().Replace("gorm:create", oracle.Create)
func Create(db *gorm.DB) {
if db.Error != nil || db.Statement == nil {
return
Expand Down
26 changes: 25 additions & 1 deletion oracle/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,31 @@ import (
"gorm.io/gorm/schema"
)

// Delete callback function for Oracle
// Delete overrides GORM's delete callback for Oracle.
//
// Delete builds a safe, Oracle-compatible DELETE that supports soft deletes,
// hard deletes, and optional RETURNING of deleted rows.
//
// Behavior:
// - DELETE safety: checks for missing WHERE conditions and refuses to run
// unless AllowGlobalUpdate is set or the WHERE clause has meaningful
// conditions.
// - Soft delete: if the model has a soft-delete field and Unscoped is false,
// it lets GORM emit the UPDATE that marks rows as deleted. If a RETURNING
// clause is present with soft delete, it executes via QueryContext so the
// returned columns can be scanned.
// - Hard delete + RETURNING: it emits a PL/SQL block that performs DELETE …
// RETURNING BULK COLLECT INTO, wiring per-row sql.Out destinations so the
// deleted rows (or selected columns) can be populated back into the
// destination slice.
// - Hard delete (no RETURNING): it emits a standard DELETE and executes it
// via ExecContext.
// - Expressions: it expands WHERE expressions, including IN with slices, and
// normalizes bind variables for Oracle.
//
// Register with:
//
// db.Callback().Delete().Replace("gorm:delete", oracle.Delete)
func Delete(db *gorm.DB) {
if db.Error != nil || db.Statement == nil {
return
Expand Down
24 changes: 23 additions & 1 deletion oracle/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,29 @@ import (
"gorm.io/gorm/schema"
)

// Update callback function for Oracle
// Update overrides GORM's update callback for Oracle.
//
// It builds Oracle-compatible UPDATE statements and supports:
//
// - Standard updates without RETURNING using GORM’s default SQL build, with
// bind variable conversion for Oracle types.
// - Updates with RETURNING, emitting a PL/SQL block that performs
// UPDATE … RETURNING BULK COLLECT INTO for multi-row updates,
// wiring sql.Out binds for each returned column and row.
// - UPDATE safety: checks for missing WHERE conditions and refuses to run
// unless AllowGlobalUpdate is set or the WHERE clause has meaningful
// conditions (beyond soft-delete filters).
// - Primary key WHERE injection when the destination object or slice has
// identifiable PK values, to avoid unintended mass updates.
// - Soft-delete compatibility: conditions on deleted_at are ignored for the
// safety check, but preserved in the WHERE for the actual SQL.
//
// For updates with RETURNING, OUT bind results are mapped back into the
// destination struct or slice using getUpdateReturningValues.
//
// Register with:
//
// db.Callback().Update().Replace("gorm:update", oracle.Update)
func Update(db *gorm.DB) {
if db.Error != nil || db.Statement == nil {
return
Expand Down