简体   繁体   中英

How can I get output values into output parameters?

I am using C# in VS 2008 to retrieve data from a PostgreSQL stored procedure that has two input parameters and two output parameters. When I created the procedure, PostgreSQL told me that I had to specify that it returns a record.

In VS2008, my first attempt to use the procedure involved creating an OdbcCommand object of type CommandType.StoredProcedure and giving it four parameters, two with direction of Input and two of direction Output. The command executed without error, first using ExecuteNonQuery() and then using ExecuteReader() , but the values of the output parameters were null. I called the reader's GetValues() function, and found that the result was a single object containing the string "{3,4}" .

Then, following a suggestion from StackOverflow, I changed the command text to: {call closest_idle_cover(?, ?, ?, ?)}

This also worked, and GetValues() gave me an array of two objects of type int, one with 3 and the other with 4. This was quite a bit better, since I wouldn't have to parse a string. But the output parameters still have null values, and indeed, the command works just as well if I only pass in the two input parameters.

So, although I have a solution that works, I remain curious: How can I get the values into my output parameters?

Here's the PostgreSQL stored procedure:

CREATE OR REPLACE FUNCTION plant_genie.closest_idle_cover(IN int, IN int, OUT int, OUT int)
  RETURNS record AS
$BODY$
DECLARE
    current_x ALIAS FOR $1;
    current_y ALIAS FOR $2;
    target_x ALIAS FOR $3;
    target_y ALIAS FOR $4;
    coverLocations ic_storage_locations%rowtype;
BEGIN
    target_x := 3;
    target_y := 4;  

    SELECT INTO coverLocations * 
    FROM ic_storage_locations 
    WHERE inner_cover IS NOT NULL 
    ORDER BY sqrt(pow(current_x - ic_storage_locations.x_coordinate, 2) + 
            pow(current_y - ic_storage_locations.y_coordinate, 2))
    LIMIT 1;

    IF FOUND THEN
        INSERT INTO op_messages (message) VALUES ('Found a cover location record.');
        target_x := coverLocations.x_coordinate;
        target_y := coverLocations.y_coordinate;
    ELSE
        INSERT INTO op_messages (message) VALUES ('Could not find a cover location record.');
    END IF;
END;
$BODY$ LANGUAGE 'plpgsql' VOLATILE COST 100;

You are using OUT parameters but then also a RETURNS record clause, without having an explicit RETURN statement in the body of the function. That combination does not work. A more elegant solution than using OUT parameters is to define the output table format - it is more obvious what is going on:

CREATE OR REPLACE FUNCTION plant_genie.closest_idle_cover(current_x int, current_y int)
RETURNS TABLE (target_x int, target_y int) AS $BODY$
DECLARE
    coverLocations ic_storage_locations%rowtype;
BEGIN
    SELECT INTO coverLocations * 
    FROM ic_storage_locations 
    WHERE inner_cover IS NOT NULL 
    ORDER BY pow(current_x - ic_storage_locations.x_coordinate, 2) + 
             pow(current_y - ic_storage_locations.y_coordinate, 2)
    LIMIT 1;

    IF FOUND THEN
        INSERT INTO op_messages (message) VALUES ('Found a cover location record.');
        RETURN QUERY SELECT coverLocations.x_coordinate, coverLocations.y_coordinate;
    ELSE
        INSERT INTO op_messages (message) VALUES ('Could not find a cover location record.');
    END IF;
END; $BODY$ LANGUAGE 'plpgsql' STRICT;

So if you call this function you are returned a record if at least 1 ic_storage_location is not null:

SELECT * FROM plant_genie.closest_idle_cover(1, 2);

You can deal with that in your C# code like you would any other data you pull out of the database.

A few observations:

  • Since you are looking for the nearest ic_storage_location you can dispense with the SQRT() function call, which is computationally expensive. Just working with the squared sums has the same property of ordering records by distance from the current location.
  • The function is defined as STRICT because it requires values for both parameters to work properly.
  • Don't assign COST values yourself, unless you really know what you are doing.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM