Search code examples
postgresqlcursorplpgsql

Postgres cursor is not taking multiple parameters


I have created a procedure, and inside the procedure I have created a parameterized cursor to which I am passing parameters. The Cursor query has two parameters: one parameter of the procedure and the other is the parameter of the cursor.

When I am opening the cursor with the parameter of the cursor, it is not taking the value of the procedure parameter. When I am creating a cursor with no parameter, it is taking the parameter of the procedure.

See the example below: c2 opens just fine and inserts data into v_text, but when I am trying to open c9 it gives me the error

ERROR:  column "p_plan_version_id" does not exist
HINT:  Perhaps you meant to reference the column "pos.plan_version_id"
CREATE OR REPLACE PROCEDURE create_file(IN p_plan_version_id NUMERIC) LANGUAGE plpgsql
AS $procedure$
    DECLARE
        v_text text;
        j record;
        l record;
        c2 CURSOR FOR
            SELECT pq.product_code,
                   SUM(quantity) quantity
            FROM product_quantity pq,
                 products         ep
            WHERE pq.plan_version_id = p_plan_version_id
            --and pipeline_id  =1
              AND     pq.product_code = ep.product_code
            GROUP BY product_code;

        C9 CURSOR (p_product_code VARCHAR) IS
            SELECT product_code ,
                   terminal_code,
                   quantity
            FROM product_stock pos
            WHERE pos.plan_version_id = p_plan_version_id
              AND pos.product_code    = p_product_code;

    BEGIN
        OPEN c2;
        --for j in C2
        LOOP
            FETCH c2 INTO j;
            EXIT WHEN NOT found;

            v_text := j.product_code
                      || ','
                      || j.quantity
                      || ',,,,,,,,,,,,,,,,,,,,';
        END LOOP;

        CLOSE c2;

        OPEN c9('OIL');
        LOOP
            FETCH c9 INTO l;
            EXIT WHEN NOT found;
 
            v_text = v_text
                     || l.product_code
                     || ','
                     || l.terminal_code
                     || ','
                     || l.quantity
                     || ','
                     || ',,,,,,,,,,,,,,,,,,,,';
        END LOOP;

        v_text = v_text
                 || ',,,,,0,0,,,,,,,,,,,,,,,,,,,,,,,,,,';
        CLOSE c9;
        raise info 'Text: %',v_text;
    END;
$procedure$;

How to pass multiple parameters to a cursor?


Solution

  • With c9, should PostgreSQL use the value of p_plan_version_id as it is in the DECLARE section, or as it is when you OPEN c9? To resolve this ambiguity, you need to pass both parameters when you open the cursor:

    DECLARE
       c9 CURSOR (p_product_code varchar, p_pvi numeric) FOR
          SELECT product_code,
                 terminal_code,
                 quantity
          FROM product_stock pos
          WHERE pos.plan_version_id = p_pvi
            AND pos.product_code    = p_product_code;
    BEGIN
       OPEN c9('OIL', p_plan_version_id);
       ...
    END;
    

    Here is a complete example to demonstrate that this works:

    CREATE FUNCTION sample(upper_limit bigint) RETURNS SETOF bigint
       LANGUAGE plpgsql AS
    $$DECLARE
       c CURSOR (l bigint, u bigint) FOR
          SELECT * FROM generate_series(l, u) AS g(c);
       r record;
    BEGIN
       OPEN c(1, upper_limit);
       LOOP
          FETCH c INTO r;
          EXIT WHEN NOT FOUND;
    
          RETURN NEXT r.c;
       END LOOP;
    END;$$;
    
    SELECT * FROM sample(10);
    
     sample 
    ════════
          1
          2
          3
          4
          5
          6
          7
          8
          9
         10
    (10 rows)