Thread: pg_operator.oprcode in 9.2rc1

pg_operator.oprcode in 9.2rc1

From
Joe Abbate
Date:
Hello hackers,

I've been testing Pyrseas against 9.2rc1.  A test that does a CREATE
OPERATOR is giving a small difference.  Specifically, the test issues
the statement:

CREATE OPERATOR + (PROCEDURE = upper, RIGHTARG = text);

Pyrseas then queries the pg_operator catalog to map the procedure for
output.  Selecting oprcode in 8.4, 9.0, and 9.1, always returns 'upper',
but in 9.2rc1, the value is 'pg_catalog.upper'.  It does not matter
whether pg_catalog is on the search_path or not.

I looked over the release notes but I couldn't find any reference to
this possible change in behavior.  I'd like to confirm whether the
schema-qualified procedure name is a permanent change or an unintended
side effect of something else.

Thanks.

Joe



Re: pg_operator.oprcode in 9.2rc1

From
Tom Lane
Date:
Joe Abbate <jma@freedomcircle.com> writes:
> Hello hackers,
> I've been testing Pyrseas against 9.2rc1.  A test that does a CREATE
> OPERATOR is giving a small difference.  Specifically, the test issues
> the statement:

> CREATE OPERATOR + (PROCEDURE = upper, RIGHTARG = text);

> Pyrseas then queries the pg_operator catalog to map the procedure for
> output.  Selecting oprcode in 8.4, 9.0, and 9.1, always returns 'upper',
> but in 9.2rc1, the value is 'pg_catalog.upper'.  It does not matter
> whether pg_catalog is on the search_path or not.

The reason for the difference is that in 9.2 there's more than one
pg_catalog.upper():

regression=# \df upper                         List of functions  Schema   | Name  | Result data type | Argument data
types|  Type  
 
------------+-------+------------------+---------------------+--------pg_catalog | upper | anyelement       | anyrange
         | normalpg_catalog | upper | text             | text                | normal
 
(2 rows)

whereas prior versions had only upper(text).  The regproc output
function isn't allowed to print argument types, which is what would be
needed to disambiguate altogether, but it does what it can to warn you
that "upper" alone is not a unique name by schema-qualifying the name.

This is not new behavior in 9.2, it just happens to occur for upper()
when it did not before.  If you're expecting regproc to always return
unique unqualified names then your code is broken anyway, since such
a requirement cannot be met when the function is overloaded.
        regards, tom lane



Re: pg_operator.oprcode in 9.2rc1

From
Joe Abbate
Date:
Hello Tom,

On 30/08/12 12:27, Tom Lane wrote:
> The reason for the difference is that in 9.2 there's more than one
> pg_catalog.upper():
> 
> regression=# \df upper
>                           List of functions
>    Schema   | Name  | Result data type | Argument data types |  Type  
> ------------+-------+------------------+---------------------+--------
>  pg_catalog | upper | anyelement       | anyrange            | normal
>  pg_catalog | upper | text             | text                | normal
> (2 rows)
> 
> whereas prior versions had only upper(text).  The regproc output
> function isn't allowed to print argument types, which is what would be
> needed to disambiguate altogether, but it does what it can to warn you
> that "upper" alone is not a unique name by schema-qualifying the name.
> 
> This is not new behavior in 9.2, it just happens to occur for upper()
> when it did not before.  If you're expecting regproc to always return
> unique unqualified names then your code is broken anyway, since such
> a requirement cannot be met when the function is overloaded.

Hmmm ... Well, I'm just doing the same thing as pg_dump, which in 9.2rc1
still outputs the same as before, namely:

SET search_path = public, pg_catalog;

--
-- Name: +; Type: OPERATOR; Schema: public; Owner: -
--

CREATE OPERATOR + (   PROCEDURE = upper,   RIGHTARG = text
);

What's somewhat confusing is that the documentation (and \d pg_operator)
states oprcode (as well as oprrest and oprjoin) are of type 'regproc'
and that it references a pg_proc.oid.  Does the catalog actually store
an OID, i.e., the OID of pg_catalog.upper(text), or something else?

Best regards,

Joe



Re: pg_operator.oprcode in 9.2rc1

