This sections shows how to proceed to install or upgrade to 14.10 release.

1 Prerrequisites

The installation of Informix service requires Java 1.8.0.

And the libncurses and libaio library as well:

Copy
dnf install ncurses-compat-libs libaio

2 Check and fix 'in-place alters'

Informix uses in-place alters to speed up database schema changes whenever possible.

New rows adopt the new schema definition, old rows do not change, therefore conversion is faster.

Recommend resolving in-place alters before an upgrade.

Run 'oncheck -pt' command to identify which tables were altered in the current version. Qualifying tables must have tblspace flag 0x800000 set. For example:

Copy
# oncheck -pt tdb:tab1
TBLspace Report for tdb:dmitriyr.tab1
 Table fragment partition par1 in DBspace dbs1
    Physical Address               2:5
    Creation date                  06/25/2012 11:58:16
    TBLspace Flags                 800802     Row Locking
                                              TBLspace use 4 bit bit-maps
...

As an alternative to 'oncheck -pt' you may run the following query against the Informix sysmaster database to find all qualifying tables:

Copy
SELECT ta.dbsname, ta.tabname, pt.partnum, HEX(pt.flags) flag
  FROM sysmaster:systabnames ta, sysmaster:sysptnhdr pt
 WHERE ta.partnum = pt.partnum
   AND BIT_AND(HEX(pt.flags),'00800000'::BINARYVAR) = '00800000';
dbsname       tdb
tabname       tab1
partnum       2097154
flag          0x00800802

In above examples tblspace flag value is 0x800802. It is clear that value 0x800000 is set here.

Run oncheck against those tables identified in p.1 to find which tables have outstanding in-place alters. You must look at "Home Data Page Version Summary" section. For example:

Copy
# oncheck -pT [database]:[table]
...
    Home Data Page Version Summary
                 Version                                 Count
                       0 (oldest)                           25
                       1 (current)                          15
...

In the above example there are 25 pages to be altered to a new version. That means that a dummy update is required to be executed against that table. For example, to create a dummy update, specify:

Copy
UPDATE tab1 SET col1=col1 WHERE 1=1;

Update a numeric data type

You must ensure that the column selected is a numeric data type (for example, INTEGER of SMALLINT) and not a character data type.

Dummy UPDATE statements force any outstanding in-place alters to complete by updating the rows in the affected tables. To generate a dummy UPDATE statement, create an UPDATE statement in which a column in the table is set to its own value. This forces the row to be updated to the latest schema without actually changing column values. Because the database server always alters rows to the latest schema, a single pass through the table that updates all rows completes all outstanding in-place alters.

The steps to perform a dummy update is explained in detail within the migration guide.

2.1 Get all pending IPAs

The next function returns a list with tables of all databases in the instance that has rows with an old schema. Compile this funcion in any database and then execute it.

Copy
CREATE FUNCTION get_pending_ipa() RETURNING
        VARCHAR(128) as database, VARCHAR(128) as table, VARCHAR(128) as partition, VARCHAR(9) as obj_type,
        INTEGER as partnum, INTEGER as lockid, SMALLINT as version, INTEGER as npages
