binary operators on integers

Started by Marko Kreenover 25 years ago11 messages
#1Marko Kreen
marko@l-t.ee
1 attachment(s)

Here is my next take on binary operators for integers.
It implements the following operators for int2/int4/int8:

~ - not
& - and
^ - xor
| - or
<< - shift left

- shift right

Notes:

* My original choice for xor was '#' because the '^' operator conflicts
with power operator on floats but Tom Lane said:

Well, you *could* use '^' since there's no definition of it for integer
operands. But that would mean that something like '4^2', which was
formerly implicitly coerced to float and interpreted as floating
power function, would suddenly mean something different. Again a
serious risk of silently breaking applications. This doesn't apply to
'|' though, since it has no numeric interpretation at all right now.

As the bit-string uses '^' too for xor-ing it would be nice to be
consistent. I am quite unsure on this matter. The patch now seems
otherwise sane to me, this is the only issue left.

* On << and >> the second argument is always int32 as this seems
to be the 'default' int type in PostgreSQL.

* Oids used are 1874 - 1909.

Comments?

Patch is against current CVS.

--
marko

Attachments:

binops2.difftext/plain; charset=us-asciiDownload
Index: doc/src/sgml/oper.sgml
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/doc/src/sgml/oper.sgml,v
retrieving revision 1.18
diff -u -r1.18 oper.sgml
--- doc/src/sgml/oper.sgml	2000/09/15 20:20:11	1.18
+++ doc/src/sgml/oper.sgml	2000/09/25 07:01:04
@@ -493,9 +493,46 @@
 	<ENTRY>Cube root</ENTRY>
 	<ENTRY>||/ 27.0</ENTRY>
        </ROW>
+       <ROW>
+	<ENTRY> & </ENTRY>
+	<ENTRY>Binary AND</ENTRY>
+	<ENTRY>91 & 15</ENTRY>
+       </ROW>
+       <ROW>
+	<ENTRY> | </ENTRY>
+	<ENTRY>Binary OR</ENTRY>
+	<ENTRY>32 | 3</ENTRY>
+       </ROW>
+       <ROW>
+	<ENTRY> ^ </ENTRY>
+	<ENTRY>Binary XOR</ENTRY>
+	<ENTRY>15 ^ 4</ENTRY>
+       </ROW>
+       <ROW>
+	<ENTRY> ~ </ENTRY>
+	<ENTRY>Binary NOT</ENTRY>
+	<ENTRY>~1</ENTRY>
+       </ROW>
+       <ROW>
+	<ENTRY> &lt;&lt; </ENTRY>
+	<ENTRY>Binary shift left</ENTRY>
+	<ENTRY>1 &lt;&lt; 4</ENTRY>
+       </ROW>
+       <ROW>
+	<ENTRY> &gt;&gt; </ENTRY>
+	<ENTRY>Binary shift right</ENTRY>
+	<ENTRY>8 &gt;&gt; 2</ENTRY>
+       </ROW>
       </TBODY>
      </TGROUP>
     </TABLE>
+    <Note>
+     <Para>
+     The binary operators work only on fixed-precision integer types,
+     that is, on the int2, int4 and int8.  Also note that '^' means XOR
+     on integer types and power on non-integer types.
+     </Para>
+    </Note>
    </Para>
   </sect1>
 
Index: src/backend/utils/adt/int.c
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/backend/utils/adt/int.c,v
retrieving revision 1.42
diff -u -r1.42 int.c
--- src/backend/utils/adt/int.c	2000/08/01 18:29:35	1.42
+++ src/backend/utils/adt/int.c	2000/09/25 07:01:05
@@ -843,3 +843,121 @@
 
 	PG_RETURN_INT32((arg1 < arg2) ? arg1 : arg2);
 }
