Skip to content

Commit a1c08e0

Browse files
Fix a bug of duplicate record keys of indexed files. (#607)
1 parent c138674 commit a1c08e0

File tree

2 files changed

+120
-5
lines changed

2 files changed

+120
-5
lines changed

libcobj/app/src/main/java/jp/osscons/opensourcecobol/libcobj/file/CobolIndexedFile.java

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ public class CobolIndexedFile extends CobolFile {
4141
private boolean indexedFirstRead = true;
4242
private boolean callStart = false;
4343
private boolean commitOnModification = true;
44+
private int fetchKeyIndex = -1;
4445

4546
/** TODO: 準備中 */
4647
public static final int COB_EQ = 1;
@@ -295,6 +296,7 @@ public int open_(String filename, int mode, int sharing) {
295296
this.indexedFirstRead = true;
296297
this.callStart = false;
297298

299+
this.fetchKeyIndex = -1;
298300
return 0;
299301
}
300302

@@ -345,6 +347,7 @@ public int close_(int opt) {
345347
} catch (SQLException e) {
346348
return COB_STATUS_30_PERMANENT_ERROR;
347349
}
350+
this.fetchKeyIndex = -1;
348351
return COB_STATUS_00_SUCCESS;
349352
}
350353

@@ -366,6 +369,7 @@ public int indexed_start_internal(
366369
break;
367370
}
368371
}
372+
this.fetchKeyIndex = p.key_index;
369373

370374
p.key = DBT_SET(key);
371375

@@ -545,8 +549,12 @@ private int returnWith(IndexedFile p, boolean closeCursor, int index, int return
545549
return returnCode;
546550
}
547551

