Thread: COMMUTATOR doesn't seem to work

COMMUTATOR doesn't seem to work

From
D'Arcy Cain
Date:
Maybe I am using it wrong but I get no error message when I use it.  I
have a type called chkpass (a version is in the additional supplied
modules) and I create the equality operator like this:

CREATE OPERATOR = (        PROCEDURE = eq,        LEFTARG = chkpass,        RIGHTARG = text,        COMMUTATOR = =,
  NEGATOR = <>
 
);

This works;

cosmostest=# SELECT 'aaa'::chkpass = 'aaa'; ?column?
---------- t
(1 row)

But...

cosmostest=# SELECT 'aaa' = 'aaa'::chkpass;
ERROR:  operator is only a shell: text = chkpass
LINE 1: SELECT 'aaa' = 'aaa'::chkpass;

When I look at the operators I see why, sort of...
 public | =    | chkpass       | text           | boolean     | public | =    | text          | chkpass        | -
    |
 

So while it created the operator it didn't set a return type.

I don't know if this is a new issue or I simply got lucky and never
tried the opposite test before but I see this in 9.0.4 and 9.1.3.
Am I using the command improperly?

-- 
D'Arcy J.M. Cain <darcy@druid.net>         |  Democracy is three wolves
http://www.druid.net/darcy/                |  and a sheep voting on
+1 416 425 1212     (DoD#0082)    (eNTP)   |  what's for dinner.
IM: darcy@Vex.Net


Re: COMMUTATOR doesn't seem to work

From
Tom Lane
Date:
"D'Arcy Cain" <darcy@druid.net> writes:
> Maybe I am using it wrong but I get no error message when I use it.  I
> have a type called chkpass (a version is in the additional supplied
> modules) and I create the equality operator like this:

> CREATE OPERATOR = (
>          PROCEDURE = eq,
>          LEFTARG = chkpass,
>          RIGHTARG = text,
>          COMMUTATOR = =,
>          NEGATOR = <>
> );

Did you actually create a "text = chkpass" function and operator?
This declaration merely promises that you will provide one eventually.
The system does not have the ability to make one for you.
        regards, tom lane


Re: COMMUTATOR doesn't seem to work

From
Florian Pflug
Date:
On Jun21, 2012, at 17:46 , D'Arcy Cain wrote:

> Maybe I am using it wrong but I get no error message when I use it.  I
> have a type called chkpass (a version is in the additional supplied
> modules) and I create the equality operator like this:
> 
...
> 
> So while it created the operator it didn't set a return type.
> 
> I don't know if this is a new issue or I simply got lucky and never
> tried the opposite test before but I see this in 9.0.4 and 9.1.3.
> Am I using the command improperly?

COMMUTATOR (and also NEGATOR) only inform the planner/optimizer
about the relationship between operators, but you still have to create
all of them manually. What you see is the placeholder for that
to-be-created operator that CREATE OPERATOR fabricated. It does that
because if the COMMUTATOR or NEGATOR was required to already exist,
how would you ever be able to create a pair of commuting operators?

If you later use CREATE OPERATOR to actually create the COMMUTATOR
or NEGATOR you specified previously, it'll simply complete the
previously created placeholder.

Long story short, you need another CREATE OPERATOR command for the
COMMUTATOR (which argument types swapped), and it should in turn
name the original operator as it's COMMUTATOR.

best regards,
Florian Pflug





Re: COMMUTATOR doesn't seem to work

From
D'Arcy Cain
Date:
On 12-06-21 12:18 PM, Tom Lane wrote:
> Did you actually create a "text = chkpass" function and operator?
> This declaration merely promises that you will provide one eventually.
> The system does not have the ability to make one for you.

I guess I am missing the point of COMMUTATOR then.  The docs say "When
you are defining a self-commutative operator, you just do it."  It
seems you need to do more than "just do it."  As far as I can tell I
will need to add another C function and another CREATE OPERATOR.
Then I can create an operator that takes args (text, chkpass) instead
of (chkpass, text).  What is the COMMUTATOR for then?  Is it just a
hint to the planner?

-- 
D'Arcy J.M. Cain <darcy@druid.net>         |  Democracy is three wolves
http://www.druid.net/darcy/                |  and a sheep voting on
+1 416 425 1212     (DoD#0082)    (eNTP)   |  what's for dinner.
IM: darcy@Vex.Net


Re: COMMUTATOR doesn't seem to work

From
Tom Lane
Date:
"D'Arcy Cain" <darcy@druid.net> writes:
> On 12-06-21 12:18 PM, Tom Lane wrote:
>> Did you actually create a "text = chkpass" function and operator?
>> This declaration merely promises that you will provide one eventually.
>> The system does not have the ability to make one for you.

> I guess I am missing the point of COMMUTATOR then.  The docs say "When
> you are defining a self-commutative operator, you just do it."  It
> seems you need to do more than "just do it.

Um, an operator with different types on left and right cannot be its own
commutator.
        regards, tom lane


Re: COMMUTATOR doesn't seem to work

From
D'Arcy Cain
Date:
On 12-06-22 12:22 AM, Tom Lane wrote:
> Um, an operator with different types on left and right cannot be its own
> commutator.

Understood.  I completely misunderstood the purpose of COMMUTATOR.  I
thought that it was telling the system that the procedure could be
called with the arguments reversed if it could not find a specific
procedure.  I see now what it is for.

So I have my type working now but I had to create a new C function
that take the opposite argument order.  Seems redundant but I could
not see a better way.

-- 
D'Arcy J.M. Cain <darcy@druid.net>         |  Democracy is three wolves
http://www.druid.net/darcy/                |  and a sheep voting on
+1 416 425 1212     (DoD#0082)    (eNTP)   |  what's for dinner.
IM: darcy@Vex.Net


Re: COMMUTATOR doesn't seem to work

From
Florian Pflug
Date:
On Jun22, 2012, at 06:32 , D'Arcy Cain wrote:
> So I have my type working now but I had to create a new C function
> that take the opposite argument order.  Seems redundant but I could
> not see a better way.

There isn't. Postgres itself contains a huge number of such functions,
e.g. for every *lt() (less-than) there's a *gt() (greater-than).

best regards,
Florian Pflug



Re: COMMUTATOR doesn't seem to work

From
D'Arcy Cain
Date:
On 12-06-22 07:11 AM, Florian Pflug wrote:
> On Jun22, 2012, at 06:32 , D'Arcy Cain wrote:
>> So I have my type working now but I had to create a new C function
>> that take the opposite argument order.  Seems redundant but I could
>> not see a better way.
>
> There isn't. Postgres itself contains a huge number of such functions,
> e.g. for every *lt() (less-than) there's a *gt() (greater-than).

Right but that's not the same thing.  Assuming you meant lt/gte and
lte/gt those still are not self-commutating (SC).  For example, '='
on two ints is SC.  The issue here is that the operator is SC but
the args are different types.  It would be nice if there was a way
to automatically generate code that reverses arguments.  Maybe such
a thing belongs in the CREATE FUNCTION command.

Or, I guess this works and keeps from creating a second C function:

CREATE OR REPLACE FUNCTION eq(chkpass, text)    RETURNS bool    STRICT    AS 'chkpass.so', 'chkpass_eq'    LANGUAGE 'c'
  RETURNS NULL ON NULL INPUT;
 

CREATE OR REPLACE FUNCTION eq(text, chkpass)    RETURNS bool    AS 'select eq($2, $1);'    LANGUAGE SQL    RETURNS NULL
ONNULL INPUT;
 


-- 
D'Arcy J.M. Cain <darcy@druid.net>         |  Democracy is three wolves
http://www.druid.net/darcy/                |  and a sheep voting on
+1 416 425 1212     (DoD#0082)    (eNTP)   |  what's for dinner.
IM: darcy@Vex.Net


Re: COMMUTATOR doesn't seem to work

From
Tom Lane
Date:
"D'Arcy Cain" <darcy@druid.net> writes:
> ... The issue here is that the operator is SC but
> the args are different types.

Well, that's a weird way of defining self-commutating, but ...

> It would be nice if there was a way
> to automatically generate code that reverses arguments.  Maybe such
> a thing belongs in the CREATE FUNCTION command.

> Or, I guess this works and keeps from creating a second C function:

> CREATE OR REPLACE FUNCTION eq(chkpass, text)
>      RETURNS bool
>      STRICT
>      AS 'chkpass.so', 'chkpass_eq'
>      LANGUAGE 'c'
>      RETURNS NULL ON NULL INPUT;

> CREATE OR REPLACE FUNCTION eq(text, chkpass)
>      RETURNS bool
>      AS 'select eq($2, $1);'
>      LANGUAGE SQL
>      RETURNS NULL ON NULL INPUT;

The thing is that either of those approaches is hugely more expensive
than just providing a second C function.  It costs probably thousands
of cycles to inline that SQL function, each time it's used in a query.
I doubt that an "auto reverse the arguments" facility would be very
much cheaper.  You could maybe argue that the aggregated maintenance
and space costs of all the commutator-pair functions are enough to
justify having some such solution instead, but I'm doubtful --- and
even if true, getting from here to there would be painful.
        regards, tom lane


Re: COMMUTATOR doesn't seem to work

From
D'Arcy Cain
Date:
On 12-06-22 11:36 AM, Tom Lane wrote:
> "D'Arcy Cain"<darcy@druid.net>  writes:
> The thing is that either of those approaches is hugely more expensive
> than just providing a second C function.  It costs probably thousands
> of cycles to inline that SQL function, each time it's used in a query.

I assumed itwould be more expensive but didn't know it would be that
much more.

> I doubt that an "auto reverse the arguments" facility would be very
> much cheaper.  You could maybe argue that the aggregated maintenance
> and space costs of all the commutator-pair functions are enough to
> justify having some such solution instead, but I'm doubtful --- and
> even if true, getting from here to there would be painful.

And it would only apply to a very specific type of function.

The other idea I had was to just have the second C function call the
first but that didn't work.  Here is what I tried.

PG_FUNCTION_INFO_V1(chkpass_eq);
Datum
chkpass_eq(PG_FUNCTION_ARGS)
{    chkpass    *a1 = (chkpass *) PG_GETARG_POINTER(0);    text       *a2 = (text *) PG_GETARG_TEXT_P(1);    char
str[9];
 
    strlcpy(str, a2->vl_dat, sizeof(str));    PG_RETURN_BOOL(strcmp(a1->password, crypt(str, a1->password)) == 0);
}

PG_FUNCTION_INFO_V1(chkpass_eq2);
Datum
chkpass_eq2(PG_FUNCTION_ARGS)
{    return chkpass_eq(PG_GETARG_POINTER(1), PG_GETARG_TEXT_P(0));
}

Now in this specific case the function is trivial and writing it twice
is no big deal but in general I hate writing the same code twice.  I
suppose I could extract the actual operation out to a third function
and call it from the others.  I may do that anyway just for the value
of the example.  Or is there a way to do what I tried above?

-- 
D'Arcy J.M. Cain <darcy@druid.net>         |  Democracy is three wolves
http://www.druid.net/darcy/                |  and a sheep voting on
+1 416 425 1212     (DoD#0082)    (eNTP)   |  what's for dinner.
IM: darcy@Vex.Net


Re: COMMUTATOR doesn't seem to work

From
Robert Haas
Date:
On Fri, Jun 22, 2012 at 12:28 PM, D'Arcy Cain <darcy@druid.net> wrote:
>> I doubt that an "auto reverse the arguments" facility would be very
>> much cheaper.  You could maybe argue that the aggregated maintenance
>> and space costs of all the commutator-pair functions are enough to
>> justify having some such solution instead, but I'm doubtful --- and
>> even if true, getting from here to there would be painful.
>
>
> And it would only apply to a very specific type of function.
>
> The other idea I had was to just have the second C function call the
> first but that didn't work.  Here is what I tried.
>
> PG_FUNCTION_INFO_V1(chkpass_eq);
> Datum
> chkpass_eq(PG_FUNCTION_ARGS)
> {
>    chkpass    *a1 = (chkpass *) PG_GETARG_POINTER(0);
>    text       *a2 = (text *) PG_GETARG_TEXT_P(1);
>    char        str[9];
>
>    strlcpy(str, a2->vl_dat, sizeof(str));
>    PG_RETURN_BOOL(strcmp(a1->password, crypt(str, a1->password)) == 0);
> }
>
> PG_FUNCTION_INFO_V1(chkpass_eq2);
> Datum
> chkpass_eq2(PG_FUNCTION_ARGS)
> {
>    return chkpass_eq(PG_GETARG_POINTER(1), PG_GETARG_TEXT_P(0));
> }
>
> Now in this specific case the function is trivial and writing it twice
> is no big deal but in general I hate writing the same code twice.  I
> suppose I could extract the actual operation out to a third function
> and call it from the others.  I may do that anyway just for the value
> of the example.  Or is there a way to do what I tried above?

I think DirectionFunctionCall2 is what you want.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company


Re: COMMUTATOR doesn't seem to work

From
D'Arcy Cain
Date:
On 12-06-22 07:09 PM, Robert Haas wrote:
> I think DirectionFunctionCall2 is what you want.

Can you elaborate?  I could not find a single hit in Google or the
documentation search on the PG site and it does not appear anywhere
in the source distribution.

-- 
D'Arcy J.M. Cain <darcy@druid.net>         |  Democracy is three wolves
http://www.druid.net/darcy/                |  and a sheep voting on
+1 416 425 1212     (DoD#0082)    (eNTP)   |  what's for dinner.
IM: darcy@Vex.Net




Re: COMMUTATOR doesn't seem to work

From
Tom Lane
Date:
"D'Arcy Cain" <darcy@druid.net> writes:
> On 12-06-22 07:09 PM, Robert Haas wrote:
>> I think DirectionFunctionCall2 is what you want.

> Can you elaborate?  I could not find a single hit in Google or the
> documentation search on the PG site and it does not appear anywhere
> in the source distribution.

He meant DirectFunctionCall2
        regards, tom lane


Re: COMMUTATOR doesn't seem to work

From
D'Arcy Cain
Date:
On 12-06-23 12:17 AM, Tom Lane wrote:
> "D'Arcy Cain" <darcy@druid.net> writes:
>> On 12-06-22 07:09 PM, Robert Haas wrote:
>>> I think DirectionFunctionCall2 is what you want.
>
>> Can you elaborate?  I could not find a single hit in Google or the
>> documentation search on the PG site and it does not appear anywhere
>> in the source distribution.
>
> He meant DirectFunctionCall2

Still nothing in the documentation.  At least the search box doesn't
find it.

-- 
D'Arcy J.M. Cain <darcy@druid.net>         |  Democracy is three wolves
http://www.druid.net/darcy/                |  and a sheep voting on
+1 416 425 1212     (DoD#0082)    (eNTP)   |  what's for dinner.
IM: darcy@Vex.Net




Re: COMMUTATOR doesn't seem to work

From
"Dickson S. Guedes"
Date:
2012/6/23 D'Arcy Cain <darcy@druid.net>:
> On 12-06-23 12:17 AM, Tom Lane wrote:
>>
>> "D'Arcy Cain" <darcy@druid.net> writes:
>>>
>>> On 12-06-22 07:09 PM, Robert Haas wrote:
>>>>
>>>> I think DirectionFunctionCall2 is what you want.
>>
>>
>>> Can you elaborate?  I could not find a single hit in Google or the
>>> documentation search on the PG site and it does not appear anywhere
>>> in the source distribution.
>>
>>
>> He meant DirectFunctionCall2
>
>
> Still nothing in the documentation.  At least the search box doesn't
> find it.

Try in the search box of postgres doxygen documentation [1]..


[1] http://doxygen.postgresql.org/

[]s
--
Dickson S. Guedes
mail/xmpp: guedes@guedesoft.net - skype: guediz
http://guedesoft.net - http://www.postgresql.org.br


Re: COMMUTATOR doesn't seem to work

From
D'Arcy Cain
Date:
On 12-06-23 08:21 AM, Dickson S. Guedes wrote:
>> Still nothing in the documentation.  At least the search box doesn't
>> find it.
>
> Try in the search box of postgres doxygen documentation [1]..

That's source, not documentation.  I already found it in the actual
source files but that's not the same thing.  For one thing, if it
isn't documented then it may not be meant to be exposed to the API.
For another, without documentation we can't tell what is guaranteed
to work and what is an implementation detail.

I know that I can fiddle about and try stuff until it works but I
don't work for Microsoft.

-- 
D'Arcy J.M. Cain <darcy@druid.net>         |  Democracy is three wolves
http://www.druid.net/darcy/                |  and a sheep voting on
+1 416 425 1212     (DoD#0082)    (eNTP)   |  what's for dinner.
IM: darcy@Vex.Net




Re: COMMUTATOR doesn't seem to work

From
Tom Lane
Date:
"D'Arcy Cain" <darcy@druid.net> writes:
> On 12-06-23 08:21 AM, Dickson S. Guedes wrote:
>> Try in the search box of postgres doxygen documentation [1]..

> That's source, not documentation.  I already found it in the actual
> source files but that's not the same thing.  For one thing, if it
> isn't documented then it may not be meant to be exposed to the API.
> For another, without documentation we can't tell what is guaranteed
> to work and what is an implementation detail.

By and large, most of what you need to know to write C code for PG
is not in the SGML documentation.  I haven't seen any volunteers
stepping up to write another thousand or two pages of formal docs,
so that's how it's going to be for the foreseeable future.  You need
to be prepared to read the source code and especially to look at
existing examples such as the contrib modules.

As far as the "not guaranteed to work" angle is concerned, it's true,
we could decide to change that.  It's not very likely though: we do
try to avoid breaking things that we expect are in use by third-party
code, and anything that is in use by half a dozen contrib modules
certainly qualifies.  If you're thinking of doing something that you
don't see lots of precedents for in contrib or the core datatypes,
it would be reasonable to ask about it on -hackers first.
        regards, tom lane