+
+/* Binary arithmetics
+ *
+ *		int[24]and		- returns arg1 & arg2
+ *		int[24]or		- returns arg1 | arg2
+ *		int[24]xor		- returns arg1 ^ arg2
+ *		int[24]not		- returns ~arg1
+ *		int[24]shl		- returns arg1 << arg2
+ *		int[24]shr		- returns arg1 >> arg2
+ */
+
+Datum
+int4and(PG_FUNCTION_ARGS)
+{
+	int32		arg1 = PG_GETARG_INT32(0);
+	int32		arg2 = PG_GETARG_INT32(1);
+
+	PG_RETURN_INT32(arg1 & arg2);
+}
+
+Datum
+int4or(PG_FUNCTION_ARGS)
+{
+	int32		arg1 = PG_GETARG_INT32(0);
+	int32		arg2 = PG_GETARG_INT32(1);
+
+	PG_RETURN_INT32(arg1 | arg2);
+}
+
+Datum
+int4xor(PG_FUNCTION_ARGS)
+{
+	int32		arg1 = PG_GETARG_INT32(0);
+	int32		arg2 = PG_GETARG_INT32(1);
+
+	PG_RETURN_INT32(arg1 ^ arg2);
+}
+
+Datum
+int4shl(PG_FUNCTION_ARGS)
+{
+	int32		arg1 = PG_GETARG_INT32(0);
+	int32		arg2 = PG_GETARG_INT32(1);
+
+	PG_RETURN_INT32(arg1 << arg2);
+}
+
+Datum
+int4shr(PG_FUNCTION_ARGS)
+{
+	int32		arg1 = PG_GETARG_INT32(0);
+	int32		arg2 = PG_GETARG_INT32(1);
+
+	PG_RETURN_INT32(arg1 >> arg2);
+}
+
+Datum
+int4not(PG_FUNCTION_ARGS)
+{
+	int32		arg1 = PG_GETARG_INT32(0);
+
+	PG_RETURN_INT32(~arg1);
+}
+
+Datum
+int2and(PG_FUNCTION_ARGS)
+{
+	int16		arg1 = PG_GETARG_INT16(0);
+	int16		arg2 = PG_GETARG_INT16(1);
+
+	PG_RETURN_INT16(arg1 & arg2);
+}
+
+Datum
+int2or(PG_FUNCTION_ARGS)
+{
+	int16		arg1 = PG_GETARG_INT16(0);
+	int16		arg2 = PG_GETARG_INT16(1);
+
+	PG_RETURN_INT16(arg1 | arg2);
+}
+
+Datum
+int2xor(PG_FUNCTION_ARGS)
+{
+	int16		arg1 = PG_GETARG_INT16(0);
+	int16		arg2 = PG_GETARG_INT16(1);
+
+	PG_RETURN_INT16(arg1 ^ arg2);
+}
+
+Datum
+int2not(PG_FUNCTION_ARGS)
+{
+	int16		arg1 = PG_GETARG_INT16(0);
+
+	PG_RETURN_INT16(~arg1);
+}
+
+
+Datum
+int2shl(PG_FUNCTION_ARGS)
+{
+	int16		arg1 = PG_GETARG_INT16(0);
+	int32		arg2 = PG_GETARG_INT32(1);
+
+	PG_RETURN_INT16(arg1 << arg2);
+}
+
+Datum
+int2shr(PG_FUNCTION_ARGS)
+{
+	int16		arg1 = PG_GETARG_INT16(0);
+	int32		arg2 = PG_GETARG_INT32(1);
+
+	PG_RETURN_INT16(arg1 >> arg2);
+}
+
Index: src/backend/utils/adt/int8.c
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/backend/utils/adt/int8.c,v
retrieving revision 1.24
diff -u -r1.24 int8.c
--- src/backend/utils/adt/int8.c	2000/07/28 05:07:41	1.24
+++ src/backend/utils/adt/int8.c	2000/09/25 07:01:06
@@ -591,6 +591,68 @@
 	PG_RETURN_INT64(val1 / val2);
 }
 
