Skip to content

Commit 1933d4c

Browse files
committed
merge: submit/corruption-fix-and-v1-hash fixup (PR mendixlabs#258 review)
2 parents caaa003 + 9767368 commit 1933d4c

4 files changed

Lines changed: 68 additions & 4 deletions

File tree

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
-- ============================================================================
2+
-- Bug #258: DROP + CREATE OR MODIFY microflow UnitID preservation
3+
-- ============================================================================
4+
--
5+
-- Symptom (before fix):
6+
-- A DROP MICROFLOW X followed by CREATE OR MODIFY MICROFLOW X in the same
7+
-- session produced a *different* UnitID for the new row. Studio Pro treats
8+
-- Unit rows with a different UnitID as unrelated documents and refuses to
9+
-- open the project:
10+
-- ".mpr does not look like a Mendix Studio Pro project file"
11+
--
12+
-- After fix:
13+
-- The executor remembers the dropped UnitID (and ContainerID, AllowedRoles)
14+
-- and reuses them on the subsequent CREATE so Studio Pro sees an in-place
15+
-- update. Also exercises v1 ContentsHash persistence — MPR v1 projects need
16+
-- the hash populated on every write or Studio Pro rejects the file as
17+
-- corrupt.
18+
--
19+
-- Usage:
20+
-- mxcli exec mdl-examples/bug-tests/258-drop-create-microflow-unitid-preservation.mdl -p app.mpr
21+
-- Open the project in Studio Pro — it must load without corruption errors
22+
-- and the microflow MF_Replaced must be visible under BugTest258.
23+
-- ============================================================================
24+
25+
create module BugTest258;
26+
27+
create microflow BugTest258.MF_Original
28+
returns string
29+
(
30+
set $return = 'original'
31+
);
32+
33+
-- Drop + recreate in the same session. Before the fix, this produced a
34+
-- dangling Unit row with a fresh UUID and the project became unopenable in
35+
-- Studio Pro. After the fix, the new microflow reuses the original UnitID.
36+
drop microflow BugTest258.MF_Original;
37+
38+
create or modify microflow BugTest258.MF_Original
39+
returns string
40+
(
41+
set $return = 'replaced'
42+
);
43+
44+
-- DESCRIBE must round-trip cleanly (no placeholder UUIDs leaking).
45+
describe microflow BugTest258.MF_Original;

mdl/executor/cmd_microflows_create.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,9 @@ func execCreateMicroflow(ctx *ExecContext, s *ast.CreateMicroflowStmt) error {
9595
if s.Folder == "" && dropped.ContainerID != "" {
9696
containerID = dropped.ContainerID
9797
}
98-
existingAllowedRoles = cloneRoleIDs(dropped.AllowedRoles)
98+
// consumeDroppedMicroflow removed the cache entry, so we own this
99+
// slice — no need to clone it again.
100+
existingAllowedRoles = dropped.AllowedRoles
99101
preserveAllowedRoles = true
100102
}
101103

sdk/mpr/writer_core.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,9 @@ func (wt *WriteTransaction) WriteUnit(unitID string, contents []byte) error {
148148
_, err := wt.tx.Exec(`
149149
UPDATE Unit SET Contents = ?, ContentsHash = ? WHERE UnitID = ?
150150
`, contents, contentsHash, unitIDBlob)
151-
if err != nil {
151+
if err != nil && isContentsHashSchemaError(err) {
152+
// Older v1 schemas do not have ContentsHash; retry without it.
153+
// Any other error (disk full, invalid UnitID, rolled-back tx) propagates.
152154
_, err = wt.tx.Exec(`
153155
UPDATE Unit SET Contents = ? WHERE UnitID = ?
154156
`, contents, unitIDBlob)

sdk/mpr/writer_units.go

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,24 @@ import (
99
"fmt"
1010
"os"
1111
"path/filepath"
12+
"strings"
1213

1314
"github.com/mendixlabs/mxcli/sdk/domainmodel"
1415
)
1516

17+
// isContentsHashSchemaError returns true when the error looks like SQLite complaining
18+
// about the absence of the ContentsHash column (i.e. an old MPR v1 schema from pre-Mx
19+
// versions that predate ContentsHash). Anything else — a disk-full error, a missing
20+
// UnitID, a rolled-back transaction — must propagate so writes don't silently succeed
21+
// without updating Contents.
22+
func isContentsHashSchemaError(err error) bool {
23+
if err == nil {
24+
return false
25+
}
26+
msg := err.Error()
27+
return strings.Contains(msg, "ContentsHash")
28+
}
29+
1630
// updateTransactionID updates the _Transaction table with a new UUID.
1731
// Studio Pro uses this to detect external changes during F4 sync.
1832
// Only applies to MPR v2 projects (Mendix >= 10.18).
@@ -154,8 +168,9 @@ func (w *Writer) updateUnit(unitID string, contents []byte) error {
154168
_, err := w.reader.db.Exec(`
155169
UPDATE Unit SET Contents = ?, ContentsHash = ? WHERE UnitID = ?
156170
`, contents, contentsHash, unitIDBlob)
157-
if err != nil {
158-
// Older v1 schemas do not have ContentsHash.
171+
if err != nil && isContentsHashSchemaError(err) {
172+
// Older v1 schemas do not have ContentsHash; retry without it.
173+
// Any other error (disk full, invalid UnitID, rolled-back tx) propagates.
159174
_, err = w.reader.db.Exec(`
160175
UPDATE Unit SET Contents = ? WHERE UnitID = ?
161176
`, contents, unitIDBlob)

0 commit comments

Comments
 (0)