Обсуждение: Possible bug in PL/Python?

Поиск
Список
Период
Сортировка

Possible bug in PL/Python?

От
Jeroen van Dongen
Дата:
Hi,

In a current project I've a PL/Python function that uses default parameters, like this:

CREATE FUNCTION auth.create_user(
    email text, 
    initial_password text, 
    display_name text DEFAULT NULL,
    mobile_phone text DEFAULT NULL, 
    status auth.enum_user_status DEFAULT 'active'
) RETURNS text AS $$
... rest of function ...

Now I try to test if 'display_name' is actually passed or not, and if not set it to something sensible, like so:
...
    if display_name is None:
        display_name = email[:email.find('@')]
...

And ... that fails with an error stating that 'display_name' is referenced before assignment.
However, if I do it like this, it works:
...
if display_name is None:
        real_display_name = email[:email.find('@')]
...

In straight Python the first example works, however in PL/Python only the second works.

Is this how it is supposed to be and did I perhaps miss something in the docs, or is it a bug?

Kind regards,
Jeroen

Re: Possible bug in PL/Python?

От
Adrian Klaver
Дата:
On Tuesday, January 17, 2012 8:27:19 am Jeroen van Dongen wrote:
> Hi,
>
> In a current project I've a PL/Python function that uses default
> parameters, like this:
>
> CREATE FUNCTION auth.create_user(
>     email text,
>     initial_password text,
>     display_name text DEFAULT NULL,
>     mobile_phone text DEFAULT NULL,
>     status auth.enum_user_status DEFAULT 'active'
> ) RETURNS text AS $$
> ... rest of function ...
>
> Now I try to test if 'display_name' is actually passed or not, and if not
> set it to something sensible, like so:
> ...
>     if display_name is None:
>         display_name = email[:email.find('@')]
> ...
>
> And ... that fails with an error stating that 'display_name' is referenced
> before assignment.
> However, if I do it like this, it works:
> ...
> if display_name is None:
>         real_display_name = email[:email.find('@')]
> ...
>
> In straight Python the first example works, however in PL/Python only the
> second works.
>
> Is this how it is supposed to be and did I perhaps miss something in the
> docs, or is it a bug?

http://www.postgresql.org/docs/9.0/interactive/plpython-funcs.html

"
The arguments are set as global variables. Because of the scoping rules of
Python, this has the subtle consequence that an argument variable cannot be
reassigned inside the function to the value of an expression that involves the
variable name itself, unless the variable is redeclared as global in the block.
For example, the following won't work:

CREATE FUNCTION pystrip(x text)
  RETURNS text
AS $$
  x = x.strip()  # error
  return x
$$ LANGUAGE plpythonu;
because assigning to x makes x a local variable for the entire block, and so the
x on the right-hand side of the assignment refers to a not-yet-assigned local
variable x, not the PL/Python function parameter. Using the global statement,
this can be made to work:

CREATE FUNCTION pystrip(x text)
  RETURNS text
AS $$
  global x
  x = x.strip()  # ok now
  return x
$$ LANGUAGE plpythonu;
But it is advisable not to rely on this implementation detail of PL/Python. It
is better to treat the function parameters as read-only.

"
>
> Kind regards,
> Jeroen

--
Adrian Klaver
adrian.klaver@gmail.com

Re: Possible bug in PL/Python?

От
Jeroen Van Dongen
Дата:
Thanks! I'd missed that part apparently :(

Regards,
Jeroen

Op 17 jan. 2012 om 17:40 heeft Adrian Klaver <adrian.klaver@gmail.com> het volgende geschreven:

> On Tuesday, January 17, 2012 8:27:19 am Jeroen van Dongen wrote:
>> Hi,
>>
>> In a current project I've a PL/Python function that uses default
>> parameters, like this:
>>
>> CREATE FUNCTION auth.create_user(
>>    email text,
>>    initial_password text,
>>    display_name text DEFAULT NULL,
>>    mobile_phone text DEFAULT NULL,
>>    status auth.enum_user_status DEFAULT 'active'
>> ) RETURNS text AS $$
>> ... rest of function ...
>>
>> Now I try to test if 'display_name' is actually passed or not, and if not
>> set it to something sensible, like so:
>> ...
>>    if display_name is None:
>>        display_name = email[:email.find('@')]
>> ...
>>
>> And ... that fails with an error stating that 'display_name' is referenced
>> before assignment.
>> However, if I do it like this, it works:
>> ...
>> if display_name is None:
>>        real_display_name = email[:email.find('@')]
>> ...
>>
>> In straight Python the first example works, however in PL/Python only the
>> second works.
>>
>> Is this how it is supposed to be and did I perhaps miss something in the
>> docs, or is it a bug?
>
> http://www.postgresql.org/docs/9.0/interactive/plpython-funcs.html
>
> "
> The arguments are set as global variables. Because of the scoping rules of
> Python, this has the subtle consequence that an argument variable cannot be
> reassigned inside the function to the value of an expression that involves the
> variable name itself, unless the variable is redeclared as global in the block.
> For example, the following won't work:
>
> CREATE FUNCTION pystrip(x text)
>  RETURNS text
> AS $$
>  x = x.strip()  # error
>  return x
> $$ LANGUAGE plpythonu;
> because assigning to x makes x a local variable for the entire block, and so the
> x on the right-hand side of the assignment refers to a not-yet-assigned local
> variable x, not the PL/Python function parameter. Using the global statement,
> this can be made to work:
>
> CREATE FUNCTION pystrip(x text)
>  RETURNS text
> AS $$
>  global x
>  x = x.strip()  # ok now
>  return x
> $$ LANGUAGE plpythonu;
> But it is advisable not to rely on this implementation detail of PL/Python. It
> is better to treat the function parameters as read-only.
>
> "
>>
>> Kind regards,
>> Jeroen
>
> --
> Adrian Klaver
> adrian.klaver@gmail.com