Referring to function parameter in function

Started by Thom Brownover 15 years ago4 messagesgeneral
Jump to latest
#1Thom Brown
thom@linux.com

I appear to be having a problem with a function I've created, and no
doubt it'll be something obvious I'm doing wrong. Here's my function:

CREATE OR REPLACE FUNCTION get_lsfr(
bitlength INT,
taps INT[],
from_value INT
) RETURNS INT AS $$
DECLARE
last_tap_value BIT;
tap INT;
new_value INT;
BEGIN
IF (SELECT MAX(x) FROM unnest(taps) AS x) > bitlength THEN
RAISE EXCEPTION 'LSFR tap exceeds range of value.';
END IF;

FOR tap IN SELECT value FROM unnest(taps) AS x(value) ORDER BY value DESC LOOP
IF last_tap_value IS NOT NULL THEN
last_tap_value := last_tap_value #
GET_BIT(from_value::bit(bitlength), tap.value-1);
ELSE
last_tap_value := GET_BIT(from_value::bit(bitlength), tap.value-1);
CONTINUE;
END IF;
END LOOP;

new_value := (last_tap_value || SUBSTRING(from_value::BIT(bitlength),
1, bitlength - 1))::BIT(bitlength)::INT;

RETURN new_value;
END;
$$ LANGUAGE plpgsql;

And here's it's usage and result:

select get_lsfr(4,'{3,4}'::int[],6);
ERROR: invalid input syntax for integer: "bitlength"
LINE 1: SELECT GET_BIT(from_value::bit(bitlength), tap.value-1)
^
QUERY: SELECT GET_BIT(from_value::bit(bitlength), tap.value-1)
CONTEXT: PL/pgSQL function "get_lsfr" line 14 at assignment

If the function is difficult to read, please look at this paste:
http://pgsql.privatepaste.com/fd5b83166c

I want to use the parameter called "bitlength" as the length of a bit
when casting a value.

So, in this case, it would be GET_BIT(6::bit(4), 4-1)

What am I missing?

--
Thom Brown
Twitter: @darkixion
IRC (freenode): dark_ixion
Registered Linux user: #516935