From
Tom Lane
Date:
Joe Abbate <jma@freedomcircle.com> writes:
> On 30/08/12 12:27, Tom Lane wrote:
>> The reason for the difference is that in 9.2 there's more than one
>> pg_catalog.upper():

> Hmmm ... Well, I'm just doing the same thing as pg_dump, which in 9.2rc1
> still outputs the same as before, namely:

Well, evidently you're *not* doing the same thing as pg_dump.

A look at pg_dump says that what it does is to cast the column to
regprocedure, and then strip the argument types from that printout.

Perhaps some experimentation would be illuminating:

regression=# select 'upper'::regproc;
ERROR:  more than one function named "upper"
LINE 1: select 'upper'::regproc;              ^
regression=# select 'upper(text)'::regprocedure;regprocedure 
--------------upper(text)
(1 row)

regression=# select 'upper(text)'::regprocedure::oid;oid 
-----871
(1 row)

regression=# select 871::regprocedure;regprocedure 
--------------upper(text)
(1 row)

regression=# select 871::regproc;         regproc      
------------------pg_catalog.upper
(1 row)

> What's somewhat confusing is that the documentation (and \d pg_operator)
> states oprcode (as well as oprrest and oprjoin) are of type 'regproc'
> and that it references a pg_proc.oid.  Does the catalog actually store
> an OID, i.e., the OID of pg_catalog.upper(text), or something else?

What's physically in there is an OID (and so the casts above are no-ops
at the representational level).  What we're discussing is the behavior
of the output function for the regproc or regprocedure types.
        regards, tom lane



Re: pg_operator.oprcode in 9.2rc1

From
Joe Abbate
Date:
Hello Tom,

On 30/08/12 13:23, Tom Lane wrote:
> Joe Abbate <jma@freedomcircle.com> writes:
>> Hmmm ... Well, I'm just doing the same thing as pg_dump, which in 9.2rc1
>> still outputs the same as before, namely:
> 
> Well, evidently you're *not* doing the same thing as pg_dump.

I meant that the Pyrseas dbtoyaml's output is essentially the same as
pg_dump, e.g.,

schema public: operator +(NONE, text):   procedure: upper

Therefore, if psql doesn't have problem restoring the operator from the
pg_dump output, neither should yamltodb have problem generating the SQL
to recreate the operator.  The above YAML (with or without the schema
qualification) does generate the correct SQL and pg_operator.oprcode
ends up with the correct OID.  So at least for this test case,
dbtoyam/yamltodb is not broken (but I'll have to do something about the
unittest difference).

> What's physically in there is an OID (and so the casts above are no-ops
> at the representational level).  What we're discussing is the behavior
> of the output function for the regproc or regprocedure types.

Yes, I suspected that an OID was stored.  What I'd still quibble with is
the use of the ambiguous regproc in pg_operator (also pg_type) and the
still-ambiguous schema-qualified proc name.  I guess it's not feasible
(at least, short term), but it'd be preferable to store a "raw" OID and
let the user cast to regprocedure (or change the 'regproc' to
'regprocedure').

Best regards,

Joe



Re: pg_operator.oprcode in 9.2rc1

From
Tom Lane
Date:
Joe Abbate <jma@freedomcircle.com> writes:
> Yes, I suspected that an OID was stored.  What I'd still quibble with is
> the use of the ambiguous regproc in pg_operator (also pg_type) and the
> still-ambiguous schema-qualified proc name.  I guess it's not feasible
> (at least, short term), but it'd be preferable to store a "raw" OID and
> let the user cast to regprocedure (or change the 'regproc' to
> 'regprocedure').

Yeah, ideally those columns would be regprocedure.  There are
bootstrapping problems involved though with populating the initial
contents of the catalogs during initdb --- the regprocedure input
function doesn't work in that environment.  (It might be possible to
hack something for pg_operator, but the circularity is rather
fundamental for loading pg_type, since the input function would need to
consult pg_type to make sense of argument types.)

In the meantime I'd suggest casting the columns to regprocedure when
querying, if you want unambiguous results.  That's what pg_dump does.
Or you can cast to OID if you like numbers.
        regards, tom lane