Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
706 views
in Technique[技术] by (71.8m points)

sql - Passing array of a composite type to stored procedure

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(input_array composite_type[])
  RETURNS SETOF text AS
$BODY$
DECLARE
    temp_var composite_type;
BEGIN

    FOR temp_var IN SELECT unnest(input_array) LOOP
        return next temp_var.message;
    END LOOP;

END
$BODY$
  LANGUAGE plpgsql;

The composite_type is defined as:

CREATE TYPE composite_type AS
   (message text,
    amount numeric(16,2));

Performing a query like this:

SELECT * FROM do_something('{"(test,11)","(test2,22)"}')

Produces this result set:

(test,11.00)
(test2,22.00)

Instead of:

test
test2

Is it something wrong with my literal or should I access the message field in a different way? Thanks for any suggestions.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

1.4m articles

1.4m replys

5 comments

56.8k users

...