#2Tom Lane
tgl@sss.pgh.pa.us
In reply to: Thom Brown (#1)
Re: Referring to function parameter in function

Thom Brown <thom@linux.com> writes:

ERROR: invalid input syntax for integer: "bitlength"
LINE 1: SELECT GET_BIT(from_value::bit(bitlength), tap.value-1)
^

I want to use the parameter called "bitlength" as the length of a bit
when casting a value.

Hm, you can't ... that's not a valid place for a parameter. You'd have
to EXECUTE a built-up string.

regards, tom lane

#3Thom Brown
thom@linux.com
In reply to: Tom Lane (#2)
Re: Referring to function parameter in function

On 18 September 2010 00:14, Tom Lane <tgl@sss.pgh.pa.us> wrote:

Thom Brown <thom@linux.com> writes:

ERROR:  invalid input syntax for integer: "bitlength"
LINE 1: SELECT GET_BIT(from_value::bit(bitlength), tap.value-1)
                                   ^

I want to use the parameter called "bitlength" as the length of a bit
when casting a value.

Hm, you can't ... that's not a valid place for a parameter.  You'd have
to EXECUTE a built-up string.

Ah, thanks Tom. Although it's now treating the actual query text as a
value by the look of it:

CREATE OR REPLACE FUNCTION get_lsfr(
bitlength INT,
taps INT[],
from_value INT
) RETURNS INT AS $$
DECLARE
last_tap_value BIT;
tap RECORD;
new_value INT;
BEGIN
IF (SELECT MAX(x) FROM unnest(taps) AS x) > bitlength THEN
RAISE EXCEPTION 'LSFR tap exceeds range of value.';
END IF;

FOR tap IN SELECT tap_values FROM unnest(taps) AS x(tap_values) ORDER
BY tap_values DESC LOOP
IF last_tap_value IS NOT NULL THEN
EXECUTE 'SELECT ' || last_tap_value || ' # GET_BIT(' || from_value
|| '::bit(' || bitlength || '), ' || tap.tap_values || '-1)' INTO
last_tap_value;
ELSE
EXECUTE 'SELECT GET_BIT(' || from_value || '::bit(' || bitlength ||
'), ' || tap.tap_values || '-1)' INTO last_tap_value;
CONTINUE;
END IF;
END LOOP;

new_value := (last_tap_value || SUBSTRING(from_value::BIT(bitlength),
1, bitlength - 1))::BIT(bitlength)::INT;

RETURN new_value;
END;
$$ LANGUAGE plpgsql;

=# select get_lsfr(4,'{3,4}'::int[],6);
ERROR: "S" is not a valid binary digit
LINE 1: SELECT 'SELECT ' || last_tap_value || ' # GET_BIT(' || from_...
^
QUERY: SELECT 'SELECT ' || last_tap_value || ' # GET_BIT(' ||
from_value || '::bit(' || bitlength || '), ' || tap.tap_values ||
'-1)'
CONTEXT: PL/pgSQL function "get_lsfr" line 12 at EXECUTE statement

http://pgsql.privatepaste.com/5441ff7cc0

I'm thinking maybe I haven't used the correct syntax.
--
Thom Brown
Twitter: @darkixion
IRC (freenode): dark_ixion
Registered Linux user: #516935

#4Thom Brown
thom@linux.com
In reply to: Thom Brown (#3)
Re: Referring to function parameter in function

On 18 September 2010 00:52, Thom Brown <thom@linux.com> wrote:

On 18 September 2010 00:14, Tom Lane <tgl@sss.pgh.pa.us> wrote:

Thom Brown <thom@linux.com> writes:

ERROR:  invalid input syntax for integer: "bitlength"
LINE 1: SELECT GET_BIT(from_value::bit(bitlength), tap.value-1)
                                   ^

I want to use the parameter called "bitlength" as the length of a bit
when casting a value.

Hm, you can't ... that's not a valid place for a parameter.  You'd have
to EXECUTE a built-up string.

Ah, thanks Tom.  Although it's now treating the actual query text as a
value by the look of it:

CREATE OR REPLACE FUNCTION get_lsfr(
       bitlength INT,
       taps INT[],
       from_value INT
) RETURNS INT AS $$
DECLARE
       last_tap_value BIT;
       tap RECORD;
       new_value INT;
BEGIN
       IF (SELECT MAX(x) FROM unnest(taps) AS x) > bitlength THEN
               RAISE EXCEPTION 'LSFR tap exceeds range of value.';
       END IF;

       FOR tap IN SELECT tap_values FROM unnest(taps) AS x(tap_values) ORDER
BY tap_values DESC LOOP
               IF last_tap_value IS NOT NULL THEN
                       EXECUTE 'SELECT ' || last_tap_value || ' # GET_BIT(' || from_value
|| '::bit(' || bitlength || '), ' || tap.tap_values || '-1)' INTO
last_tap_value;
               ELSE
                       EXECUTE 'SELECT GET_BIT(' || from_value || '::bit(' || bitlength ||
'), ' || tap.tap_values || '-1)' INTO last_tap_value;
                       CONTINUE;
               END IF;
       END LOOP;

       new_value := (last_tap_value || SUBSTRING(from_value::BIT(bitlength),
1, bitlength - 1))::BIT(bitlength)::INT;

       RETURN new_value;
END;
$$ LANGUAGE plpgsql;

=# select get_lsfr(4,'{3,4}'::int[],6);
ERROR:  "S" is not a valid binary digit
LINE 1: SELECT 'SELECT ' || last_tap_value || ' # GET_BIT(' || from_...
              ^
QUERY:  SELECT 'SELECT ' || last_tap_value || ' # GET_BIT(' ||
from_value || '::bit(' || bitlength || '), ' || tap.tap_values ||
'-1)'
CONTEXT:  PL/pgSQL function "get_lsfr" line 12 at EXECUTE statement

http://pgsql.privatepaste.com/5441ff7cc0

I'm thinking maybe I haven't used the correct syntax.
--

I've solved it. These constructs take a bit of getting used to. I
just needed to convert the parameter being injected after the SELECT
to text as the bit value couldn't be inserted natively. My function
works perfectly now. Thanks for the help :)

--
Thom Brown
Twitter: @darkixion
IRC (freenode): dark_ixion
Registered Linux user: #516935