Skip to content

Commit 670eadb

Browse files
Merge pull request #102 from joboon/OnConflictLobFixes
fix: LOB failures during OnConflict merges
2 parents 153b92e + b0725eb commit 670eadb

File tree

3 files changed

+131
-8
lines changed

3 files changed

+131
-8
lines changed

oracle/common.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,16 @@
3939
package oracle
4040

4141
import (
42+
"bytes"
4243
"database/sql"
4344
"encoding/json"
4445
"fmt"
46+
"math"
4547
"reflect"
4648
"strings"
4749
"time"
4850

51+
"github.com/godror/godror"
4952
"github.com/google/uuid"
5053
"gorm.io/datatypes"
5154
"gorm.io/gorm"
@@ -206,6 +209,14 @@ func convertValue(val interface{}) interface{} {
206209
return 0
207210
}
208211
case string:
212+
if len(v) > math.MaxInt16 {
213+
return godror.Lob{IsClob: true, Reader: strings.NewReader(v)}
214+
}
215+
return v
216+
case []byte:
217+
if len(v) > math.MaxInt16 {
218+
return godror.Lob{IsClob: false, Reader: bytes.NewReader(v)}
219+
}
209220
return v
210221
default:
211222
return val

tests/blob_test.go

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,33 +41,44 @@ package tests
4141
import (
4242
"bytes"
4343
"crypto/rand"
44+
"strings"
4445
"testing"
4546
"time"
4647

4748
"gorm.io/gorm"
4849
)
4950

5051
type BlobTestModel struct {
51-
ID uint `gorm:"primaryKey;autoIncrement"`
52-
Name string `gorm:"size:100;not null"`
53-
Data []byte `gorm:"type:blob"`
52+
ID uint `gorm:"primaryKey;autoIncrement"`
53+
Name string `gorm:"size:100;not null"`
54+
Data []byte `gorm:"type:blob"`
5455
OptionalData *[]byte `gorm:"type:blob"`
55-
CreatedAt time.Time
56-
UpdatedAt time.Time
56+
CreatedAt time.Time
57+
UpdatedAt time.Time
5758
}
5859

5960
type BlobVariantModel struct {
60-
ID uint `gorm:"primaryKey"`
61+
ID uint `gorm:"primaryKey"`
6162
SmallBlob []byte `gorm:"type:blob"`
6263
LargeBlob []byte `gorm:"type:blob"`
6364
}
6465

66+
type BlobOneToManyModel struct {
67+
ID uint `gorm:"primaryKey"`
68+
Children []BlobChildModel `gorm:"foreignKey:ID"`
69+
}
70+
71+
type BlobChildModel struct {
72+
ID uint `gorm:"primaryKey"`
73+
Data []byte `gorm:"type:blob"`
74+
}
75+
6576
func setupBlobTestTables(t *testing.T) {
6677
t.Log("Setting up BLOB test tables")
6778

68-
DB.Migrator().DropTable(&BlobTestModel{}, &BlobVariantModel{})
79+
DB.Migrator().DropTable(&BlobTestModel{}, &BlobVariantModel{}, &BlobOneToManyModel{}, &BlobChildModel{})
6980

70-
err := DB.AutoMigrate(&BlobTestModel{}, &BlobVariantModel{})
81+
err := DB.AutoMigrate(&BlobTestModel{}, &BlobVariantModel{}, &BlobOneToManyModel{}, &BlobChildModel{})
7182
if err != nil {
7283
t.Fatalf("Failed to migrate BLOB test tables: %v", err)
7384
}
@@ -423,6 +434,23 @@ func TestBlobWithReturning(t *testing.T) {
423434
}
424435
}
425436

437+
func TestBlobOnConflict(t *testing.T) {
438+
setupBlobTestTables(t)
439+
440+
model := &BlobOneToManyModel{
441+
ID: 1,
442+
Children: []BlobChildModel{
443+
{
444+
Data: []byte(strings.Repeat("X", 32768)),
445+
},
446+
},
447+
}
448+
err := DB.Create(model).Error
449+
if err != nil {
450+
t.Fatalf("Failed to create BLOB record with ON CONFLICT: %v", err)
451+
}
452+
}
453+
426454
func TestBlobErrorHandling(t *testing.T) {
427455
setupBlobTestTables(t)
428456

tests/clob_test.go

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/*
2+
** Copyright (c) 2025 Oracle and/or its affiliates.
3+
**
4+
** The Universal Permissive License (UPL), Version 1.0
5+
**
6+
** Subject to the condition set forth below, permission is hereby granted to any
7+
** person obtaining a copy of this software, associated documentation and/or data
8+
** (collectively the "Software"), free of charge and under any and all copyright
9+
** rights in the Software, and any and all patent rights owned or freely
10+
** licensable by each licensor hereunder covering either (i) the unmodified
11+
** Software as contributed to or provided by such licensor, or (ii) the Larger
12+
** Works (as defined below), to deal in both
13+
**
14+
** (a) the Software, and
15+
** (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
16+
** one is included with the Software (each a "Larger Work" to which the Software
17+
** is contributed by such licensors),
18+
**
19+
** without restriction, including without limitation the rights to copy, create
20+
** derivative works of, display, perform, and distribute the Software and make,
21+
** use, sell, offer for sale, import, export, have made, and have sold the
22+
** Software and the Larger Work(s), and to sublicense the foregoing rights on
23+
** either these or other terms.
24+
**
25+
** This license is subject to the following condition:
26+
** The above copyright notice and either this complete permission notice or at
27+
** a minimum a reference to the UPL must be included in all copies or
28+
** substantial portions of the Software.
29+
**
30+
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
31+
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
32+
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
33+
** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
34+
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
35+
** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
36+
** SOFTWARE.
37+
*/
38+
39+
package tests
40+
41+
import (
42+
"strings"
43+
"testing"
44+
)
45+
46+
type ClobOneToManyModel struct {
47+
ID uint `gorm:"primaryKey"`
48+
Children []ClobChildModel `gorm:"foreignKey:ID"`
49+
}
50+
51+
type ClobChildModel struct {
52+
ID uint `gorm:"primaryKey"`
53+
Data string `gorm:"type:clob"`
54+
}
55+
56+
func setupClobTestTables(t *testing.T) {
57+
t.Log("Setting up CLOB test tables")
58+
59+
DB.Migrator().DropTable(&ClobOneToManyModel{}, &ClobChildModel{})
60+
61+
err := DB.AutoMigrate(&ClobOneToManyModel{}, &ClobChildModel{})
62+
if err != nil {
63+
t.Fatalf("Failed to migrate CLOB test tables: %v", err)
64+
}
65+
66+
t.Log("CLOB test tables created successfully")
67+
}
68+
69+
func TestClobOnConflict(t *testing.T) {
70+
setupClobTestTables(t)
71+
72+
model := &ClobOneToManyModel{
73+
ID: 1,
74+
Children: []ClobChildModel{
75+
{
76+
Data: strings.Repeat("X", 32768),
77+
},
78+
},
79+
}
80+
err := DB.Create(model).Error
81+
if err != nil {
82+
t.Fatalf("Failed to create BLOB record with ON CONFLICT: %v", err)
83+
}
84+
}

0 commit comments

Comments
 (0)