views:

82

answers:

1

Good day gurus,

I have a script that populates tables on a regular basis that crashed and gave the above error. The strange thing is that it has been running for close to 3 months on the production system with no problems and suddenly crashed last week. There has not been any changes on the tables as far as I know.

Has anyone encountered something like this before? I believe it has something to do with the aggregate functions I'm implementing in it; but it worked initially.

please; kindly find attached the part of the script I've developed into a procedure that I reckon gives the error.

CREATE OR REPLACE PROCEDURE V1 IS

--DECLARE

    v_a       VARCHAR2(4000);
    v_b       VARCHAR2(4000);
    v_c       VARCHAR2(4000);
    v_d       VARCHAR2(4000);
    v_e       VARCHAR2(4000);
    v_f       VARCHAR2(4000);
    v_g       VARCHAR2(4000);
    v_h       VARCHAR2(4000);
    v_i       VARCHAR2(4000);
    v_j       VARCHAR2(4000);
    v_k       VARCHAR2(4000);
    v_l       VARCHAR2(4000);
    v_m       VARCHAR2(4000);
    v_n       NUMBER(10);
    v_o       VARCHAR2(4000);

--
-- Procedure that populates DEMO table

        BEGIN

              -- Delete all from the DEMO table
              DELETE FROM DEMO;

              -- Populate fields in DEMO from DEMOV1
              INSERT INTO DEMO(ID, D_ID, CTR_ID, C_ID, DT_NAM, TP, BYR, ENY,
                               ONG, SUMM, DTW, REV, LD, MD, STAT, CRD)
              SELECT ID, D_ID, CTR_ID, C_ID, DT_NAM, TP, TO_NUMBER(TO_CHAR(BYR,'YYYY')), 
                   TO_NUMBER(TO_CHAR(NVL(ENY,SYSDATE),'YYYY')), CASE WHEN ENY IS NULL THEN 'Y' ELSE 'N' END, SUMMARY, DTW,
                   REV, LD, MD, '1', SYSDATE 
              FROM DEMOV1;

          -- LOOP THROUGH DEMO TABLE
          FOR j IN (SELECT ID, CTR_ID, C_ID FROM DEMO)
          LOOP




                Select semic_concat(TXTDESC)
                INTO v_a 
                From GEOT
                WHERE ID = j.ID;



               SELECT COUNT(*)
               INTO v_n
               FROM MERP M, PROJ P
               WHERE M.MID = P.COD
               AND ID = j.ID
               AND PROAC IS NULL;

               IF (v_n > 0)
               THEN


                    Select semic_concat(PRO)
                    INTO v_b 
                    FROM MERP M, PROJ P
                    WHERE M.MID = P.COD
                    AND ID = j.ID;

               ELSE


                    Select semic_concat(PRO || '(' || PROAC || ')' )
                    INTO v_b 
                    FROM MERP M, PROJ P
                    WHERE M.MID = P.COD
                    AND ID = j.ID;

               END IF;


                Select semic_concat(VOCNAME('P02',COD))
                INTO v_c 
                From PAR
                WHERE ID = j.ID;



                Select semic_concat(VOCNAME('L05',COD))
                INTO v_d 
                From INST
                WHERE ID = j.ID;


                Select semic_concat(NVL(AUTHOR,'Anon') ||' ('||to_char(PUB,'YYYY')||') '||TITLE||', '||EDT)
                INTO v_e 
                From REFE
                WHERE ID = j.ID;



                Select semic_concat(NAM)
                INTO v_f 
                FROM EDM E, EDO EO
                WHERE E.EDMID = EO.EDOID
                AND ID = j.ID;



                Select semic_concat(VOCNAME('L08', COD))
                INTO v_g 
                FROM AVA 
                WHERE ID = j.ID;



               SELECT or_concat(NAM)
               INTO v_o
               FROM CON 
               WHERE ID = j.ID
               AND NAM = 'Unknown';

                    IF (v_o = 'Unknown')
                    THEN

                        Select or_concat(JOBTITLE || ' (' || EMAIL || ')')
                        INTO v_h 
                        FROM CON 
                        WHERE ID = j.ID;

                    ELSE

                        Select or_concat(NAM || ' (' || EMAIL || ')')
                        INTO v_h 
                        FROM CON 
                        WHERE ID = j.ID;

                    END IF;



                Select commaencap_concat(COD)
                INTO v_i 
                FROM PAR 
                WHERE ID = j.ID;

                IF (v_i = ',')
                THEN

                    v_i := null;

                ELSE

                    Select commaencap_concat(COD)
                    INTO v_i 
                    FROM PAR 
                    WHERE ID = j.ID;


                END IF;



                Select commaencap_concat(COD)
                INTO v_j 
                FROM INST 
                WHERE ID = j.ID;

                IF (v_j = ',')
                THEN

                    v_j := null;

                ELSE

                    Select commaencap_concat(COD)
                    INTO v_j 
                    FROM INST
                    WHERE ID = j.ID;

                END IF;



                Select commaencap_concat(COD)
                    INTO v_k 
                    FROM SAR 
                    WHERE ID = j.ID;

                IF (v_k = ',')
                THEN

                    v_k := null;

                ELSE

                    Select commaencap_concat(COD)
                    INTO v_k 
                    FROM SAR 
                    WHERE ID = j.ID;

                END IF;




                Select commaencap_concat(CONID)
                    INTO v_l 
                    FROM CON 
                    WHERE ID = j.ID;

                IF (v_l = ',')
                THEN

                    v_l := null;

                ELSE

                    Select commaencap_concat(CONID)
                    INTO v_l 
                    FROM CON 
                    WHERE ID = j.ID;

                END IF;



                Select commaencap_concat(PROID)
                    INTO v_m 
                    FROM PRO 
                    WHERE ID = j.ID;

                IF (v_m = ',')
                THEN

                    v_m := null;

                ELSE

                    Select commaencap_concat(PROID)
                    INTO v_m 
                    FROM PRO 
                    WHERE ID = j.ID;

                END IF;

                 -- UPDATE DEMO TABLE
                 UPDATE DEMO
                 SET GEOC = v_a,
                     PRO = v_b,
                     PAR = v_c,
                     INS = v_d,
                     REFER = v_e,
                     ORGR = v_f,
                     AVAY = v_g,
                     CON = v_h,
                     DTH = v_i,
                     INST = v_j,
                     SA = v_k,
                     CC = v_l,
                     EDPR = v_m,
                     CTR = (SELECT NAM
                                  FROM EDM
                                  WHERE EDMID = j.CTR_ID),
                     COLL = (SELECT NAM
                                    FROM EDM
                                    WHERE EDMID = j.C_ID)

                WHERE ID = j.ID;

          END LOOP;


        END V1;

