Обсуждение: invalid regular expression: invalid backreference number
I've got a function that generates usernames and passwords on insert if
they haven't yet been set. The code block is:
-- create a new username for new people
IF (LENGTH(COALESCE(new_pp_username, '')) = 0) THEN
LOOP
gen_pp_username := LOWER(SUBSTRING(new_pp_first_name from 1 for
2)) || LOWER(SUBSTRING(new_pp_last_name from 1 for 8)) ||
round(random()*100);
gen_pp_username := regexp_replace(gen_pp_username, E'\\W', '', 'g');
EXIT WHEN ((SELECT COUNT(*) FROM people WHERE pp_username =
gen_pp_username AND pp_provisional_p='f') = 0);
END LOOP;
ELSE
gen_pp_username := new_pp_username;
END IF;
-- create a new password if there is none
IF (LENGTH(COALESCE(new_pp_password, '')) = 0) THEN
chars :=
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
FOR i in 1..8 LOOP
gen_pp_password := gen_pp_password || SUBSTRING(chars,
ceil(random()*LENGTH(chars)), 1);2007-02-15 15:32:57.264727500
END LOOP;
ELSE
gen_pp_password := new_pp_password;
END IF;
This used to work before my upgrade to 8.2.1.
The error the function now throws is:
<jross%wykids>ERROR: invalid regular expression: invalid backreference
number
2007-02-15 15:32:57.264729500 <jross%wykids>CONTEXT: SQL function
"substring" statement 1
2007-02-15 15:32:57.264730500 PL/pgSQL function "set_people" line 58
at assignment
I've futzed around with the various ways I can call substring, but I
don't understand why this is throwing the error.
Any help would be greatly appreciated!
Jeff Ross
Jeff Ross <jross@wykids.org> writes:
> This used to work before my upgrade to 8.2.1.
Which version were you using before?
> The error the function now throws is:
> <jross%wykids>ERROR: invalid regular expression: invalid backreference
> number
> 2007-02-15 15:32:57.264729500 <jross%wykids>CONTEXT: SQL function
> "substring" statement 1
> 2007-02-15 15:32:57.264730500 PL/pgSQL function "set_people" line 58
> at assignment
You could have helped us out by mentioning exactly which line was line
58 ... but I'm guessing it's this one:
> gen_pp_password := gen_pp_password || SUBSTRING(chars,
> ceil(random()*LENGTH(chars)), 1);2007-02-15 15:32:57.264727500
Since ceil() produces float8 which does not implicitly cast to int,
this call has probably never done what you thought --- AFAICS it will
cast all the arguments to text and invoke substring(text,text,text)
which treats its second argument as a SQL99 regular expression.
I doubt that it's useful to figure out exactly what changed to make
it fail more obviously than before --- I think the problem is that
you'd better cast the ceil() result to int.
[ObRant: still another example of why implicit casts to text are evil.]
regards, tom lane
Tom Lane wrote:
Thanks for the reply, Tom.
> Jeff Ross <jross@wykids.org> writes:
>
>> This used to work before my upgrade to 8.2.1.
>>
>
> Which version were you using before?
>
>
8.1.x
>> The error the function now throws is:
>>
>
>
>> <jross%wykids>ERROR: invalid regular expression: invalid backreference
>> number
>> 2007-02-15 15:32:57.264729500 <jross%wykids>CONTEXT: SQL function
>> "substring" statement 1
>> 2007-02-15 15:32:57.264730500 PL/pgSQL function "set_people" line 58
>> at assignment
>>
>
> You could have helped us out by mentioning exactly which line was line
> 58 ... but I'm guessing it's this one:
>
>
Sorry, my bad, but you guessed right.
>> gen_pp_password := gen_pp_password || SUBSTRING(chars,
>> ceil(random()*LENGTH(chars)), 1);2007-02-15 15:32:57.264727500
>>
>
> Since ceil() produces float8 which does not implicitly cast to int,
> this call has probably never done what you thought --- AFAICS it will
> cast all the arguments to text and invoke substring(text,text,text)
> which treats its second argument as a SQL99 regular expression.
> I doubt that it's useful to figure out exactly what changed to make
> it fail more obviously than before --- I think the problem is that
> you'd better cast the ceil() result to int.
>
> [ObRant: still another example of why implicit casts to text are evil.]
>
> regards, tom lane
>
>
To debug this I've extracted the code into its own function:
CREATE FUNCTION gen_password() RETURNS text AS $$
DECLARE
password text;
chars := 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
BEGIN
FOR i IN 1..9 LOOP
password := password || SUBSTRING(chars,
ceil(random()*LENGTH(chars))::int, 1);
END LOOP;
return password;
END;
$$
LANGUAGE plpgsql;
when I try to generate the function with this I get the following error:
psql -f create_password.sql wykids
psql:create_password.sql:12: LOG: statement: CREATE FUNCTION
gen_password() RETURNS text AS $$
DECLARE
password text;
chars :=
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
BEGIN
FOR i IN 1..9 LOOP
password := password || SUBSTRING(chars,
ceil(random()*LENGTH(chars))::int, 1);
END LOOP;
return password;
END;
$$
LANGUAGE plpgsql;
psql:create_password.sql:12: ERROR: invalid type name ""
CONTEXT: compile of PL/pgSQL function "gen_password" near line 3
I've not been able to figure out this error message at all, and google
hasn't been any help either. I'm only now learning functions (I
inherited the one that used to work) so if someone can point me in the
general direction I sure would appreciate it.
Thanks,
Jeff Ross
On Sun, 18 Feb 2007, Jeff Ross wrote: > Tom Lane wrote: > > > > Since ceil() produces float8 which does not implicitly cast to int, > > this call has probably never done what you thought --- AFAICS it will > > cast all the arguments to text and invoke substring(text,text,text) > > which treats its second argument as a SQL99 regular expression. > > I doubt that it's useful to figure out exactly what changed to make > > it fail more obviously than before --- I think the problem is that > > you'd better cast the ceil() result to int. > > > > [ObRant: still another example of why implicit casts to text are evil.] > > > To debug this I've extracted the code into its own function: > > > CREATE FUNCTION gen_password() RETURNS text AS $$ > DECLARE > password text; > chars := 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; > BEGIN > FOR i IN 1..9 LOOP > password := password || SUBSTRING(chars, > ceil(random()*LENGTH(chars))::int, 1); > END LOOP; > return password; > END; > $$ > LANGUAGE plpgsql; > > > when I try to generate the function with this I get the following error: > > psql -f create_password.sql wykids > psql:create_password.sql:12: LOG: statement: CREATE FUNCTION > gen_password() RETURNS text AS $$ > DECLARE > password text; > chars := [snipped] > psql:create_password.sql:12: ERROR: invalid type name "" > CONTEXT: compile of PL/pgSQL function "gen_password" near line 3 Given the context and function, I'd say it's complaining because you didn't put a type after chars and before the := for the initializer. Changing it to chars text := ... should make that work. In addition, the default initialized value for password will be a NULL which probably won't do what you want either, since NULL || something is NULL, so you probably want password text := '' there.
Jeff Ross <jross@wykids.org> writes:
> To debug this I've extracted the code into its own function:
> CREATE FUNCTION gen_password() RETURNS text AS $$
> DECLARE
> password text;
> chars := 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
> BEGIN
You forgot to give a type for the "chars" variable.
> psql:create_password.sql:12: ERROR: invalid type name ""
> CONTEXT: compile of PL/pgSQL function "gen_password" near line 3
I agree that this is a pretty awful error message :-( ... will take a
look at whether it can be improved.
regards, tom lane