-- For version 7.x use this header instead:
--CREATE PROCEDURE get_pending_ipa() RETURNING VARCHAR(128), VARCHAR(128), VARCHAR(128), VARCHAR(9), INTEGER, INTEGER, SMALLINT, INTEGER;
-- Name: $RCSfile: get_pending_ipa.sql,v $
-- CVS file: $Source: /usr/local/cvs/stable/informix/queries/get_pending_ipa.sql,v $
-- CVS id: $Header: /usr/local/cvs/stable/informix/queries/get_pending_ipa.sql,v 1.5 2011/09/09 20:57:31 fnunes Exp $
-- Revision: $Revision: 1.5 $
-- Revised on: $Date: 2011/09/09 20:57:31 $
-- Revised by: $Author: fnunes $
-- Support: Fernando Nunes - domusonline@gmail.com
-- Licence: This script is licensed as GPL ( http://www.gnu.org/licenses/old-licenses/lgpl-2.0.html )
-- Variables holding the database,tabnames and partnum
DEFINE v_dbsname, v_old_dbsname LIKE sysmaster:systabnames.dbsname;
DEFINE v_tabname, v_partname, v_old_tabname LIKE sysmaster:systabnames.tabname;
DEFINE v_partnum, v_old_partnum LIKE sysmaster:syspaghdr.pg_partnum;
DEFINE v_lockid, v_old_lockid LIKE sysmaster:sysptnhdr.lockid;
DEFINE v_pg_next INTEGER;
DEFINE v_pg_partnum INTEGER;
DEFINE v_obj_type VARCHAR(9);
-- Variables holding the various table versions and respective number of pages pending to migrate
DEFINE v_version SMALLINT;
DEFINE v_pages INTEGER;
-- Hexadecimal representation of version and pending number of pages
DEFINE v_char_version CHAR(6);
DEFINE v_char_pages CHAR(10);
DEFINE v_aux_char CHAR(8);
-- Hexadecimal representation of the slot 6 data. Each 16 bytes will appear as a record that needs to be concatenated
DEFINE v_hexdata VARCHAR(128);
-- Variable to hold the sysmaster:syssltdat hexadecimal representation of each 16 bytes of the slot data
DEFINE v_slot_hexdata CHAR(40);
DEFINE v_aux VARCHAR(128);
DEFINE v_endian CHAR(6);
DEFINE v_offset SMALLINT;
DEFINE v_slotoff SMALLINT;
DEFINE v_dummy INTEGER;
-- In case we need to trace the function... Uncomment the following two lines
--SET DEBUG FILE TO "/tmp/get_pending_ipa.dbg";
--TRACE ON;
-- Now lets find out the Endianess ( http://en.wikipedia.org/wiki/Endianness ) of this platform
-- The data in sysmaster:syssltdat will be different because of possible byte swap
-- Read the first slot of the rootdbs TBLSpace tblspace (0x00100001)
-- The first 4 bytes hold the partition number (0x00100001)
SELECT
        s.hexdata[1,8]
INTO
        v_hexdata
FROM
        sysmaster:syssltdat s
WHERE
        s.partnum = '0x100001' AND
        s.pagenum = 1 AND
        s.slotnum = 1 AND
        s.slotoff = 0;
IF v_hexdata = '01001000'
THEN
        -- Byte swap order, so we're little Endian (Intel, Tru64....)
        LET v_endian = 'LITTLE';
ELSE
        IF v_hexdata = '00100001'
        THEN
                -- Just as we write it (no byte swap), so we're big Endian (Sparc, Power, Itanium...)
                LET v_endian = 'BIG';
        ELSE
                -- Just in case something weird (like a bug(!) or physical modification) happened
                RAISE EXCEPTION -746, 0, 'Invalid Endianess calculation... Check procedure code!!!';
        END IF
END IF
-- Flags to mark the beginning
LET v_hexdata = "-";
LET v_old_dbsname = "-";
LET v_old_tabname = "-";
-- The information we want for each version description will occupy this number of characters
-- in the sysmaster:syssltdat.hexdata notation (after removing spaces). The size depends on the engine version.
LET v_offset=DBINFO('version','major');
IF v_offset >= 10
THEN
        LET v_offset = 48;
ELSE
        LET v_offset = 40;
END IF
LET v_old_lockid = -1;
FOREACH
        -- This query will browse through all the instance partitions, excluding sysmaster database, and will look for
        -- any extended partition header (where partition header "next" field is not 0)
        -- the ABS(...) is just a trick to make partnums that are equal to lock id appear at the end
        SELECT
                t.dbsname, t.tabname, t1.tabname, t.partnum, p.pg_partnum, p.pg_next, h.lockid, ABS(h.lockid - h.partnum)
        INTO
                v_dbsname, v_partname ,v_tabname, v_partnum, v_pg_partnum, v_pg_next, v_lockid, v_dummy
        FROM
                sysmaster:systabnames t,
                sysmaster:syspaghdr p,
                sysmaster:sysptnhdr h,
                sysmaster:systabnames t1
        WHERE
                p.pg_partnum = sysmaster:partaddr(sysmaster:partdbsnum(t.partnum),1) AND
                p.pg_pagenum = sysmaster:partpagenum(t.partnum) AND
                t.dbsname NOT IN ('sysmaster') AND
                h.partnum = t.partnum AND
                t1.partnum = h.lockid AND
                p.pg_next != 0
        ORDER BY
                t.dbsname, t.tabname, 8 DESC, t.partnum
        IF v_lockid = v_partnum
        THEN
                IF v_lockid = v_old_lockid
                THEN
                        LET v_obj_type = "Part Main";
                ELSE
                        LET v_obj_type = "Table";
                END IF
        ELSE
                LET v_obj_type = "Part";
        END IF
        LET v_old_lockid = v_lockid;
        WHILE v_pg_next != 0
                -- Find if we're dealing with a fragmented table or not...
                -- While this extended partition page points to another one...
                -- Get all the slot 6 data (where the version metadata is stored - version, number of pages, descriptor page etc.
                FOREACH
                SELECT
                        REPLACE(s.hexdata, ' '), s.slotoff, p.pg_next
                INTO
                        v_slot_hexdata, v_slotoff, v_pg_next
                FROM
                        sysmaster:syspaghdr p,
                        sysmaster:syssltdat s
                WHERE
                        s.partnum = p.pg_partnum AND
                        s.pagenum = p.pg_pagenum AND
                        s.slotnum = 6 AND
                        p.pg_partnum = v_pg_partnum AND
                        p.pg_pagenum = v_pg_next
                IF ( v_dbsname != v_old_dbsname OR v_tabname != v_old_tabname OR v_partnum != v_old_partnum)
                THEN
                        LET v_old_dbsname = v_dbsname;
                        LET v_old_tabname = v_tabname;
                        LET v_old_partnum = v_partnum;
                        -- First iteraction for each table
                        LET v_hexdata = v_slot_hexdata;
                ELSE
                        -- Next iteractions for each table
                        LET v_hexdata = TRIM(v_hexdata) || v_slot_hexdata;
                        IF LENGTH(v_hexdata) >= v_offset
                        THEN
                                -- We already have enough data for a version within a table
                                -- Note that we probably have part of the next version description in v_hexdata
                                -- So we need to copy part of it, and keep the rest for next iteractions
                                LET v_aux=v_hexdata;
                                LET v_hexdata=SUBSTR(v_aux,v_offset+1,LENGTH(v_aux)-v_offset);
                                -- Split the version and number of pending pages part...
                                LET v_char_version = v_aux[1,4];
                                LET v_char_pages = v_aux[9,16];
                                -- Create a usable hex number. Prefix it with '0x' and convert due to little endian if that's the case
                                IF v_endian = "BIG"
                                THEN
                                        LET v_char_version = '0x'||v_char_version;
                                        LET v_char_pages = '0x'||v_char_pages;
                                ELSE
                                        LET v_aux_char = v_char_version;
                                        LET v_char_version[5]=v_aux_char[1];
                                        LET v_char_version[6]=v_aux_char[2];
                                        LET v_char_version[4]=v_aux_char[4];
                                        LET v_char_version[3]=v_aux_char[3];
                                        LET v_char_version[2]='x';
                                        LET v_char_version[1]='0';
                                        LET v_aux_char = v_char_pages;
                                        LET v_char_pages[9]=v_aux_char[1];
                                        LET v_char_pages[10]=v_aux_char[2];
                                        LET v_char_pages[7]=v_aux_char[3];
                                        LET v_char_pages[8]=v_aux_char[4];
                                        LET v_char_pages[6]=v_aux_char[6];
                                        LET v_char_pages[5]=v_aux_char[5];
                                        LET v_char_pages[3]=v_aux_char[7];
                                        LET v_char_pages[4]=v_aux_char[8];
                                        LET v_char_pages[2]='x';
                                        LET v_char_pages[1]='0';
                                END IF
                                -- HEX into DEC (integer)
                                LET v_version = TRUNC(v_char_version + 0);
                                LET v_pages = TRUNC(v_char_pages + 0);
                                IF v_pages > 0
                                THEN
                                        -- This version has pending pages so show it...
                                        RETURN TRIM(v_dbsname), TRIM(v_tabname), TRIM(v_partname), TRIM(v_obj_type), v_partnum, v_lockid, v_version, v_pages WITH RESUME;
                                END IF
                        END IF
                END IF
                END FOREACH
                IF LENGTH(v_hexdata) >= v_offset
                THEN
                        -- If we still have data to process...
                        LET v_aux=v_hexdata;
                        LET v_char_version = v_aux[1,4];
                        LET v_char_pages = v_aux[9,16];
                        IF v_endian = "BIG"
                        THEN
                                LET v_char_version = '0x'||v_char_version;
                                LET v_char_pages = '0x'||v_char_pages;
                        ELSE
                                LET v_aux_char = v_char_version;
                                LET v_char_version[5]=v_aux_char[1];
                                LET v_char_version[6]=v_aux_char[2];
                                LET v_char_version[4]=v_aux_char[4];
                                LET v_char_version[3]=v_aux_char[3];
                                LET v_char_version[2]='x';
                                LET v_char_version[1]='0';
                                LET v_aux_char = v_char_pages;
                                LET v_char_pages[9]=v_aux_char[1];
                                LET v_char_pages[10]=v_aux_char[2];
                                LET v_char_pages[7]=v_aux_char[3];
                                LET v_char_pages[8]=v_aux_char[4];
                                LET v_char_pages[6]=v_aux_char[6];
                                LET v_char_pages[5]=v_aux_char[5];
                                LET v_char_pages[3]=v_aux_char[7];
                                LET v_char_pages[4]=v_aux_char[8];
                                LET v_char_pages[2]='x';
                                LET v_char_pages[1]='0';
                        END IF
                        -- HEX into DEC (integer)
                        LET v_version = TRUNC(v_char_version + 0);
                        LET v_pages = TRUNC(v_char_pages + 0);
                        IF v_pages > 0
                        THEN
                                -- This version has pending pages so show it...
                                RETURN TRIM(v_dbsname), TRIM(v_tabname), TRIM(v_partname), TRIM(v_obj_type), v_partnum, v_lockid, v_version, v_pages WITH RESUME;
                        END IF
                END IF
        END WHILE
END FOREACH;
END FUNCTION;
-- For version 7.x use this close statement instead:
--END PROCEDURE;
Copy
execute function get_pending_ipa();

2.2 Resolve outstanding in-place alter operations

2.2.1 From version 12.10.xC4 or later

If you are reverting from version 12.10.xC4 or later, you can remove in-place alter operations by running the admin( ) or task( ) SQL administration command with the table update_ipa or fragment update_ipa argument. You can include the parallel option to run the operation in parallel. For example, the following statement removes in-place alter operations in parallel from a table that is named "mytable" at database "mydb":

Copy
database sysadmin;    
EXECUTE FUNCTION task('table update_ipa parallel','mytable','mydb');

2.2.2 From an earlier version of 12.10.xC4

If you are reverting from an earlier version of 12.10, you can resolve outstanding in-place alter operations by running dummy UPDATE statements. Dummy UPDATE statements force any outstanding in-place alter operations to complete by updating the rows in the affected tables. To generate a dummy UPDATE statement, create an UPDATE statement in which a column in the table is set to its own value. This forces the row to be updated to the latest schema without changing column values. Because the database server always alters rows to the latest schema, a single pass through the table that updates all rows completes all outstanding in-place alter operations.

The dummy UPDATE statement differs from a standard UPDATE statement because it does not change the data. A standard UPDATE statement usually changes the value of the affected row. For example, to create a dummy update, specify:

Copy
UPDATE tab1 SET col1=col1 WHERE 1=1;

You must ensure that the column selected is a numeric data type (for example, INTEGER of SMALLINT) and not a character data type (or failing that, a char(1) or a char as small as possible).

Updating big tables

The direct UPDATE on large tables can be produce a LONG TRANSACTION. In order to avoid it, you can use the following procedure indicating the table and field for each case.

Copy
CREATE PROCEDURE "informix".dei_dummyupdate(p_tabname CHAR, p_fieldname CHAR)
    DEFINE numrow SMALLINT;
    DEFINE fieldv CHAR;

    LET numrow = 0;

    FOREACH sal_cursor WITH HOLD FOR
        SELECT p_fieldname INTO fieldv FROM p_tabname

        IF numrow = 0 THEN
            BEGIN WORK;
        END IF

        LET numrow = numrow + 1;
        UPDATE p_tabname SET p_fieldname = p_fieldname
            WHERE CURRENT OF sal_cursor;

        IF numrow = 10000 THEN
            COMMIT WORK;
            LET numrow = 0;
        END IF

    END FOREACH
    IF numrow > 0 AND numrow < 10000 THEN
    	COMMIT WORK;
    END IF
END PROCEDURE;

Execute this procedure for each table and field

Copy
execute procedure dei_updrows(tabname, fieldname);

3 Ensure the scheduler is enabled

Informix upgrades datablade modules using the scheduler. Ensure the scheduler is not stopped, removing the file if exists:

Copy
rm $INFORMIXDIR/etc/sysadmin/stop

And then disable auto statistics tasks.

You can execute the following update to enable the auto statistics tasks:

Copy
dbaccess sysadmin;
UPDATE ph_task SET tk_enable='t' WHERE tk_name LIKE '%Statistics%';

Review the status of the sysadmin database statistics tasks.

Copy
dbaccess sysadmin;
SELECT tk_enable 
  FROM ph_task
 WHERE tk_name LIKE '%Statistics%';

4 Backup of the logical logs

Backup of the logical logs

Ensure the logical logs are backed up.

If the logical logs are not backed up the conversion from previous version will fail.

Copy
23:43:20  Initialization of Conversion Session
23:43:20  The restore point ended and related data in directory /home/informix/tmp/0 were removed.
23:43:21  Conversion halted because logs are not backed up.
            To continue conversion it is necessary to restart prior
            server and backup logical logs.
23:43:21  Conversion failed.
23:43:21  FAILED
23:43:21  Restart conversion after fixing the problem.

5 Disable the service

To prevent a poosible restart service done from systemd while the version is upgraded, is necessary to disable informix as service:

As root user execute:

Copy
systemctl disable informix

6 Shuts down the database server gracefully

If exists "open transaction" the conversion can not be continue:

Copy
23:25:19  An open transaction was detected when the database server changed log
          versions. Start the previous version of the database server in
          quiescent mode and then shut down the server gracefully, before
          migrating to this version of the server.
23:25:19  Cannot Rollforward from Checkpoint.

Shutsdowan gracefully to ensure close open transactions

The service must be stopped before do the new installation. Do a checkpoint before and ensure that there is no sessions either transactions open.

Copy
onmode -c
Copy
onmode -s

Stops the service

Copy
onmode -ky

And then starts in quiescent mode:

Copy
oninit -s

Stops the service

Copy
onmode -ky

7 Preserving previous version

If there is a previous version of Informix installed you must preserve the content:

Copy
cp -Rp $INFORMIXDIR ${INFORMIXDIR}_old

8 Installation

Run the Informix development installer to install the 14.10 Informix.

Copy
tar xvf INFORMIX_DEV_ED_14.10.FC1_Linux.tar

And install the software as user root. Make sure the $INFORMIXDIR is set to the correct path and ensure that is the same used on the proccess of installation:

Copy
su -
./ids_install

The development version has limi of 2GB of memory.

Last installation step

At the last step before confirm the installation ensure that the Informix is not running.

Copy
===============================================================================
Ready To Install
----------------

InstallAnywhere is now ready to install IBM Informix Software Bundle onto your
system at the following location:

   /home/informix

PRESS <ENTER> TO INSTALL:
Copy
onstat -
Shared memory is not initialized

9 Licensing the product

Upon the software is installed run the Informix edition installer to switch the 14.10 Informix installation from one edition to another (sample based on Enterprise Edition). As user informix:.

Copy
su - informix
unzip INFORMIX_EE_License_Ins_14.10.FC1.zip

Make sure the $INFORMIXDIR is set to the correct path and ensure that is the same used on the proccess of installation:

Copy
$HOME_JAVA8/bin/java -jar ee_edition.jar

10 Start informix

Now you can setart informix, and auto-upgraded will be executed

As user informix execute:

Copy
oninit -v

11 Enable the service

If the service was disabled, you can enable it again.

As user informix execute

Copy
onmode -c
onmode -s
onmode -ky

As root user execute:

Copy
systemctl enable informix
systemctl start informix