548-
/** Equivalent to indexed_write_internal in libcob/fileio.c */
549552
private int indexed_write_internal(boolean rewrite, int opt) {
553+
return this.indexed_write_internal(rewrite, null, opt);
554+
}
555+
556+
/** Equivalent to indexed_write_internal in libcob/fileio.c */
557+
private int indexed_write_internal(boolean rewrite, int[] dupNumbers, int opt) {
550558
IndexedFile p = this.filei;
551559

552560
boolean closeCursor;
@@ -592,7 +600,12 @@ private int indexed_write_internal(boolean rewrite, int opt) {
592600

593601
PreparedStatement insertStatement;
594602
if (isDuplicateColumn(i)) {
595-
int dupNo = getNextKeyDupNo(p.connection, i, p.key);
603+
int dupNo;
604+
if (dupNumbers == null || dupNumbers[i] < 0 || i != this.fetchKeyIndex) {
605+
dupNo = getNextKeyDupNo(p.connection, i, p.key);
606+
} else {
607+
dupNo = dupNumbers[i];
608+
}
596609
insertStatement =
597610
p.connection.prepareStatement(
598611
String.format(
@@ -693,19 +706,25 @@ public int rewrite_(int opt) {
693706
}
694707

695708
p.key = DBT_SET(this.keys[0].getField());
709+
int[] dupNumbers = new int[this.nkeys];
710+
java.util.Arrays.fill(dupNumbers, -1);
696711

697-
int ret = this.indexed_delete_internal(true);
712+
int ret = this.indexed_delete_internal(true, dupNumbers);
698713

699714
if (ret != COB_STATUS_00_SUCCESS) {
700715
p.write_cursor_open = false;
701716
return ret;
702717
}
703718

704-
return this.indexed_write_internal(true, opt);
719+
return this.indexed_write_internal(true, dupNumbers, opt);
705720
}
706721

707-
/** Equivalent to indexed_delete_internal in libcob/fileio.c */
708722
private int indexed_delete_internal(boolean rewrite) {
723+
return this.indexed_delete_internal(rewrite, null);
724+
}
725+
726+
/** Equivalent to indexed_delete_internal in libcob/fileio.c */
727+
private int indexed_delete_internal(boolean rewrite, int[] dupNumbers) {
709728
IndexedFile p = this.filei;
710729
boolean closeCursor;
711730

@@ -731,6 +750,25 @@ private int indexed_delete_internal(boolean rewrite) {
731750

732751
// delete data from sub tables
733752
for (int i = 1; i < this.nkeys; ++i) {
753+
// save the duplicate number of the record to be deleted
754+
if (isDuplicateColumn(i)) {
755+
try (PreparedStatement statement =
756+
p.connection.prepareStatement(
757+
String.format(
758+
"select dupNo from %s where value = ?", getTableName(i)))) {
759+
statement.setBytes(1, p.key);
760+
ResultSet rs = statement.executeQuery();
761+
if (rs.next()) {
762+
int dupNo = rs.getInt(1);
763+
if (dupNumbers != null) {
764+
dupNumbers[i] = dupNo;
765+
}
766+
}
767+
} catch (SQLException e) {
768+
return returnWith(p, closeCursor, 0, COB_STATUS_30_PERMANENT_ERROR);
769+
}
770+
}
771+
// delete the record
734772
try (PreparedStatement statement =
735773
p.connection.prepareStatement(
736774
String.format("delete from %s where value = ?", getTableName(i)))) {

tests/misc.src/record-key-duplicates-error.at

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,80 @@ AT_CHECK([${COBJ} prog.cbl], [1], [],
2626
[prog.cbl:8: Error: Record keys with duplicates are not yet supported
2727
])
2828
AT_CLEANUP
29+
30+
AT_SETUP([Error on rewriting record keys with duplicates])
31+
32+
AT_DATA([prog.cbl],
33+
[ IDENTIFICATION DIVISION.
34+
PROGRAM-ID. prog.
35+
36+
ENVIRONMENT DIVISION.
37+
INPUT-OUTPUT SECTION.
38+
FILE-CONTROL.
39+
SELECT DUP-FILE ASSIGN TO "dupfile.dat"
40+
ORGANIZATION IS INDEXED
41+
ACCESS MODE IS DYNAMIC
42+
RECORD KEY IS DUP-KEY
43+
ALTERNATE RECORD KEY IS DUP-KEY2 WITH DUPLICATES
44+
FILE STATUS IS FILE-STATUS.
45+
46+
DATA DIVISION.
47+
FILE SECTION.
48+
FD DUP-FILE.
49+
01 DUP-RECORD.
50+
05 DUP-KEY PIC X(5).
51+
05 DUP-KEY2 PIC X(5).
52+
05 DUP-DATA PIC X(10).
53+
54+
WORKING-STORAGE SECTION.
55+
01 FILE-STATUS PIC XX.
56+
01 WS-END-OF-FILE PIC X VALUE 'N'.
57+
58+
PROCEDURE DIVISION.
59+
MAIN-PROCEDURE.
60+
OPEN OUTPUT DUP-FILE.
61+
MOVE "11111AAAAAaaaaaaaaaa" TO DUP-RECORD.
62+
WRITE DUP-RECORD.
63+
MOVE "22222BBBBBbbbbbbbbbb" TO DUP-RECORD.
64+
WRITE DUP-RECORD.
65+
MOVE "33333BBBBBcccccccccc" TO DUP-RECORD.
66+
WRITE DUP-RECORD.
67+
MOVE "44444AAAAAdddddddddd" TO DUP-RECORD.
68+
WRITE DUP-RECORD.
69+
MOVE "55555CCCCCeeeeeeeeee" TO DUP-RECORD.
70+
WRITE DUP-RECORD.
71+
CLOSE DUP-FILE.
72+
73+
OPEN I-O DUP-FILE
74+
IF FILE-STATUS NOT = "00"
75+
DISPLAY "Error opening file: " FILE-STATUS
76+
STOP RUN
77+
END-IF.
78+
79+
MOVE "BBBBB" TO DUP-KEY2.
80+
START DUP-FILE KEY IS >= DUP-KEY2.
81+
IF FILE-STATUS = "00"
82+
MOVE 'N' TO WS-END-OF-FILE
83+
PERFORM UNTIL WS-END-OF-FILE = 'Y'
84+
READ DUP-FILE NEXT
85+
AT END
86+
MOVE 'Y' TO WS-END-OF-FILE
87+
NOT AT END
88+
REWRITE DUP-RECORD
89+
DISPLAY DUP-RECORD
90+
END-PERFORM
91+
ELSE
92+
DISPLAY "Key not found"
93+
END-IF.
94+
CLOSE DUP-FILE.
95+
STOP RUN.
96+
])
97+
98+
AT_CHECK([${COBJ} prog.cbl])
99+
AT_CHECK([java prog], [0],
100+
[22222BBBBBbbbbbbbbbb
101+
33333BBBBBcccccccccc
102+
55555CCCCCeeeeeeeeee
103+
])
104+
105+
AT_CLEANUP

0 commit comments

Comments
 (0)