Passing array of a composite type to stored procedure

前端 未结 2 1899
再見小時候
再見小時候 2020-12-19 20:26

I\'m probably doing something wrong with forming the literal. Suppose I have a simple stored procedure like this:

CREATE OR REPLACE FUNCTION do_something(inp         


        
相关标签:
2条回答
  • 2020-12-19 20:31

    Craig explained well a reason for this behave - Assignment variable=value inside FOR statement expects zero nesting. So you should to do:

    CREATE OR REPLACE FUNCTION do_something(input_array composite_type[])
    RETURNS SETOF text AS $BODY$
    DECLARE
        temp_var record;
    BEGIN
         -- unnesting
        FOR temp_var IN SELECT (unnest(input_array)).*
        LOOP
            RETURN NEXT temp_var.message;
        END LOOP;
        RETURN;
    END
    $BODY$ LANGUAGE plpgsql;
    

    or -- preferable - newer use SetReturnedFunction inside "column list"

    CREATE OR REPLACE FUNCTION do_something(input_array composite_type[])
    RETURNS SETOF text AS $BODY$
    DECLARE
        temp_var record;
    BEGIN
         -- SELECT FROM
        FOR temp_var IN SELECT * FROM unnest(input_array) 
        LOOP
            RETURN NEXT temp_var.message;
        END LOOP;
        RETURN;
    END
    $BODY$ LANGUAGE plpgsql;
    
    0 讨论(0)
  • 2020-12-19 20:32

    How you specify your input appears fine, as the same behaviour is observed with row- and array-constructor syntax:

    SELECT * FROM do_something( ARRAY[ ROW('test',11), ROW('test2',22) ]::composite_type[] );
    

    And:

    SELECT ARRAY[ ROW('test',11), ROW('test2',22) ]::composite_type[];
    

    produces:

     '{"(test,11.00)","(test2,22.00)"}'
    

    If you add a:

     RAISE NOTICE '!%!',temp_var;
    

    inside the loop the output is:

    NOTICE:  !("(test,11.00)",)!
    NOTICE:  !("(test2,22.00)",)!
    

    showing that you're actually getting a tuple with "message" as the tuple text you expected and a null "amount".

    So. Why?

    It's a bit of a subtle one. You're using:

    SELECT unnest(input_array)
    

    which seems to do what you want, right:

    regress=>     SELECT unnest( ARRAY[ ROW('test',11), ROW('test2',22) ]::composite_type[] );
        unnest     
    ---------------
     (test,11.00)
     (test2,22.00)
    (2 rows)
    

    ... but actually, it's returning a single column of type composite_type. PL/PgSQL composite type assignment expects one column per type column instead. So the single col is being shoved into 'message' and there is no second col.

    Instead, write:

    SELECT * FROM unnest(input_array)
    

    to unpack the composite for assignment. Then it works as expected:

    regress=> SELECT * FROM do_something( ARRAY[ ROW('test',11), ROW('test2',22) ]::composite_type[] );
     do_something 
    --------------
     test
     test2
    (2 rows)
    

    If the first field of composite_type were of a non-text type, you'd get an error that was rather more informative about this.

    0 讨论(0)
提交回复
热议问题