From cc53a1e7ccfa762bda70e1b6a15bfd929bf1b4e3 Mon Sep 17 00:00:00 2001
From: Robert Haas <rhaas@postgresql.org>
Date: Thu, 19 Jan 2012 15:23:04 -0500
Subject: [PATCH] Add bitwise AND, OR, and NOT operators for macaddr data type.

Brendan Jurd, reviewed by Fujii Masao
---
 doc/src/sgml/func.sgml                |  4 +-
 src/backend/utils/adt/mac.c           | 53 +++++++++++++++++++++++++++
 src/include/catalog/catversion.h      |  2 +-
 src/include/catalog/pg_operator.h     |  7 ++++
 src/include/catalog/pg_proc.h         |  3 ++
 src/include/utils/builtins.h          |  3 ++
 src/test/regress/expected/macaddr.out | 48 ++++++++++++++++++++++++
 src/test/regress/sql/macaddr.sql      |  4 ++
 8 files changed, 122 insertions(+), 2 deletions(-)

diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index ff9b8b0853e..43b72f695c2 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -8300,7 +8300,9 @@ CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple
    <para>
     The <type>macaddr</type> type also supports the standard relational
     operators (<literal>&gt;</literal>, <literal>&lt;=</literal>, etc.) for
-    lexicographical ordering.
+    lexicographical ordering, and the bitwise arithmetic operators
+    (<literal>~</literal>, <literal>&amp;</literal> and <literal>|</literal>)
+    for NOT, AND and OR.
    </para>
 
   </sect1>
diff --git a/src/backend/utils/adt/mac.c b/src/backend/utils/adt/mac.c
index 333f4bca467..958ff54d73e 100644
--- a/src/backend/utils/adt/mac.c
+++ b/src/backend/utils/adt/mac.c
@@ -241,6 +241,59 @@ hashmacaddr(PG_FUNCTION_ARGS)
 	return hash_any((unsigned char *) key, sizeof(macaddr));
 }
 
+/*
+ * Arithmetic functions: bitwise NOT, AND, OR.
+ */
+Datum
+macaddr_not(PG_FUNCTION_ARGS)
+{
+	macaddr	   *addr = PG_GETARG_MACADDR_P(0);
+	macaddr	   *result;
+
+	result = (macaddr *) palloc(sizeof(macaddr));
+	result->a = ~addr->a;
+	result->b = ~addr->b;
+	result->c = ~addr->c;
+	result->d = ~addr->d;
+	result->e = ~addr->e;
+	result->f = ~addr->f;
+	PG_RETURN_MACADDR_P(result);
+}
+
+Datum
+macaddr_and(PG_FUNCTION_ARGS)
+{
+	macaddr	   *addr1 = PG_GETARG_MACADDR_P(0);
+	macaddr	   *addr2 = PG_GETARG_MACADDR_P(1);
+	macaddr	   *result;
+
+	result = (macaddr *) palloc(sizeof(macaddr));
+	result->a = addr1->a & addr2->a;
+	result->b = addr1->b & addr2->b;
+	result->c = addr1->c & addr2->c;
+	result->d = addr1->d & addr2->d;
+	result->e = addr1->e & addr2->e;
+	result->f = addr1->f & addr2->f;
+	PG_RETURN_MACADDR_P(result);
+}
+
+Datum
+macaddr_or(PG_FUNCTION_ARGS)
+{
+	macaddr	   *addr1 = PG_GETARG_MACADDR_P(0);
+	macaddr	   *addr2 = PG_GETARG_MACADDR_P(1);
+	macaddr	   *result;
+
+	result = (macaddr *) palloc(sizeof(macaddr));
+	result->a = addr1->a | addr2->a;
+	result->b = addr1->b | addr2->b;
+	result->c = addr1->c | addr2->c;
+	result->d = addr1->d | addr2->d;
+	result->e = addr1->e | addr2->e;
+	result->f = addr1->f | addr2->f;
+	PG_RETURN_MACADDR_P(result);
+}
+
 /*
  *	Truncation function to allow comparing mac manufacturers.
  *	From suggestion by Alex Pilosov <alex@pilosoft.com>
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index 9e799c6a103..285fae3e4ab 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -53,6 +53,6 @@
  */
 
 /*							yyyymmddN */
-#define CATALOG_VERSION_NO	201201191
+#define CATALOG_VERSION_NO	201201192
 
 #endif
diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h
index f19865dd083..ead5af6d80c 100644
--- a/src/include/catalog/pg_operator.h
+++ b/src/include/catalog/pg_operator.h
@@ -1116,6 +1116,13 @@ DESCR("greater than");
 DATA(insert OID = 1225 (  ">="	   PGNSP PGUID b f f 829 829	 16 1223 1222 macaddr_ge scalargtsel scalargtjoinsel ));
 DESCR("greater than or equal");
 