/

The aggregate functions, commaencap_concat (encapsulates with a comma), or_concat (concats with an or) and semic_concat(concats with a semi-colon).

the remaining tables used are all linked to the main table DEMO.

I have checked the column sizes and there seems to be no problem. I tried executing the SELECT statements alone and they give the same error without populating the tables.

Any clues?

Many thanks for your anticipated support.

Thanks APC for all your help; particularly the rowtype and debug advice. I have checked all columns against each other and have made those that were less than 4000 bytes to 4000 bytes in size but I'm still getting the same error message.

The SELECT statement I tried was with one of the aggregate functions that is in the procedure:

            Select semic_concat(TXTDESC)
           -- INTO v_a 
            From GEOT
            WHERE ID IN (SELECT ID FROM DEMO);

and it raised the same error of string buffer too small; but when I added a group by to the statement it worked.

            Select semic_concat(TXTDESC)
            -- INTO v_a 
            From GEOT
            WHERE ID IN (SELECT ID FROM DEMO)
            GROUP BY ID;

I tried swapping all occurrences of such statements in the procedure but it still gives the same error. Thanks once again; still working on it.

+4  A: 

Aggregating functions, er, aggregate. That means that they add numbers or concatenate strings together. The larger the source values the bigger the aggegated product.

Without knowing more details it is hard to be certain, but the most likely explanation is that something in your data has changed, with the consequence that your aggregated value is now too big to fit in the target column.

edit

" I tried the SELECT statement on its own and gives the same error... "

Hmmm, which SELECT? Your procedure has got oodles of them.

Anyway, the thing you need to do is learn to debug your code. (1)

The best way to debug PL/SQL is with an IDE which supports such endeavours. Both TOAD and PL/SQL Developer do so, as does Oracle's own (free) product SQL Developer. Find out more.

Alternatively you can use DBMS_OUTPUT (AKA the Devil's Debugger) and interpolate lots of DBMS_OUTPUT.PUT_LINE() calls to see which statement you're about to execute, and the length of the relevant values.

However, given that all your PL/SQL string variables are the maximum SQL column length - varchar2(4000) - I would focus on the code which populates your v_n variable. number(10) is by no means the biggest number it is possible to hold in SQL, so as you are breaching a buffer limit that would seem the most likely candidate. Although, since the error message does mention string buffer I may be selling you a bum steer.

The other possibility is that final UPDATE statement. Are all the columns of DEMO sized as varchar2(4000)? If not then you need to look at them. It is good practice to specify variables using the %TYPE syntax:

 v_a demo.geoc%TYPE;
 v_b demo.pro%TYPE;

Or, to save typing, specify a single record variable:

v_demo demo%rowtype;

Which you can reference like this:

select semic_concat(TXTDESC) 
into v_demo.geoc  
From GEOT 
WHERE ID = j.ID; 

(Incidentally it possible to use a row level variable in update statements using the UPDATE ... SET ROW = syntax, but I don't think that would be appropriate in your situation.)

edit 2

Again, NO_DATA_FOUND points to a data issue. Unless our database is read only, we must expect that data will change and we should handle data-related exceptions. If the reason you don't handle NO_DATA_FOUND is because the data should always be there you have a broader problem, possibly a missing or disabled foreign key. Generally it is safer to assume that we will get NO_DATA_FOUND, TOO_MANY_ROWS, etc and include helpful exception handlers to log the relevant details.


footnote (1) Or learn to develop it Test First using a unit test harness, but this is a stable door, horse gone scenario...

APC
@APC, yep. I tried the SELECT statement on its own and gives the same error...
Tunde
Voted up for the term "Devil's debugger"
Gary
APC, many thanks again for your help and assistance. I am now getting a different error message of "NO DATA FOUND" with one of the select statements involving the aggregate functions. The strange thing is that it worked for close to 3 months... still working on it.Thanks once again; I really appreciate your efforts.
Tunde
Many thanks APC, I have added the NO_DATA_FOUND exception and it has stopped crashing but not doing what its meant to do i.e. populating the DEMO table; but I doubt this is the problem. Each SQL statement returns a value when run separately outside the PL/SQL block; i.e. Select semic_concat(TXTDESC) -- INTO v_a From GEOT WHERE ID IN (SELECT ID FROM DEMO) GROUP BY ID;Thanks once again.
Tunde
Many thanks APC, I was able to fix it. It was actually one of the aggregated values that was larger than 4000 bytes and was to big for both the aggregate function and the destination column. This increased in size due to more data added to the source table.Many thanks again for your help, assistance and advice. Cheers
Tunde