Skip to content

Commit 179e3b4

Browse files
Merge branch 'main' into hkhasnis-add-tests-error-translator
2 parents 3d6e999 + 46a5293 commit 179e3b4

29 files changed

+2564
-173
lines changed

.github/workflows/run-tests.yaml

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,15 @@ jobs:
99
GORM_ORACLEDB_USER: ${{ secrets.GORM_ORACLEDB_USER }}
1010
GORM_ORACLEDB_PASSWORD: ${{ secrets.GORM_ORACLEDB_PASSWORD }}
1111
GORM_ORACLEDB_CONNECTSTRING: ${{ secrets.GORM_ORACLEDB_CONNECTSTRING }}
12+
GORM_SYS_PASSOWRD: ${{ secrets.GORM_SYS_PASSOWRD }}
1213
GORM_ORACLEDB_LIBDIR: /home/runner/work/_temp/instantclient_23_9
1314
services:
1415
oracle:
1516
image: gvenzl/oracle-free:latest
1617
env:
1718
APP_USER: ${{ env.GORM_ORACLEDB_USER }}
1819
APP_USER_PASSWORD: ${{ env.GORM_ORACLEDB_PASSWORD }}
19-
ORACLE_RANDOM_PASSWORD: yes
20+
ORACLE_PASSWORD: ${{ env.GORM_SYS_PASSOWRD }}
2021
ports:
2122
- 1521:1521
2223
steps:
@@ -29,15 +30,38 @@ jobs:
2930
- name: Install Oracle Instant Client
3031
run: |
3132
cd $RUNNER_TEMP
32-
# Download the desired Oracle Instant Client zip files
33+
# Download the desired Oracle Instant Client zip files and SQL*Plus packages
3334
curl -sSfLO "https://download.oracle.com/otn_software/linux/instantclient/2390000/instantclient-basic-linux.x64-23.9.0.25.07.zip"
35+
curl -sSfLO "https://download.oracle.com/otn_software/linux/instantclient/2390000/instantclient-sqlplus-linux.x64-23.9.0.25.07.zip"
3436
# Unzip the packages into a single directory
3537
unzip -q -o "instantclient-basic-linux.x64-23.9.0.25.07.zip"
38+
unzip -q -o "instantclient-sqlplus-linux.x64-23.9.0.25.07.zip"
3639
# Install the operating system libaio package
3740
sudo ln -s /usr/lib/x86_64-linux-gnu/libaio.so.1t64 /usr/lib/libaio.so.1
3841
# Update the runtime link path
3942
echo "/home/runner/work/_temp/instantclient_23_9" | sudo tee /etc/ld.so.conf.d/oracle-instantclient.conf
4043
sudo ldconfig
44+
45+
- name: Wait for Oracle to be ready
46+
run: |
47+
# Wait until Oracle is accepting connections
48+
for i in {1..30}; do
49+
if docker exec $(docker ps -qf "ancestor=gvenzl/oracle-free:latest") \
50+
bash -c "echo exit | sqlplus -s / as sysdba" >/dev/null 2>&1; then
51+
echo "Oracle is ready!"
52+
break
53+
fi
54+
echo "Waiting for Oracle..."
55+
sleep 10
56+
done
57+
58+
- name: Alter user quota on tablespace SYSAUX
59+
run: |
60+
cat <<EOF > alter_user.sql
61+
ALTER USER $GORM_ORACLEDB_USER QUOTA UNLIMITED ON SYSAUX;
62+
EOF
63+
64+
$GORM_ORACLEDB_LIBDIR/sqlplus -s "sys/${GORM_SYS_PASSOWRD}@${GORM_ORACLEDB_CONNECTSTRING} AS SYSDBA" @alter_user.sql
4165
4266
- name: Checkout
4367
uses: actions/checkout@v4

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.vscode