+/* Binary arithmetics
+ *
+ *		int8and		- returns arg1 & arg2
+ *		int8or		- returns arg1 | arg2
+ *		int8xor		- returns arg1 ^ arg2
+ *		int8not		- returns ~arg1
+ *		int8shl		- returns arg1 << arg2
+ *		int8shr		- returns arg1 >> arg2
+ */
+
+Datum
+int8and(PG_FUNCTION_ARGS)
+{
+	int64		arg1 = PG_GETARG_INT64(0);
+	int64		arg2 = PG_GETARG_INT64(1);
+
+	PG_RETURN_INT64(arg1 & arg2);
+}
+
+Datum
+int8or(PG_FUNCTION_ARGS)
+{
+	int64		arg1 = PG_GETARG_INT64(0);
+	int64		arg2 = PG_GETARG_INT64(1);
+
+	PG_RETURN_INT64(arg1 | arg2);
+}
+
+Datum
+int8xor(PG_FUNCTION_ARGS)
+{
+	int64		arg1 = PG_GETARG_INT64(0);
+	int64		arg2 = PG_GETARG_INT64(1);
+
+	PG_RETURN_INT64(arg1 ^ arg2);
+}
+
+Datum
+int8not(PG_FUNCTION_ARGS)
+{
+	int64		arg1 = PG_GETARG_INT64(0);
+
+	PG_RETURN_INT64(~arg1);
+}
+
+Datum
+int8shl(PG_FUNCTION_ARGS)
+{
+	int64		arg1 = PG_GETARG_INT64(0);
+	int32		arg2 = PG_GETARG_INT32(1);
+
+	PG_RETURN_INT64(arg1 << arg2);
+}
+
+Datum
+int8shr(PG_FUNCTION_ARGS)
+{
+	int64		arg1 = PG_GETARG_INT64(0);
+	int32		arg2 = PG_GETARG_INT32(1);
+
+	PG_RETURN_INT64(arg1 >> arg2);
+}
 
 /*----------------------------------------------------------
  *	Conversion operators.
Index: src/include/catalog/pg_operator.h
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/include/catalog/pg_operator.h,v
retrieving revision 1.82
diff -u -r1.82 pg_operator.h
--- src/include/catalog/pg_operator.h	2000/09/15 18:45:27	1.82
+++ src/include/catalog/pg_operator.h	2000/09/25 07:01:10
@@ -754,6 +754,27 @@
 DATA(insert OID = 1872 ( "<="	   PGUID 0 b t f  20  21  16  1867 1871   0  0 int82le scalarltsel scalarltjoinsel ));
 DATA(insert OID = 1873 ( ">="	   PGUID 0 b t f  20  21  16  1866 1870   0  0 int82ge scalargtsel scalargtjoinsel ));
 
+DATA(insert OID = 1874 ( "&"	   PGUID 0 b t f  21  21  21 1874   0   0   0 int2and - - ));
+DATA(insert OID = 1875 ( "|"	   PGUID 0 b t f  21  21  21 1875   0   0   0 int2or - - ));
+DATA(insert OID = 1876 ( "^"	   PGUID 0 b t f  21  21  21 1876   0   0   0 int2xor - - ));
+DATA(insert OID = 1877 ( "~"	   PGUID 0 l t f   0  21  21    0   0   0   0 int2not - - ));
+DATA(insert OID = 1878 ( "<<"	   PGUID 0 b t f  21  23  21    0   0   0   0 int2shl - - ));
+DATA(insert OID = 1879 ( ">>"	   PGUID 0 b t f  21  23  21    0   0   0   0 int2shr - - ));
+
+DATA(insert OID = 1880 ( "&"	   PGUID 0 b t f  23  23  23 1880   0   0   0 int4and - - ));
+DATA(insert OID = 1881 ( "|"	   PGUID 0 b t f  23  23  23 1881   0   0   0 int4or - - ));
+DATA(insert OID = 1882 ( "^"	   PGUID 0 b t f  23  23  23 1882   0   0   0 int4xor - - ));
+DATA(insert OID = 1883 ( "~"	   PGUID 0 l t f   0  23  23    0   0   0   0 int4not - - ));
+DATA(insert OID = 1884 ( "<<"	   PGUID 0 b t f  23  23  23    0   0   0   0 int4shl - - ));
+DATA(insert OID = 1885 ( ">>"	   PGUID 0 b t f  23  23  23    0   0   0   0 int4shr - - ));
+
+DATA(insert OID = 1886 ( "&"	   PGUID 0 b t f  20  20  20 1886   0   0   0 int8and - - ));
+DATA(insert OID = 1887 ( "|"	   PGUID 0 b t f  20  20  20 1887   0   0   0 int8or - - ));
+DATA(insert OID = 1888 ( "^"	   PGUID 0 b t f  20  20  20 1888   0   0   0 int8xor - - ));
+DATA(insert OID = 1889 ( "~"	   PGUID 0 l t f   0  20  20    0   0   0   0 int8not - - ));
+DATA(insert OID = 1890 ( "<<"	   PGUID 0 b t f  20  23  20    0   0   0   0 int8shl - - ));
+DATA(insert OID = 1891 ( ">>"	   PGUID 0 b t f  20  23  20    0   0   0   0 int8shr - - ));
+
 /*
  * function prototypes
  */
