diff --git a/libcobj/app/src/main/java/jp/osscons/opensourcecobol/libcobj/file/CobolFile.java b/libcobj/app/src/main/java/jp/osscons/opensourcecobol/libcobj/file/CobolFile.java index 56e9a6b2..348c8697 100755 --- a/libcobj/app/src/main/java/jp/osscons/opensourcecobol/libcobj/file/CobolFile.java +++ b/libcobj/app/src/main/java/jp/osscons/opensourcecobol/libcobj/file/CobolFile.java @@ -285,6 +285,12 @@ public class CobolFile { /** TODO: 準備中 */ protected static final int COB_STATUS_91_NOT_AVAILABLE = 91; + /** + * File status 92: Version incompatibility. + * Indicates that the file operation failed due to a version mismatch between the file and the program. + */ + protected static final int COB_STATUS_92_VERSION_INCOMPATIBLE = 92; + // ============================================== // The following constants must not be equal // to any of the above constants `COB_STATUS_*` @@ -1103,6 +1109,9 @@ public void open(int mode, int sharing, AbstractCobolField fnstatus) { case COB_STATUS_91_NOT_AVAILABLE: saveStatus(COB_STATUS_91_NOT_AVAILABLE, fnstatus); return; + case COB_STATUS_92_VERSION_INCOMPATIBLE: + saveStatus(COB_STATUS_92_VERSION_INCOMPATIBLE, fnstatus); + return; case COB_LINAGE_INVALID: saveStatus(COB_STATUS_57_I_O_LINAGE, fnstatus); return; @@ -2066,6 +2075,9 @@ public void cob_delete_file(AbstractCobolField fnstatus) { case COB_STATUS_91_NOT_AVAILABLE: saveStatus(COB_STATUS_91_NOT_AVAILABLE, fnstatus); return; + case COB_STATUS_92_VERSION_INCOMPATIBLE: + saveStatus(COB_STATUS_92_VERSION_INCOMPATIBLE, fnstatus); + return; case COB_LINAGE_INVALID: saveStatus(COB_STATUS_57_I_O_LINAGE, fnstatus); return; diff --git a/libcobj/app/src/main/java/jp/osscons/opensourcecobol/libcobj/file/CobolIndexedFile.java b/libcobj/app/src/main/java/jp/osscons/opensourcecobol/libcobj/file/CobolIndexedFile.java index 8f355cef..f82588c8 100644 --- a/libcobj/app/src/main/java/jp/osscons/opensourcecobol/libcobj/file/CobolIndexedFile.java +++ b/libcobj/app/src/main/java/jp/osscons/opensourcecobol/libcobj/file/CobolIndexedFile.java @@ -227,6 +227,13 @@ public int open_(String filename, int mode, int sharing) { return getConnectionStatus; } + if(fileExists) { + int code = this.checkVersionOld(); + if(code != COB_STATUS_00_SUCCESS) { + return code; + } + } + try { // Acquire a file lock boolean succeedToFileLock = this.acquireFileLock(filename, mode, fileExists); @@ -292,6 +299,45 @@ private int getConnection(String filename) { return COB_STATUS_00_SUCCESS; } + private int checkVersionOld() { + IndexedFile p = this.filei; + try (Statement st = p.connection.createStatement()) { + String fileLockTableExistsSql = + "select exists(select 1 from sqlite_master where type = 'table' and name = 'file_lock')"; + ResultSet fileLockTableExistsResultSet = st.executeQuery(fileLockTableExistsSql); + if (fileLockTableExistsResultSet.next()) { + boolean fileLockTableExists = fileLockTableExistsResultSet.getInt(1) == 1; + if(!fileLockTableExists) { + return COB_STATUS_92_VERSION_INCOMPATIBLE; + } + } else { + return COB_STATUS_92_VERSION_INCOMPATIBLE; // file_lock table does not exist + } + + boolean lockedByColumnExists = false; + boolean processIdColumnExists = false; + boolean lockedAtColumnExists = false; + try (ResultSet rs = st.executeQuery("PRAGMA table_info('table0')")) { + while (rs.next()) { + String columnName = rs.getString("name"); + if ("locked_by".equals(columnName)) { + lockedByColumnExists = true; + } else if ("process_id".equals(columnName)) { + processIdColumnExists = true; + } else if ("locked_at".equals(columnName)) { + lockedAtColumnExists = true; + } + if (lockedByColumnExists && processIdColumnExists && lockedAtColumnExists) { + return COB_STATUS_00_SUCCESS; // All required columns exist + } + } + } + } catch (SQLException e) { + return COB_STATUS_30_PERMANENT_ERROR; + } + return COB_STATUS_92_VERSION_INCOMPATIBLE; + } + private String getOpenModeString(int mode) { switch (mode) { case COB_OPEN_INPUT: diff --git a/tests/Makefile.am b/tests/Makefile.am index 5efa5da9..7be45806 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -217,6 +217,7 @@ indexed_lock_DEPENDENCIES = \ indexed-lock.src/release-lock.at \ indexed-lock.src/open-input.at \ indexed-lock.src/lock-mode-clause.at \ + indexed-lock.src/old-file.at \ indexed-lock.src/lock-mode-automatic.at misc_DEPENDENCIES = \ diff --git a/tests/Makefile.in b/tests/Makefile.in index fe002ccd..3e02765c 100644 --- a/tests/Makefile.in +++ b/tests/Makefile.in @@ -756,6 +756,7 @@ indexed_lock_DEPENDENCIES = \ indexed-lock.src/release-lock.at \ indexed-lock.src/open-input.at \ indexed-lock.src/lock-mode-clause.at \ + indexed-lock.src/old-file.at \ indexed-lock.src/lock-mode-automatic.at misc_DEPENDENCIES = \ diff --git a/tests/indexed-lock.at b/tests/indexed-lock.at index 509cdc66..79c9b197 100644 --- a/tests/indexed-lock.at +++ b/tests/indexed-lock.at @@ -10,3 +10,4 @@ m4_include([release-lock.at]) m4_include([open-input.at]) m4_include([lock-mode-clause.at]) m4_include([lock-mode-automatic.at]) +m4_include([old-file.at]) diff --git a/tests/indexed-lock.src/indexed-file/old_indexed_file.dat b/tests/indexed-lock.src/indexed-file/old_indexed_file.dat new file mode 100644 index 00000000..b9ce5729 Binary files /dev/null and b/tests/indexed-lock.src/indexed-file/old_indexed_file.dat differ diff --git a/tests/indexed-lock.src/old-file.at b/tests/indexed-lock.src/old-file.at new file mode 100644 index 00000000..a7c9ce44 --- /dev/null +++ b/tests/indexed-lock.src/old-file.at @@ -0,0 +1,53 @@ +AT_SETUP([old file]) +AT_DATA([open_file_status.at], [ + IDENTIFICATION DIVISION. + PROGRAM-ID. open_file_status. + + ENVIRONMENT DIVISION. + INPUT-OUTPUT SECTION. + FILE-CONTROL. + SELECT F ASSIGN TO "indexed_file.dat" + ORGANIZATION IS INDEXED + ACCESS MODE IS DYNAMIC + RECORD KEY IS REC-KEY + ALTERNATE RECORD KEY IS REC-KEY2 WITH DUPLICATES + FILE STATUS IS FILE-STATUS. + + DATA DIVISION. + FILE SECTION. + FD f. + 01 REC. + 05 REC-KEY PIC X(5). + 05 REC-KEY2 PIC X(5). + 05 REC-DATA PIC X(5). + + WORKING-STORAGE SECTION. + 01 FILE-STATUS PIC XX. + PROCEDURE DIVISION. + MAIN-PROCEDURE. + OPEN INPUT f. + DISPLAY FILE-STATUS. + CLOSE f. + + OPEN I-O f. + DISPLAY FILE-STATUS. + CLOSE f. + + OPEN EXTEND f. + DISPLAY FILE-STATUS. + CLOSE f. + + OPEN OUTPUT f. + DISPLAY FILE-STATUS. + CLOSE f. +]) + +AT_CHECK([${COBJ} open_file_status.at]) +AT_CHECK([cp ../../indexed-lock.src/indexed-file/old_indexed_file.dat indexed_file.dat]) +AT_CHECK([java open_file_status], [0], +[92 +92 +92 +92 +]) +AT_CLEANUP \ No newline at end of file