Skip to content

Commit 8198e9e

Browse files
authored
orm: fix double fkey insert and update (fix #25593) (#25606)
1 parent 1f416d9 commit 8198e9e

File tree

5 files changed

+136
-2
lines changed

5 files changed

+136
-2
lines changed

vlib/orm/orm_fk_test.v

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,3 +103,66 @@ fn test_fkey_insert_as_assignment_expr() {
103103
}!
104104
assert res.len == 2
105105
}
106+
107+
struct Foo2 {
108+
id int @[primary; sql: serial]
109+
name string
110+
children []Child2 @[fkey: 'parent_id']
111+
}
112+
113+
struct Child2 {
114+
id int @[primary; sql: serial]
115+
parent_id int
116+
name string
117+
bar ?Bar2 @[fkey: 'child_id']
118+
}
119+
120+
struct Bar2 {
121+
id int @[primary; sql: serial]
122+
child_id int
123+
name string
124+
}
125+
126+
fn test_double_fkey_insert() {
127+
db := sqlite.connect(':memory:')!
128+
129+
sql db {
130+
create table Foo2
131+
create table Child2
132+
create table Bar2
133+
}!
134+
135+
child_one := Child2{
136+
name: 'abc'
137+
}
138+
139+
child_two := Child2{
140+
name: 'def'
141+
}
142+
143+
bar_one := Bar2{
144+
id: 0
145+
name: 'name'
146+
}
147+
148+
foo := Foo2{
149+
name: 'abc'
150+
children: [
151+
child_one,
152+
child_two,
153+
]
154+
}
155+
_ := sql db {
156+
insert foo into Foo2
157+
}!
158+
159+
result := sql db {
160+
select from Foo2 where id == 1
161+
}!
162+
assert result[0].children.len == 2
163+
164+
res := sql db {
165+
select from Child2
166+
}!
167+
assert res.len == 2
168+
}

vlib/v/checker/orm.v

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,13 @@ fn (mut c Checker) sql_stmt_line(mut node ast.SqlStmtLine) ast.Type {
327327
}
328328

329329
field := updated_fields.first()
330+
for attr in field.attrs {
331+
if attr.name == 'fkey' {
332+
c.orm_error("`${column}` is a foreign column of `${table_sym.name}`, it can't update here",
333+
node.pos)
334+
break
335+
}
336+
}
330337
node.updated_columns[i] = c.fetch_field_name(field)
331338
}
332339

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
vlib/v/checker/tests/orm_fkey_update.vv:56:10: error: ORM: `bar` is a foreign column of `Child`, it can't update here
2+
54 |
3+
55 | sql db {
4+
56 | update Child set bar = bar_one where id == 0
5+
| ~~~~~
6+
57 | }!
7+
58 | }
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import db.sqlite
2+
3+
struct Foo {
4+
id int @[primary; sql: serial]
5+
name string
6+
children []Child @[fkey: 'parent_id']
7+
}
8+
9+
struct Child {
10+
id int @[primary; sql: serial]
11+
parent_id int
12+
name string
13+
bar ?Bar @[fkey: 'child_id']
14+
}
15+
16+
struct Bar {
17+
id int @[primary; sql: serial]
18+
child_id int
19+
name string
20+
}
21+
22+
fn main() {
23+
db := sqlite.connect(':memory:')!
24+
25+
sql db {
26+
create table Foo
27+
create table Child
28+
create table Bar
29+
}!
30+
31+
child_one := Child{
32+
name: 'abc'
33+
}
34+
35+
child_two := Child{
36+
name: 'def'
37+
}
38+
39+
bar_one := Bar{
40+
id: 0
41+
name: 'name'
42+
}
43+
44+
foo := Foo{
45+
name: 'abc'
46+
children: [
47+
child_one,
48+
child_two,
49+
]
50+
}
51+
_ := sql db {
52+
insert foo into Foo
53+
}!
54+
55+
sql db {
56+
update Child set bar = bar_one where id == 0
57+
}!
58+
}

vlib/v/gen/c/orm.v

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -558,6 +558,7 @@ fn (mut g Gen) write_orm_insert_with_last_ids(node ast.SqlStmtLine, connection_v
558558
last_ids := g.new_tmp_var()
559559
res_ := g.new_tmp_var()
560560
tmp_var := g.new_tmp_var()
561+
g.writeln('Array_orm__Primitive ${last_ids} = builtin____new_array_with_default_noscan(0, 0, sizeof(orm__Primitive), 0);')
561562
if is_option {
562563
g.writeln('${ctyp} ${tmp_var} = (*(${ctyp}*)builtin__array_get(*(Array_${ctyp}*)${node.object_var}${member_access_type}${arr.object_var}.data, ${idx}));')
563564
} else {
@@ -583,8 +584,6 @@ fn (mut g Gen) write_orm_insert_with_last_ids(node ast.SqlStmtLine, connection_v
583584
unsafe { fff.free() }
584585
g.write_orm_insert_with_last_ids(arr, connection_var_name, g.get_table_name_by_struct_type(arr.table_expr.typ),
585586
last_ids, res_, id_name, fkeys[i], or_expr)
586-
// Validates sub insertion success otherwise, handled and propagated error.
587-
g.or_block(res_, or_expr, ast.int_type.set_flag(.result))
588587
g.indent--
589588
g.writeln('}')
590589
}

0 commit comments

Comments
 (0)