Index: src/include/catalog/pg_proc.h
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/include/catalog/pg_proc.h,v
retrieving revision 1.167
diff -u -r1.167 pg_proc.h
--- src/include/catalog/pg_proc.h	2000/09/19 18:18:01	1.167
+++ src/include/catalog/pg_proc.h	2000/09/25 07:01:17
@@ -2511,6 +2511,44 @@
 DATA(insert OID = 1861 (  int82ge		   PGUID 12 f t t t 2 f 16 "20 21" 100 0 0 100  int82ge - ));
 DESCR("greater-than-or-equal");
 
+DATA(insert OID = 1892 (  int2and		   PGUID 12 f t t t 2 f 21 "21 21" 100 0 0 100  int2and - ));
+DESCR("binary and");
+DATA(insert OID = 1893 (  int2or		   PGUID 12 f t t t 2 f 21 "21 21" 100 0 0 100  int2or - ));
+DESCR("binary or");
+DATA(insert OID = 1894 (  int2xor		   PGUID 12 f t t t 2 f 21 "21 21" 100 0 0 100  int2xor - ));
+DESCR("binary xor");
+DATA(insert OID = 1895 (  int2not		   PGUID 12 f t t t 1 f 21 "21" 100 0 0 100  int2not - ));
+DESCR("binary not");
+DATA(insert OID = 1896 (  int2shl		   PGUID 12 f t t t 2 f 21 "21 23" 100 0 0 100  int2shl - ));
+DESCR("binary shift left");
+DATA(insert OID = 1897 (  int2shr		   PGUID 12 f t t t 2 f 21 "21 23" 100 0 0 100  int2shr - ));
+DESCR("binary shift right");
+
+DATA(insert OID = 1898 (  int4and		   PGUID 12 f t t t 2 f 23 "23 23" 100 0 0 100  int4and - ));
+DESCR("binary and");
+DATA(insert OID = 1899 (  int4or		   PGUID 12 f t t t 2 f 23 "23 23" 100 0 0 100  int4or - ));
+DESCR("binary or");
+DATA(insert OID = 1900 (  int4xor		   PGUID 12 f t t t 2 f 23 "23 23" 100 0 0 100  int4xor - ));
+DESCR("binary xor");
+DATA(insert OID = 1901 (  int4not		   PGUID 12 f t t t 1 f 23 "23" 100 0 0 100  int4not - ));
+DESCR("binary not");
+DATA(insert OID = 1902 (  int4shl		   PGUID 12 f t t t 2 f 23 "23 23" 100 0 0 100  int4shl - ));
+DESCR("binary shift left");
+DATA(insert OID = 1903 (  int4shr		   PGUID 12 f t t t 2 f 23 "23 23" 100 0 0 100  int4shr - ));
+DESCR("binary shift right");
+
+DATA(insert OID = 1904 (  int8and		   PGUID 12 f t t t 2 f 20 "20 20" 100 0 0 100  int8and - ));
+DESCR("binary and");
+DATA(insert OID = 1905 (  int8or		   PGUID 12 f t t t 2 f 20 "20 20" 100 0 0 100  int8or - ));
+DESCR("binary or");
+DATA(insert OID = 1906 (  int8xor		   PGUID 12 f t t t 2 f 20 "20 20" 100 0 0 100  int8xor - ));
+DESCR("binary xor");
+DATA(insert OID = 1907 (  int8not		   PGUID 12 f t t t 1 f 20 "20" 100 0 0 100  int8not - ));
+DESCR("binary not");
+DATA(insert OID = 1908 (  int8shl		   PGUID 12 f t t t 2 f 20 "20 23" 100 0 0 100  int8shl - ));
+DESCR("binary shift left");
+DATA(insert OID = 1909 (  int8shr		   PGUID 12 f t t t 2 f 20 "20 23" 100 0 0 100  int8shr - ));
+DESCR("binary shift right");
 
 /*
  * prototypes for functions pg_proc.c
Index: src/include/utils/builtins.h
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/include/utils/builtins.h,v
retrieving revision 1.138
diff -u -r1.138 builtins.h
--- src/include/utils/builtins.h	2000/09/19 18:18:02	1.138
+++ src/include/utils/builtins.h	2000/09/25 07:01:19
@@ -127,6 +127,19 @@
 extern Datum int4larger(PG_FUNCTION_ARGS);
 extern Datum int4smaller(PG_FUNCTION_ARGS);
 
+extern Datum int4and(PG_FUNCTION_ARGS);
+extern Datum int4or(PG_FUNCTION_ARGS);
+extern Datum int4xor(PG_FUNCTION_ARGS);
+extern Datum int4not(PG_FUNCTION_ARGS);
+extern Datum int4shl(PG_FUNCTION_ARGS);
+extern Datum int4shr(PG_FUNCTION_ARGS);
+extern Datum int2and(PG_FUNCTION_ARGS);
+extern Datum int2or(PG_FUNCTION_ARGS);
+extern Datum int2xor(PG_FUNCTION_ARGS);
+extern Datum int2not(PG_FUNCTION_ARGS);
+extern Datum int2shl(PG_FUNCTION_ARGS);
+extern Datum int2shr(PG_FUNCTION_ARGS);
+
 /* name.c */
 extern Datum namein(PG_FUNCTION_ARGS);
 extern Datum nameout(PG_FUNCTION_ARGS);