+DATA(insert OID = 3147 (  "~"	   PGNSP PGUID l f f	  0 829 829 0 0 macaddr_not - - ));
+DESCR("bitwise not");
+DATA(insert OID = 3148 (  "&"	   PGNSP PGUID b f f	829 829 829 0 0 macaddr_and - - ));
+DESCR("bitwise and");
+DATA(insert OID = 3149 (  "|"	   PGNSP PGUID b f f	829 829 829 0 0 macaddr_or - - ));
+DESCR("bitwise or");
+
 /* INET type (these also support CIDR via implicit cast) */
 DATA(insert OID = 1201 (  "="	   PGNSP PGUID b t t 869 869	 16 1201 1202 network_eq eqsel eqjoinsel ));
 DESCR("equal");
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 9994468571c..b6ac1959cc1 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -2039,6 +2039,9 @@ DATA(insert OID = 834 (  macaddr_ge			PGNSP PGUID 12 1 0 0 0 f f f t f i 2 0 16
 DATA(insert OID = 835 (  macaddr_ne			PGNSP PGUID 12 1 0 0 0 f f f t f i 2 0 16 "829 829" _null_ _null_ _null_ _null_	macaddr_ne _null_ _null_ _null_ ));
 DATA(insert OID = 836 (  macaddr_cmp		PGNSP PGUID 12 1 0 0 0 f f f t f i 2 0 23 "829 829" _null_ _null_ _null_ _null_	macaddr_cmp _null_ _null_ _null_ ));
 DESCR("less-equal-greater");
+DATA(insert OID = 3144 (  macaddr_not		PGNSP PGUID 12 1 0 0 0 f f f t f i 1 0 829 "829" _null_ _null_ _null_ _null_	macaddr_not _null_ _null_ _null_ ));
+DATA(insert OID = 3145 (  macaddr_and		PGNSP PGUID 12 1 0 0 0 f f f t f i 2 0 829 "829 829" _null_ _null_ _null_ _null_	macaddr_and _null_ _null_ _null_ ));
+DATA(insert OID = 3146 (  macaddr_or		PGNSP PGUID 12 1 0 0 0 f f f t f i 2 0 829 "829 829" _null_ _null_ _null_ _null_	macaddr_or _null_ _null_ _null_ ));
 
 /* for inet type support */
 DATA(insert OID = 910 (  inet_in			PGNSP PGUID 12 1 0 0 0 f f f t f i 1 0 869 "2275" _null_ _null_ _null_ _null_ inet_in _null_ _null_ _null_ ));
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index 46b2f3b2452..68179d550f8 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -900,6 +900,9 @@ extern Datum macaddr_eq(PG_FUNCTION_ARGS);
 extern Datum macaddr_ge(PG_FUNCTION_ARGS);
 extern Datum macaddr_gt(PG_FUNCTION_ARGS);
 extern Datum macaddr_ne(PG_FUNCTION_ARGS);
+extern Datum macaddr_not(PG_FUNCTION_ARGS);
+extern Datum macaddr_and(PG_FUNCTION_ARGS);
+extern Datum macaddr_or(PG_FUNCTION_ARGS);
 extern Datum macaddr_trunc(PG_FUNCTION_ARGS);
 extern Datum hashmacaddr(PG_FUNCTION_ARGS);
 
diff --git a/src/test/regress/expected/macaddr.out b/src/test/regress/expected/macaddr.out
index 0b2a96d2f7a..50d0369139a 100644
--- a/src/test/regress/expected/macaddr.out
+++ b/src/test/regress/expected/macaddr.out
@@ -103,4 +103,52 @@ SELECT b <> '08:00:2b:01:02:03' FROM macaddr_data WHERE a = 1; -- false
  f
 (1 row)
 
+SELECT ~b                       FROM macaddr_data;
+     ?column?      
+-------------------
+ f7:ff:d4:fe:fd:fc
+ f7:ff:d4:fe:fd:fc
+ f7:ff:d4:fe:fd:fc
+ f7:ff:d4:fe:fd:fc
+ f7:ff:d4:fe:fd:fc
+ f7:ff:d4:fe:fd:fc
+ f7:ff:d4:fe:fd:fb
+ f7:ff:d4:fe:fd:fd
+ f7:ff:d5:fe:fd:fc
+ f7:ff:d3:fe:fd:fc
+ f7:ff:d5:fe:fd:fb
+(11 rows)
+
+SELECT  b & '00:00:00:ff:ff:ff' FROM macaddr_data;
+     ?column?      
+-------------------
+ 00:00:00:01:02:03
+ 00:00:00:01:02:03
+ 00:00:00:01:02:03
+ 00:00:00:01:02:03
+ 00:00:00:01:02:03
+ 00:00:00:01:02:03
+ 00:00:00:01:02:04
+ 00:00:00:01:02:02
+ 00:00:00:01:02:03
+ 00:00:00:01:02:03
+ 00:00:00:01:02:04
+(11 rows)
+
+SELECT  b | '01:02:03:04:05:06' FROM macaddr_data;
+     ?column?      
+-------------------
+ 09:02:2b:05:07:07
+ 09:02:2b:05:07:07
+ 09:02:2b:05:07:07
+ 09:02:2b:05:07:07
+ 09:02:2b:05:07:07
+ 09:02:2b:05:07:07
+ 09:02:2b:05:07:06
+ 09:02:2b:05:07:06
+ 09:02:2b:05:07:07
+ 09:02:2f:05:07:07
+ 09:02:2b:05:07:06
+(11 rows)
+
 DROP TABLE macaddr_data;
diff --git a/src/test/regress/sql/macaddr.sql b/src/test/regress/sql/macaddr.sql
index ce8d9209329..1ccf501722f 100644
--- a/src/test/regress/sql/macaddr.sql
+++ b/src/test/regress/sql/macaddr.sql
@@ -35,4 +35,8 @@ SELECT b =  '08:00:2b:01:02:03' FROM macaddr_data WHERE a = 1; -- true
 SELECT b <> '08:00:2b:01:02:04' FROM macaddr_data WHERE a = 1; -- true
 SELECT b <> '08:00:2b:01:02:03' FROM macaddr_data WHERE a = 1; -- false
 
+SELECT ~b                       FROM macaddr_data;
+SELECT  b & '00:00:00:ff:ff:ff' FROM macaddr_data;
+SELECT  b | '01:02:03:04:05:06' FROM macaddr_data;
+
 DROP TABLE macaddr_data;
-- 
GitLab