db2-luwdatabase-cursorreorganize

DB2 LUW How to CHECK/REORG Tables in a loop?


I have the following statements intended to CHECK/REORG tables in a loop. Partially, this works.

BEGIN
    DECLARE SQLSTATE    CHAR(5);
    DECLARE RetState    CHAR(5);
    DECLARE SqlStmt     VARCHAR(1000);
    DECLARE Not_Needed  CONDITION FOR '51027';
    DECLARE CONTINUE HANDLER for Not_Needed
        BEGIN
            SET RetState = SQLSTATE;
        END;
    FOR i AS (SELECT TABNAME FROM SYSIBMADM.ADMINTABINFO WHERE TABSCHEMA = 'LIBRAT' AND REORG_PENDING = 'Y')
    DO
        SET SqlStmt = 'SET INTEGRITY FOR LIBRAT.'||Trim(TABNAME)||' IMMEDIATE CHECKED';
        EXECUTE IMMEDIATE SqlStmt;
        IF RetState = '51027' THEN
--          SET SqlStmt = 'REORG TABLE LIBRAT.'||Trim(TABNAME);
--          EXECUTE IMMEDIATE SqlStmt;
            CALL SYSPROC.ADMIN_CMD('REORG TABLE LIBRAT.'||Trim(TABNAME));
        END IF;
        SET RetState = NULL;
    END FOR;
END@

However, I first tried performing the REORG as an IMMEDIATE command and got this message.

Error: An unexpected token "LIBRAT" was found following "REORG TABLE ". Expected tokens may include: "JOIN".. SQLCODE=-104, SQLSTATE=42601, DRIVER=4.33.31

So, then I tried the ADMIN_CMD procedure. It works, but then my FOR cursor fails as follows.

Error: The cursor specified in a FETCH statement or CLOSE statement is not open or a cursor variable in a cursor scalar function reference is not open.. SQLCODE=-501, SQLSTATE=24501, DRIVER=4.33.31

Apparently, the procedure is performing a COMMIT. Is there a way to do this while avoiding these pitfalls? Thanks.


Solution

  • REORG closes even WITH HOLD cursors.
    You may store your commands to, say, char array, and process it then w/o cursors like in the example below.

    BEGIN
      DECLARE v_arr DBMS_OUTPUT.CHARARR;
      DECLARE SQLSTATE CHAR(5);
      DECLARE v_ind INT DEFAULT 1;
      DECLARE c1 CURSOR FOR 
        SELECT 'REORG TABLE "' || TABSCHEMA || '"."' || TABNAME || '"' 
        FROM SYSCAT.TABLES
        WHERE TYPE = 'T'
        LIMIT 2;
    
      OPEN C1;
      L1: LOOP
        FETCH C1 INTO v_arr[v_ind];
        IF SQLSTATE = '02000' THEN LEAVE L1; END IF;
        SET v_ind = v_ind + 1;
      END LOOP L1;
      CLOSE C1;
    
      SET v_ind = 1;
      WHILE v_ind <= CARDINALITY(v_arr) DO
        CALL ADMIN_CMD(v_arr[v_ind]);
        --CALL DBMS_OUTPUT.PUT_LINE(v_arr[v_ind]);
        SET v_ind = v_ind + 1;
      END WHILE;
    END
    @