Index: src/include/utils/int8.h
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/include/utils/int8.h,v
retrieving revision 1.23
diff -u -r1.23 int8.h
--- src/include/utils/int8.h	2000/07/28 05:07:44	1.23
+++ src/include/utils/int8.h	2000/09/25 07:01:19
@@ -76,6 +76,13 @@
 extern Datum int8larger(PG_FUNCTION_ARGS);
 extern Datum int8smaller(PG_FUNCTION_ARGS);
 
+extern Datum int8and(PG_FUNCTION_ARGS);
+extern Datum int8or(PG_FUNCTION_ARGS);
+extern Datum int8xor(PG_FUNCTION_ARGS);
+extern Datum int8not(PG_FUNCTION_ARGS);
+extern Datum int8shl(PG_FUNCTION_ARGS);
+extern Datum int8shr(PG_FUNCTION_ARGS);
+
 extern Datum int84pl(PG_FUNCTION_ARGS);
 extern Datum int84mi(PG_FUNCTION_ARGS);
 extern Datum int84mul(PG_FUNCTION_ARGS);
#2Bruce Momjian
pgman@candle.pha.pa.us
In reply to: Marko Kreen (#1)
Re: binary operators on integers

Can someone comment on this?

Here is my next take on binary operators for integers.
It implements the following operators for int2/int4/int8:

~ - not
& - and
^ - xor
| - or
<< - shift left

- shift right

Notes:

* My original choice for xor was '#' because the '^' operator conflicts
with power operator on floats but Tom Lane said:

Well, you *could* use '^' since there's no definition of it for integer
operands. But that would mean that something like '4^2', which was
formerly implicitly coerced to float and interpreted as floating
power function, would suddenly mean something different. Again a
serious risk of silently breaking applications. This doesn't apply to
'|' though, since it has no numeric interpretation at all right now.

As the bit-string uses '^' too for xor-ing it would be nice to be
consistent. I am quite unsure on this matter. The patch now seems
otherwise sane to me, this is the only issue left.

* On << and >> the second argument is always int32 as this seems
to be the 'default' int type in PostgreSQL.

* Oids used are 1874 - 1909.

Comments?

Patch is against current CVS.

--
marko

[ Attachment, skipping... ]

-- 
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026
#3Tom Lane
tgl@sss.pgh.pa.us
In reply to: Bruce Momjian (#2)
Re: binary operators on integers

Bruce Momjian <pgman@candle.pha.pa.us> writes:

Can someone comment on this?

We were debating what to do about the precedence issues; see
followup messages. I have no problem with adding functions
like this, just gotta pick the operator names and precedences...

regards, tom lane

#4Peter Eisentraut
peter_e@gmx.net
In reply to: Marko Kreen (#1)
Re: binary operators on integers

This patch was installed, with xor as "#". The parser still needs work.
Besides the known issue of "|", this also parses funny:

=> select 5 & ~ 6;
ERROR: Unable to identify a right operator '&' for type 'int4'

Marko Kreen writes:

Here is my next take on binary operators for integers.
It implements the following operators for int2/int4/int8:

~ - not
& - and
^ - xor
| - or
<< - shift left

- shift right

Notes:

* My original choice for xor was '#' because the '^' operator conflicts
with power operator on floats but Tom Lane said:

Well, you *could* use '^' since there's no definition of it for integer
operands. But that would mean that something like '4^2', which was
formerly implicitly coerced to float and interpreted as floating
power function, would suddenly mean something different. Again a
serious risk of silently breaking applications. This doesn't apply to
'|' though, since it has no numeric interpretation at all right now.

As the bit-string uses '^' too for xor-ing it would be nice to be
consistent. I am quite unsure on this matter. The patch now seems
otherwise sane to me, this is the only issue left.

* On << and >> the second argument is always int32 as this seems
to be the 'default' int type in PostgreSQL.

* Oids used are 1874 - 1909.

Comments?

Patch is against current CVS.

--
Peter Eisentraut peter_e@gmx.net http://yi.org/peter-e/

#5Marko Kreen
marko@l-t.ee
In reply to: Peter Eisentraut (#4)
Re: binary operators on integers

On Tue, Oct 24, 2000 at 10:23:55PM +0200, Peter Eisentraut wrote:

This patch was installed, with xor as "#". The parser still needs work.
Besides the known issue of "|", this also parses funny:

=> select 5 & ~ 6;
ERROR: Unable to identify a right operator '&' for type 'int4'

I have known that from the beginning. On first patch I did not get
it work correctly, so in second patch I disabled all gram.y hack
altogether. So this patch does not change anything in parser/.
At the moment it should be used: select 5 & (~ 6);

I can hack the gram.y and scan.l to get those operators to work
but as I saw no consensus has been reached in -hackers whether
and how it should be solved globally?

--
marko

#6Tom Lane
tgl@sss.pgh.pa.us
In reply to: Peter Eisentraut (#4)
Re: [PATCHES] binary operators on integers

Peter Eisentraut <peter_e@gmx.net> writes:

This patch was installed, with xor as "#". The parser still needs work.
Besides the known issue of "|", this also parses funny:

=> select 5 & ~ 6;
ERROR: Unable to identify a right operator '&' for type 'int4'

I think we're kind of stuck on that, at least in terms of a solution
specifically for ~ --- I don't think we should be wiring knowledge of
whether specific operators are prefix/suffix/infix into the grammar.

It might perhaps be possible to tweak the grammar so that

operand operator operator operand

is generically resolved as

operand infix-op (prefix-op operand)

and not

(operand postfix-op) infix-op operand

the way it is now. Given that postfix operators are relatively seldom
used, this seems a more sensible default --- but I suppose somewhere out
there is an application that will break. (At least it probably won't
break silently.)

Comments anyone?

regards, tom lane

#7Bruce Momjian
pgman@candle.pha.pa.us
In reply to: Peter Eisentraut (#4)
Re: binary operators on integers

Looks like this is fixed:

test=> select 5 & ~ 6;
ERROR: Unable to identify a right operator '&' for type 'int4'
You may need to add parentheses or an explicit cast
test=> select 5 & (~ 6);
?column?
----------
1
(1 row)

This patch was installed, with xor as "#". The parser still needs work.
Besides the known issue of "|", this also parses funny:

=> select 5 & ~ 6;
ERROR: Unable to identify a right operator '&' for type 'int4'

Marko Kreen writes:

Here is my next take on binary operators for integers.
It implements the following operators for int2/int4/int8:

~ - not
& - and
^ - xor
| - or
<< - shift left

- shift right

Notes:

* My original choice for xor was '#' because the '^' operator conflicts
with power operator on floats but Tom Lane said:

Well, you *could* use '^' since there's no definition of it for integer
operands. But that would mean that something like '4^2', which was
formerly implicitly coerced to float and interpreted as floating
power function, would suddenly mean something different. Again a
serious risk of silently breaking applications. This doesn't apply to
'|' though, since it has no numeric interpretation at all right now.

As the bit-string uses '^' too for xor-ing it would be nice to be
consistent. I am quite unsure on this matter. The patch now seems
otherwise sane to me, this is the only issue left.

* On << and >> the second argument is always int32 as this seems
to be the 'default' int type in PostgreSQL.

* Oids used are 1874 - 1909.

Comments?

Patch is against current CVS.

--
Peter Eisentraut peter_e@gmx.net http://yi.org/peter-e/

-- 
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026
#8Marko Kreen
marko@l-t.ee
In reply to: Bruce Momjian (#7)
Re: binary operators on integers

On Fri, Jan 19, 2001 at 04:30:09PM -0500, Bruce Momjian wrote:

Looks like this is fixed:

test=> select 5 & ~ 6;
ERROR: Unable to identify a right operator '&' for type 'int4'
You may need to add parentheses or an explicit cast
test=> select 5 & (~ 6);
?column?
----------
1
(1 row)

I can still reproduce it:

marko=# SELECT 5 & ~6;
ERROR: Unable to identify a right operator '&' for type 'int4'
You may need to add parentheses or an explicit cast

Or did you mean it can be fixed with parenthesis? That was the
case from the beginning.

This patch was installed, with xor as "#". The parser still needs work.
Besides the known issue of "|", this also parses funny:

=> select 5 & ~ 6;
ERROR: Unable to identify a right operator '&' for type 'int4'

--
marko

#9Tom Lane
tgl@sss.pgh.pa.us
In reply to: Marko Kreen (#8)
Re: [PATCHES] binary operators on integers

Marko Kreen <marko@l-t.ee> writes:

I can still reproduce it:
marko=# SELECT 5 & ~6;
ERROR: Unable to identify a right operator '&' for type 'int4'
You may need to add parentheses or an explicit cast

Correct, we did not rejigger the operator precedence.

I played around with this a little bit, and find that the attached patch
makes the above case work as desired --- essentially, it changes things
so that
a_expr Op Op a_expr
will be parsed as
a_expr Op (Op a_expr)
not
(a_expr Op) Op a_expr
which is what you get now because Op is marked left-associative.

Now, this is a situation where we can't fix one case without breaking
another, namely the case where you really DID want the first Op to be
parsed as a postfix operator. Thus the problem moves over to here:

regression=# select 4! ~ 10;
ERROR: Unable to identify an operator '!' for types 'int4' and 'int4'
You will have to retype this query using an explicit cast
regression=# select (4!) ~ 10;
?column?
----------
f
(1 row)

whereas this worked without parens in 7.0.

Given the infrequency of use of postfix operators compared to prefix,
I am inclined to think that we should change the grammar to make the
latter easier to use at the expense of the former. On the other hand,
it seems there's a pretty large risk of backwards-incompatibility here.
Comments?

BTW, the regress tests do not break, so they contain no examples where
it makes a difference.

regards, tom lane

*** src/backend/parser/gram.y.orig	Sat Jan 20 12:37:52 2001
--- src/backend/parser/gram.y	Sat Jan 20 13:03:17 2001
***************
*** 383,388 ****
--- 383,389 ----
  %nonassoc	OVERLAPS
  %nonassoc	BETWEEN
  %nonassoc	IN
+ %left		POSTFIXOP		/* dummy for postfix Op rules */
  %left		Op				/* multi-character ops and user-defined operators */
  %nonassoc	NOTNULL
  %nonassoc	ISNULL
***************
*** 4312,4320 ****
  				{	$$ = makeA_Expr(OP, "+", NULL, $2); }
  		| '-' a_expr					%prec UMINUS
  				{	$$ = doNegate($2); }
! 		| '%' a_expr
  				{	$$ = makeA_Expr(OP, "%", NULL, $2); }
! 		| '^' a_expr
  				{	$$ = makeA_Expr(OP, "^", NULL, $2); }
  		| a_expr '%'
  				{	$$ = makeA_Expr(OP, "%", $1, NULL); }
--- 4313,4321 ----
  				{	$$ = makeA_Expr(OP, "+", NULL, $2); }
  		| '-' a_expr					%prec UMINUS
  				{	$$ = doNegate($2); }
! 		| '%' a_expr					%prec UMINUS
  				{	$$ = makeA_Expr(OP, "%", NULL, $2); }
! 		| '^' a_expr					%prec UMINUS
  				{	$$ = makeA_Expr(OP, "^", NULL, $2); }
  		| a_expr '%'
  				{	$$ = makeA_Expr(OP, "%", $1, NULL); }
***************
*** 4353,4361 ****

| a_expr Op a_expr
{ $$ = makeA_Expr(OP, $2, $1, $3); }
! | Op a_expr
{ $$ = makeA_Expr(OP, $1, NULL, $2); }
! | a_expr Op
{ $$ = makeA_Expr(OP, $2, $1, NULL); }

  		| a_expr AND a_expr
--- 4354,4362 ----

| a_expr Op a_expr
{ $$ = makeA_Expr(OP, $2, $1, $3); }
! | Op a_expr %prec UMINUS
{ $$ = makeA_Expr(OP, $1, NULL, $2); }
! | a_expr Op %prec POSTFIXOP
{ $$ = makeA_Expr(OP, $2, $1, NULL); }

  		| a_expr AND a_expr
***************
*** 4560,4568 ****
  				{	$$ = makeA_Expr(OP, "+", NULL, $2); }
  		| '-' b_expr					%prec UMINUS
  				{	$$ = doNegate($2); }
! 		| '%' b_expr
  				{	$$ = makeA_Expr(OP, "%", NULL, $2); }
! 		| '^' b_expr
  				{	$$ = makeA_Expr(OP, "^", NULL, $2); }
  		| b_expr '%'
  				{	$$ = makeA_Expr(OP, "%", $1, NULL); }
--- 4561,4569 ----
  				{	$$ = makeA_Expr(OP, "+", NULL, $2); }
  		| '-' b_expr					%prec UMINUS
  				{	$$ = doNegate($2); }
! 		| '%' b_expr					%prec UMINUS
  				{	$$ = makeA_Expr(OP, "%", NULL, $2); }
! 		| '^' b_expr					%prec UMINUS
  				{	$$ = makeA_Expr(OP, "^", NULL, $2); }
  		| b_expr '%'
  				{	$$ = makeA_Expr(OP, "%", $1, NULL); }
***************
*** 4589,4597 ****

| b_expr Op b_expr
{ $$ = makeA_Expr(OP, $2, $1, $3); }
! | Op b_expr
{ $$ = makeA_Expr(OP, $1, NULL, $2); }
! | b_expr Op
{ $$ = makeA_Expr(OP, $2, $1, NULL); }
;

--- 4590,4598 ----

| b_expr Op b_expr
{ $$ = makeA_Expr(OP, $2, $1, $3); }
! | Op b_expr %prec UMINUS
{ $$ = makeA_Expr(OP, $1, NULL, $2); }
! | b_expr Op %prec POSTFIXOP
{ $$ = makeA_Expr(OP, $2, $1, NULL); }
;

#10Marko Kreen
marko@l-t.ee
In reply to: Tom Lane (#9)
Re: [PATCHES] binary operators on integers

On Sat, Jan 20, 2001 at 01:31:49PM -0500, Tom Lane wrote:

Given the infrequency of use of postfix operators compared to prefix,
I am inclined to think that we should change the grammar to make the
latter easier to use at the expense of the former. On the other hand,
it seems there's a pretty large risk of backwards-incompatibility here.
Comments?

I say, go for it! :) if it matters anything :]

And the backwards incompatibility should be simply mentioned in
release notes. Only problem is, that this is such a obscure
incompatibility that I am not sure e.g. distro packagers bother
to mention it in new 7.1 install splash-screens. "If you have
used factorial '!' or start of interval '|' operator in
expressions, note that ..." ?

--
marko

#11Tom Lane
tgl@sss.pgh.pa.us
In reply to: Tom Lane (#9)
Re: [PATCHES] binary operators on integers

I wrote:

Given the infrequency of use of postfix operators compared to prefix,
I am inclined to think that we should change the grammar to make the
latter easier to use at the expense of the former. On the other hand,
it seems there's a pretty large risk of backwards-incompatibility here.
Comments?

I backed away from part of the proposed patch --- changing the
precedence of all the prefix-operator productions to UMINUS would
probably break people's queries. But I've applied the part that
changes the behavior of a_expr Op Op a_expr. This will now be
parsed as an infix operator followed by a prefix operator.

regards, tom lane