binary operators on integers
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> << </ENTRY>
+ <ENTRY>Binary shift left</ENTRY>
+ <ENTRY>1 << 4</ENTRY>
+ </ROW>
+ <ROW>
+ <ENTRY> >> </ENTRY>
+ <ENTRY>Binary shift right</ENTRY>
+ <ENTRY>8 >> 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);
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
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
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/
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
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
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
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
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); }
;
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
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