README.md

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,73 @@ func main() {
3636
}
3737
```
3838

39+
## Documentation
40+
41+
### OnUpdate Foreign Key Constraint
42+
43+
Since Oracle doesn’t support `ON UPDATE` in foreign keys, the driver simulates it using **triggers**.
44+
45+
When a field has a constraint tagged with `OnUpdate`, the driver:
46+
47+
1. Skips generating the unsupported `ON UPDATE` clause in the foreign key definition.
48+
2. Creates a trigger on the parent table that automatically cascades updates to the child table(s) whenever the referenced column is changed.
49+
50+
The `OnUpdate` tag accepts the following values (case-insensitive): `CASCADE`, `SET NULL`, and `SET DEFAULT`.
51+
52+
Take the following struct for an example:
53+
54+
```go
55+
type Profile struct {
56+
ID uint
57+
Name string
58+
Refer uint
59+
}
60+
61+
type Member struct {
62+
ID uint
63+
Name string
64+
ProfileID uint
65+
Profile Profile `gorm:"Constraint:OnUpdate:CASCADE"`
66+
}
67+
```
68+
69+
Trigger SQL created by the driver when migrating:
70+
71+
```sql
72+
CREATE OR REPLACE TRIGGER "fk_trigger_profiles_id_members_profile_id"
73+
AFTER UPDATE OF "id" ON "profiles"
74+
FOR EACH ROW
75+
BEGIN
76+
UPDATE "members"
77+
SET "profile_id" = :NEW."id"
78+
WHERE "profile_id" = :OLD."id";
79+
END;
80+
```
81+
82+
### JSON Columns
83+
84+
Use either JSON type—both fully support `INSERT`, `UPDATE`, and `DELETE``RETURNING`:
85+
86+
- `gorm.io/datatypes.JSON` — convenient for logging/printing; returned as text then rewrapped.
87+
- `encoding/json.RawMessage` — raw `[]byte` fast-path; ideal for large payloads or minimal decoding.
88+
89+
#### Notes:
90+
- On multi-row `RETURNING`, we use PL/SQL bulk blocks and map results back into your structs.
91+
- `datatypes.JSON` comes back as text; `json.RawMessage` comes back as bytes.
92+
93+
Take the following struct as an example:
94+
95+
```go
96+
type Record struct {
97+
ID uint `gorm:"primaryKey;autoIncrement;column:record_id"`
98+
Name string `gorm:"column:name"`
99+
// Text-oriented JSON
100+
Properties datatypes.JSON `gorm:"column:properties"`
101+
// Raw bytes JSON
102+
Payload json.RawMessage `gorm:"column:payload"`
103+
}
104+
```
105+
39106
## Contributing
40107

41108
This project welcomes contributions from the community. Before submitting a pull request, please [review our contribution guide](./CONTRIBUTING.md)

go.mod

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,24 @@ module github.com/oracle-samples/gorm-oracle
22

33
go 1.24.4
44

5-
require gorm.io/gorm v1.30.0
6-
7-
require github.com/godror/godror v0.49.0
5+
require (
6+
github.com/godror/godror v0.49.3
7+
gorm.io/datatypes v1.2.6
8+
gorm.io/gorm v1.31.0
9+
)
810

911
require (
12+
filippo.io/edwards25519 v1.1.0 // indirect
1013
github.com/VictoriaMetrics/easyproto v0.1.4 // indirect
1114
github.com/go-logfmt/logfmt v0.6.0 // indirect
15+
github.com/go-sql-driver/mysql v1.8.1 // indirect
1216
github.com/godror/knownpb v0.3.0 // indirect
17+
github.com/google/uuid v1.6.0 // indirect
1318
github.com/jinzhu/inflection v1.0.0 // indirect
1419
github.com/jinzhu/now v1.1.5 // indirect
15-
golang.org/x/exp v0.0.0-20250531010427-b6e5de432a8b // indirect
16-
golang.org/x/term v0.27.0 // indirect
17-
golang.org/x/text v0.25.0 // indirect
18-
google.golang.org/protobuf v1.36.6 // indirect
20+
golang.org/x/exp v0.0.0-20250911091902-df9299821621 // indirect
21+
golang.org/x/term v0.35.0 // indirect
22+
golang.org/x/text v0.29.0 // indirect
23+
google.golang.org/protobuf v1.36.9 // indirect
24+
gorm.io/driver/mysql v1.5.6 // indirect
1925
)

go.sum

Lines changed: 54 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
2+
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
13
github.com/UNO-SOFT/zlog v0.8.1 h1:TEFkGJHtUfTRgMkLZiAjLSHALjwSBdw6/zByMC5GJt4=
24
github.com/UNO-SOFT/zlog v0.8.1/go.mod h1:yqFOjn3OhvJ4j7ArJqQNA+9V+u6t9zSAyIZdWdMweWc=
35
github.com/VictoriaMetrics/easyproto v0.1.4 h1:r8cNvo8o6sR4QShBXQd1bKw/VVLSQma/V2KhTBPf+Sc=
@@ -6,29 +8,63 @@ github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi
68
github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
79
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
810
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
9-
github.com/godror/godror v0.49.0 h1:oXAzPOm7bAGdFGkTaePCRXv3dfyr6Agni++4XhaRcC8=
10-
github.com/godror/godror v0.49.0/go.mod h1:D4gKled+sJVcagT1HWibkBsO9PcLn2Nu96FCr1RtnzI=
11+
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
12+
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
13+
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
14+
github.com/godror/godror v0.49.3 h1:84CPEu1p3qPvpN7PTHv8NDept+t+d+AoO/7WjYVsFNc=
15+
github.com/godror/godror v0.49.3/go.mod h1:kTMcxZzRw73RT5kn9v3JkBK4kHI6dqowHotqV72ebU8=
1116
github.com/godror/knownpb v0.3.0 h1:+caUdy8hTtl7X05aPl3tdL540TvCcaQA6woZQroLZMw=
1217
github.com/godror/knownpb v0.3.0/go.mod h1:PpTyfJwiOEAzQl7NtVCM8kdPCnp3uhxsZYIzZ5PV4zU=
13-
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
14-
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
18+
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA=
19+
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
20+
github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A=
21+
github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI=
22+
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
23+
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
24+
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
25+
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
26+
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
27+
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
28+
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 h1:L0QtFUgDarD7Fpv9jeVMgy/+Ec0mtnmYuImjTz6dtDA=
29+
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
30+
github.com/jackc/pgx/v5 v5.5.5 h1:amBjrZVmksIdNjxGW/IiIMzxMKZFelXbUoPNb+8sjQw=
31+
github.com/jackc/pgx/v5 v5.5.5/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A=
32+
github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
33+
github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
1534
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
1635
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
1736
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
1837
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
38+
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
39+
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
40+
github.com/microsoft/go-mssqldb v1.7.2 h1:CHkFJiObW7ItKTJfHo1QX7QBBD1iV+mn1eOyRP3b/PA=
41+
github.com/microsoft/go-mssqldb v1.7.2/go.mod h1:kOvZKUdrhhFQmxLZqbwUV0rHkNkZpthMITIb2Ko1IoA=
1942
github.com/oklog/ulid/v2 v2.0.2 h1:r4fFzBm+bv0wNKNh5eXTwU7i85y5x+uwkxCUTNVQqLc=
2043
github.com/oklog/ulid/v2 v2.0.2/go.mod h1:mtBL0Qe/0HAx6/a4Z30qxVIAL1eQDweXq5lxOEiwQ68=
21-
golang.org/x/exp v0.0.0-20250531010427-b6e5de432a8b h1:QoALfVG9rhQ/M7vYDScfPdWjGL9dlsVVM5VGh7aKoAA=
22-
golang.org/x/exp v0.0.0-20250531010427-b6e5de432a8b/go.mod h1:U6Lno4MTRCDY+Ba7aCcauB9T60gsv5s4ralQzP72ZoQ=
23-
golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
24-
golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
25-
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
26-
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
27-
golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
28-
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
29-
golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
30-
golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
31-
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
32-
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
33-
gorm.io/gorm v1.30.0 h1:qbT5aPv1UH8gI99OsRlvDToLxW5zR7FzS9acZDOZcgs=
34-
gorm.io/gorm v1.30.0/go.mod h1:8Z33v652h4//uMA76KjeDH8mJXPm1QNCYrMeatR0DOE=
44+
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
45+
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
46+
golang.org/x/exp v0.0.0-20250911091902-df9299821621 h1:2id6c1/gto0kaHYyrixvknJ8tUK/Qs5IsmBtrc+FtgU=
47+
golang.org/x/exp v0.0.0-20250911091902-df9299821621/go.mod h1:TwQYMMnGpvZyc+JpB/UAuTNIsVJifOlSkrZkhcvpVUk=
48+
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
49+
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
50+
golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
51+
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
52+
golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ=
53+
golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA=
54+
golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk=
55+
golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
56+
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
57+
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
58+
gorm.io/datatypes v1.2.6 h1:KafLdXvFUhzNeL2ncm03Gl3eTLONQfNKZ+wJ+9Y4Nck=
59+
gorm.io/datatypes v1.2.6/go.mod h1:M2iO+6S3hhi4nAyYe444Pcb0dcIiOMJ7QHaUXxyiNZY=
60+
gorm.io/driver/mysql v1.5.6 h1:Ld4mkIickM+EliaQZQx3uOJDJHtrd70MxAUqWqlx3Y8=
61+
gorm.io/driver/mysql v1.5.6/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM=
62+
gorm.io/driver/postgres v1.5.0 h1:u2FXTy14l45qc3UeCJ7QaAXZmZfDDv0YrthvmRq1l0U=
63+
gorm.io/driver/postgres v1.5.0/go.mod h1:FUZXzO+5Uqg5zzwzv4KK49R8lvGIyscBOqYrtI1Ce9A=
64+
gorm.io/driver/sqlite v1.6.0 h1:WHRRrIiulaPiPFmDcod6prc4l2VGVWHz80KspNsxSfQ=
65+
gorm.io/driver/sqlite v1.6.0/go.mod h1:AO9V1qIQddBESngQUKWL9yoH93HIeA1X6V633rBwyT8=
66+
gorm.io/driver/sqlserver v1.6.0 h1:VZOBQVsVhkHU/NzNhRJKoANt5pZGQAS1Bwc6m6dgfnc=
67+
gorm.io/driver/sqlserver v1.6.0/go.mod h1:WQzt4IJo/WHKnckU9jXBLMJIVNMVeTu25dnOzehntWw=
68+
gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
69+
gorm.io/gorm v1.31.0 h1:0VlycGreVhK7RF/Bwt51Fk8v0xLiiiFdbGDPIZQ7mJY=
70+
gorm.io/gorm v1.31.0/go.mod h1:XyQVbO2k6YkOis7C2437jSit3SsDK72s7n7rsSHd+Gs=

oracle/common.go

Lines changed: 60 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,13 @@ package oracle
4040

4141
import (
4242
"database/sql"
43+
"encoding/json"
4344
"fmt"
4445
"reflect"
4546
"strings"
4647
"time"
4748

49+
"gorm.io/datatypes"
4850
"gorm.io/gorm"
4951
"gorm.io/gorm/schema"
5052
)
@@ -169,11 +171,18 @@ func convertValue(val interface{}) interface{} {
169171
val = v.Interface()
170172
}
171173

172-
if v.Kind() == reflect.Ptr && v.IsNil() {
173-
return nil
174-
}
175-
176174
switch v := val.(type) {
175+
case json.RawMessage:
176+
if v == nil {
177+
return nil
178+
}
179+
return []byte(v)
180+
case *json.RawMessage:
181+
if v == nil {
182+
return nil
183+
}
184+
b := []byte(*v)
185+
return b
177186
case bool:
178187
if v {
179188
return 1
@@ -198,7 +207,25 @@ func convertFromOracleToField(value interface{}, field *schema.Field) interface{
198207
if isPtr {
199208
targetType = targetType.Elem()
200209
}
201-
210+
if field.FieldType == reflect.TypeOf(json.RawMessage{}) {
211+
switch v := value.(type) {
212+
case []byte:
213+
return json.RawMessage(v) // from BLOB
214+
case *[]byte:
215+
if v == nil {
216+
return json.RawMessage(nil)
217+
}
218+
return json.RawMessage(*v)
219+
}
220+
}
221+
if isJSONField(field) {
222+
switch v := value.(type) {
223+
case string:
224+
return datatypes.JSON([]byte(v))
225+
case []byte:
226+
return datatypes.JSON(v)
227+
}
228+
}
202229
var converted interface{}
203230

204231
switch targetType {
@@ -276,6 +303,24 @@ func convertFromOracleToField(value interface{}, field *schema.Field) interface{
276303
return converted
277304
}
278305

306+
func isJSONField(f *schema.Field) bool {
307+
_rawMsgT := reflect.TypeOf(json.RawMessage{})
308+
_gormJSON := reflect.TypeOf(datatypes.JSON{})
309+
if f == nil {
310+
return false
311+
}
312+
ft := f.FieldType
313+
return ft == _rawMsgT || ft == _gormJSON
314+
}
315+
316+
func isRawMessageField(f *schema.Field) bool {
317+
t := f.FieldType
318+
for t.Kind() == reflect.Ptr {
319+
t = t.Elem()
320+
}
321+
return t == reflect.TypeOf(json.RawMessage(nil))
322+
}
323+
279324
// Helper function to handle primitive type conversions
280325
func convertPrimitiveType(value interface{}, targetType reflect.Type) interface{} {
281326
switch targetType.Kind() {
@@ -424,6 +469,12 @@ func writeQuotedIdentifier(builder *strings.Builder, identifier string) {
424469
builder.WriteByte('"')
425470
}
426471

472+
func QuoteIdentifier(identifier string) string {
473+
var builder strings.Builder
474+
writeQuotedIdentifier(&builder, identifier)
475+
return builder.String()
476+
}
477+
427478
// writeTableRecordCollectionDecl writes the PL/SQL declarations needed to
428479
// define a custom record type and a collection of that record type,
429480
// based on the schema of the given table.
@@ -448,19 +499,19 @@ func writeQuotedIdentifier(builder *strings.Builder, identifier string) {
448499
// - plsqlBuilder: The builder to write the PL/SQL code into.
449500
// - dbNames: The slice containing the column names.
450501
// - table: The table name
451-
func writeTableRecordCollectionDecl(plsqlBuilder *strings.Builder, dbNames []string, table string) {
502+
func writeTableRecordCollectionDecl(db *gorm.DB, plsqlBuilder *strings.Builder, dbNames []string, table string) {
452503
// Declare a record where each element has the same structure as a row from the given table
453504
plsqlBuilder.WriteString(" TYPE t_record IS RECORD (\n")
454505
for i, field := range dbNames {
455506
if i > 0 {
456507
plsqlBuilder.WriteString(",\n")
457508
}
458509
plsqlBuilder.WriteString(" ")
459-
writeQuotedIdentifier(plsqlBuilder, field)
510+
db.QuoteTo(plsqlBuilder, field)
460511
plsqlBuilder.WriteString(" ")
461-
writeQuotedIdentifier(plsqlBuilder, table)
512+
db.QuoteTo(plsqlBuilder, table)
462513
plsqlBuilder.WriteString(".")
463-
writeQuotedIdentifier(plsqlBuilder, field)
514+
db.QuoteTo(plsqlBuilder, field)
464515
plsqlBuilder.WriteString("%TYPE")
465516
}
466517
plsqlBuilder.WriteString("\n")

0 commit comments

Comments
 (0)