19.12.2019 18:19, Antonin Houska wrote:
Anastasia Lubennikova <a.lubennik...@postgrespro.ru> wrote:

I attached new version with pg_opclass documentation update.

One more thing I am uncertain about  is array_ops. Arrays may contain bitwise
and not bitwise element types.
What is the correct value of opcisbitwise the array_ops itself?
How about setting opcisbitwise to false for the array_ops opclass and checking
opcisbitwise of the element type whenever we need to know whether the array is
"bitwise equal"? When checking array_eq(), I thought whether the existence of
"expanded array" format is a problem but it does not seem to be: the
conversion of "expanded" value to "flat" value and then back to the "expanded"
should not change the array contents.

Anyway, in the current version of the patch I see that array_ops opclasses
have opcisbitwise=true. It should be false even if you don't use the approach
of checking the element type.

Besides that, I think that record_ops is similar to array_ops and therefore it
should not set opcisbitwise to true.

I also remember that, when thinking about the problem in the context of the
aggregate push down patch, I considered some of the geometric types
problematic. For example, box_eq() uses this expression

#define FPeq(A,B)                               (fabs((A) - (B)) <= EPSILON)

so equality does not imply bitwise equality here. Maybe you should only set
the flag for btree opclasses for now.

Thank you for pointing out at the issue with geometric opclasses.
If I understand it correctly, regular float types are not bitwise as well.

I updated the patchset.
The first patch now contains only infrastructure changes
and the second one sets opcisbitwise for btree opclasses in pg_opclass.dat.

I've tried to be conservative and only mark types that are 100% bitwise safe.
See attached v2-Opclass-isbitwise.out file.

Non-atomic types, such as record, range, json and enum depend on element types. Text can be considered bitwise (i.e. texteq uses memcmp) only when specific collation clauses are satisfied.

We can make this 'opcisbitwise' parameter enum (or char) instead of boolean to mark "always bitwise", "never bitwise" and "maybe bitwise". Though, I doubt if it will be helpful in any real use case.

What do you think?

--
Anastasia Lubennikova
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

commit 891c03c4b8f37cf6711d6ae84f4e75573c123ec8
Author: Anastasia <a.lubennik...@postgrespro.ru>
Date:   Mon Dec 23 19:52:22 2019 +0300

    v4-Opclass-bitwise-equality-0001.patch
    Add new infrastracture to mark opclass as BITWISE. Actual values of this parameter will be added in the following patch.

diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out
index c915885..9b5c33b 100644
--- a/contrib/postgres_fdw/expected/postgres_fdw.out
+++ b/contrib/postgres_fdw/expected/postgres_fdw.out
@@ -3111,7 +3111,7 @@ create operator public.>^ (
 create operator family my_op_family using btree;
 create function my_op_cmp(a int, b int) returns int as
   $$begin return btint4cmp(a, b); end $$ language plpgsql;
-create operator class my_op_class for type int using btree family my_op_family as
+create operator class my_op_class bitwise for type int using btree family my_op_family as
  operator 1 public.<^,
  operator 3 public.=^,
  operator 5 public.>^,
diff --git a/contrib/postgres_fdw/sql/postgres_fdw.sql b/contrib/postgres_fdw/sql/postgres_fdw.sql
index 4f29e7c..48263d6 100644
--- a/contrib/postgres_fdw/sql/postgres_fdw.sql
+++ b/contrib/postgres_fdw/sql/postgres_fdw.sql
@@ -825,7 +825,7 @@ create operator family my_op_family using btree;
 create function my_op_cmp(a int, b int) returns int as
   $$begin return btint4cmp(a, b); end $$ language plpgsql;
 
-create operator class my_op_class for type int using btree family my_op_family as
+create operator class my_op_class bitwise for type int using btree family my_op_family as
  operator 1 public.<^,
  operator 3 public.=^,
  operator 5 public.>^,
diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index 55694c4..87cc344 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -4544,6 +4544,13 @@ SCRAM-SHA-256$<replaceable>&lt;iteration count&gt;</replaceable>:<replaceable>&l
       <entry>Type of data stored in index, or zero if same as <structfield>opcintype</structfield></entry>
      </row>
 
+     <row>
+      <entry><structfield>opcisbitwise</structfield></entry>
+      <entry><type>bool</type></entry>
+      <entry></entry>
+      <entry>True if the operator class equality is the same as equivalence</entry>
+     </row>
+
     </tbody>
    </tgroup>
   </table>
diff --git a/doc/src/sgml/ref/create_opclass.sgml b/doc/src/sgml/ref/create_opclass.sgml
index dd5252f..8d0ddfc 100644
--- a/doc/src/sgml/ref/create_opclass.sgml
+++ b/doc/src/sgml/ref/create_opclass.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE OPERATOR CLASS <replaceable class="parameter">name</replaceable> [ DEFAULT ] FOR TYPE <replaceable class="parameter">data_type</replaceable>
+CREATE OPERATOR CLASS <replaceable class="parameter">name</replaceable> [ DEFAULT | BITWISE ] FOR TYPE <replaceable class="parameter">data_type</replaceable>
   USING <replaceable class="parameter">index_method</replaceable> [ FAMILY <replaceable class="parameter">family_name</replaceable> ] AS
   {  OPERATOR <replaceable class="parameter">strategy_number</replaceable> <replaceable class="parameter">operator_name</replaceable> [ ( <replaceable class="parameter">op_type</replaceable>, <replaceable class="parameter">op_type</replaceable> ) ] [ FOR SEARCH | FOR ORDER BY <replaceable class="parameter">sort_family_name</replaceable> ]
    | FUNCTION <replaceable class="parameter">support_number</replaceable> [ ( <replaceable class="parameter">op_type</replaceable> [ , <replaceable class="parameter">op_type</replaceable> ] ) ] <replaceable class="parameter">function_name</replaceable> ( <replaceable class="parameter">argument_type</replaceable> [, ...] )
@@ -106,6 +106,20 @@ CREATE OPERATOR CLASS <replaceable class="parameter">name</replaceable> [ DEFAUL
     </listitem>
    </varlistentry>
 
+    <varlistentry>
+    <term><literal>BITWISE</literal></term>
+    <listitem>
+     <para>
+      If present, the operator class equality is the same as equivalence.
+      For example, two integers that compare equal are also binary equal,
+      while, numerics can compare equal but have different scales,
+      thus numeric opclass is not <literal>BITWISE</literal>. Even though,
+      most opclasses implement bitwise equal comparison, this behaviour
+      must be set explicitly.
+     </para>
+    </listitem>
+   </varlistentry>
+
    <varlistentry>
     <term><replaceable class="parameter">data_type</replaceable></term>
     <listitem>
diff --git a/src/backend/commands/opclasscmds.c b/src/backend/commands/opclasscmds.c
index cb7a6bd..c0fe187 100644
--- a/src/backend/commands/opclasscmds.c
+++ b/src/backend/commands/opclasscmds.c
@@ -653,6 +653,7 @@ DefineOpClass(CreateOpClassStmt *stmt)
 	values[Anum_pg_opclass_opcintype - 1] = ObjectIdGetDatum(typeoid);
 	values[Anum_pg_opclass_opcdefault - 1] = BoolGetDatum(stmt->isDefault);
 	values[Anum_pg_opclass_opckeytype - 1] = ObjectIdGetDatum(storageoid);
+	values[Anum_pg_opclass_opcisbitwise - 1] = BoolGetDatum(stmt->isBitwise);
 
 	tup = heap_form_tuple(rel->rd_att, values, nulls);
 
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index a9b8b84..73b076dd 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -3790,6 +3790,7 @@ _copyCreateOpClassStmt(const CreateOpClassStmt *from)
 	COPY_NODE_FIELD(datatype);
 	COPY_NODE_FIELD(items);
 	COPY_SCALAR_FIELD(isDefault);
+	COPY_SCALAR_FIELD(isBitwise);
 
 	return newnode;
 }
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 2fcd4a3..8f4ece4 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -1609,6 +1609,7 @@ _equalCreateOpClassStmt(const CreateOpClassStmt *a, const CreateOpClassStmt *b)
 	COMPARE_NODE_FIELD(datatype);
 	COMPARE_NODE_FIELD(items);
 	COMPARE_SCALAR_FIELD(isDefault);
+	COMPARE_SCALAR_FIELD(isBitwise);
 
 	return true;
 }
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index c508684..683f9b4 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -447,7 +447,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 
 %type <boolean> opt_instead
 %type <boolean> opt_unique opt_concurrently opt_verbose opt_full
-%type <boolean> opt_freeze opt_analyze opt_default opt_recheck
+%type <boolean> opt_freeze opt_analyze opt_default opt_recheck opt_bitwise
 %type <defelt>	opt_binary copy_delimiter
 
 %type <boolean> copy_from opt_program
@@ -618,7 +618,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 	AGGREGATE ALL ALSO ALTER ALWAYS ANALYSE ANALYZE AND ANY ARRAY AS ASC
 	ASSERTION ASSIGNMENT ASYMMETRIC AT ATTACH ATTRIBUTE AUTHORIZATION
 
-	BACKWARD BEFORE BEGIN_P BETWEEN BIGINT BINARY BIT
+	BACKWARD BEFORE BEGIN_P BETWEEN BIGINT BINARY BIT BITWISE
 	BOOLEAN_P BOTH BY
 
 	CACHE CALL CALLED CASCADE CASCADED CASE CAST CATALOG_P CHAIN CHAR_P
@@ -5953,16 +5953,17 @@ opt_if_not_exists: IF_P NOT EXISTS              { $$ = true; }
  *****************************************************************************/
 
 CreateOpClassStmt:
-			CREATE OPERATOR CLASS any_name opt_default FOR TYPE_P Typename
+			CREATE OPERATOR CLASS any_name opt_default opt_bitwise FOR TYPE_P Typename
 			USING access_method opt_opfamily AS opclass_item_list
 				{
 					CreateOpClassStmt *n = makeNode(CreateOpClassStmt);
 					n->opclassname = $4;
 					n->isDefault = $5;
-					n->datatype = $8;
-					n->amname = $10;
-					n->opfamilyname = $11;
-					n->items = $13;
+					n->isBitwise = $6;
+					n->datatype = $9;
+					n->amname = $11;
+					n->opfamilyname = $12;
+					n->items = $14;
 					$$ = (Node *) n;
 				}
 		;
@@ -6025,6 +6026,10 @@ opt_default:	DEFAULT						{ $$ = true; }
 			| /*EMPTY*/						{ $$ = false; }
 		;
 
+opt_bitwise:	BITWISE						{ $$ = true; }
+			| /*EMPTY*/						{ $$ = false; }
+		;
+
 opt_opfamily:	FAMILY any_name				{ $$ = $2; }
 			| /*EMPTY*/						{ $$ = NIL; }
 		;
@@ -15129,6 +15134,7 @@ unreserved_keyword:
 			| BACKWARD
 			| BEFORE
 			| BEGIN_P
+			| BITWISE
 			| BY
 			| CACHE
 			| CALL
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 08658c8..00e248b 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -12833,6 +12833,7 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
 	int			i_opcintype;
 	int			i_opckeytype;
 	int			i_opcdefault;
+	int			i_opcisbitwise;
 	int			i_opcfamily;
 	int			i_opcfamilyname;
 	int			i_opcfamilynsp;
@@ -12849,6 +12850,7 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
 	char	   *opcintype;
 	char	   *opckeytype;
 	char	   *opcdefault;
+	char	   *opcisbitwise;
 	char	   *opcfamily;
 	char	   *opcfamilyname;
 	char	   *opcfamilynsp;
@@ -12875,11 +12877,25 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
 	nameusing = createPQExpBuffer();
 
 	/* Get additional fields from the pg_opclass row */
-	if (fout->remoteVersion >= 80300)
+	if (fout->remoteVersion >= 13000)
+	{
+		appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
+						  "opckeytype::pg_catalog.regtype, "
+						  "opcdefault, opcisbitwise, opcfamily, "
+						  "opfname AS opcfamilyname, "
+						  "nspname AS opcfamilynsp, "
+						  "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
+						  "FROM pg_catalog.pg_opclass c "
+						  "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily "
+						  "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
+						  "WHERE c.oid = '%u'::pg_catalog.oid",
+						  opcinfo->dobj.catId.oid);
+	}
+	else if (fout->remoteVersion >= 80300)
 	{
 		appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
 						  "opckeytype::pg_catalog.regtype, "
-						  "opcdefault, opcfamily, "
+						  "opcdefault, 'f' as opcisbitwise, opcfamily, "
 						  "opfname AS opcfamilyname, "
 						  "nspname AS opcfamilynsp, "
 						  "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
@@ -12893,7 +12909,7 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
 	{
 		appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
 						  "opckeytype::pg_catalog.regtype, "
-						  "opcdefault, NULL AS opcfamily, "
+						  "opcdefault, 'f' as opcisbitwise, NULL AS opcfamily, "
 						  "NULL AS opcfamilyname, "
 						  "NULL AS opcfamilynsp, "
 						  "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcamid) AS amname "
@@ -12907,6 +12923,7 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
 	i_opcintype = PQfnumber(res, "opcintype");
 	i_opckeytype = PQfnumber(res, "opckeytype");
 	i_opcdefault = PQfnumber(res, "opcdefault");
+	i_opcisbitwise = PQfnumber(res, "opcisbitwise");
 	i_opcfamily = PQfnumber(res, "opcfamily");
 	i_opcfamilyname = PQfnumber(res, "opcfamilyname");
 	i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
@@ -12916,6 +12933,7 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
 	opcintype = pg_strdup(PQgetvalue(res, 0, i_opcintype));
 	opckeytype = PQgetvalue(res, 0, i_opckeytype);
 	opcdefault = PQgetvalue(res, 0, i_opcdefault);
+	opcisbitwise = PQgetvalue(res, 0, i_opcisbitwise);
 	/* opcfamily will still be needed after we PQclear res */
 	opcfamily = pg_strdup(PQgetvalue(res, 0, i_opcfamily));
 	opcfamilyname = PQgetvalue(res, 0, i_opcfamilyname);
@@ -12933,6 +12951,8 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
 					  fmtQualifiedDumpable(opcinfo));
 	if (strcmp(opcdefault, "t") == 0)
 		appendPQExpBufferStr(q, "DEFAULT ");
+	if (strcmp(opcisbitwise, "t") == 0)
+		appendPQExpBufferStr(q, "BITWISE ");
 	appendPQExpBuffer(q, "FOR TYPE %s USING %s",
 					  opcintype,
 					  fmtId(amname));
diff --git a/src/include/catalog/pg_opclass.h b/src/include/catalog/pg_opclass.h
index 84853c1..9ab32b3 100644
--- a/src/include/catalog/pg_opclass.h
+++ b/src/include/catalog/pg_opclass.h
@@ -73,6 +73,9 @@ CATALOG(pg_opclass,2616,OperatorClassRelationId)
 
 	/* type of data in index, or InvalidOid */
 	Oid			opckeytype BKI_DEFAULT(0) BKI_LOOKUP(pg_type);
+
+	/* T if opclass equality also means "bitwise equality" */
+	bool		opcisbitwise BKI_DEFAULT(f);
 } FormData_pg_opclass;
 
 /* ----------------
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index ff626cb..47ad85f 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -2577,6 +2577,7 @@ typedef struct CreateOpClassStmt
 	TypeName   *datatype;		/* datatype of indexed column */
 	List	   *items;			/* List of CreateOpClassItem nodes */
 	bool		isDefault;		/* Should be marked as default for type? */
+	bool		isBitwise;		/* Is opclass equality bitwise? */
 } CreateOpClassStmt;
 
 #define OPCLASS_ITEM_OPERATOR		1
diff --git a/src/include/parser/kwlist.h b/src/include/parser/kwlist.h
index 00ace84..d6a8e8f 100644
--- a/src/include/parser/kwlist.h
+++ b/src/include/parser/kwlist.h
@@ -58,6 +58,7 @@ PG_KEYWORD("between", BETWEEN, COL_NAME_KEYWORD)
 PG_KEYWORD("bigint", BIGINT, COL_NAME_KEYWORD)
 PG_KEYWORD("binary", BINARY, TYPE_FUNC_NAME_KEYWORD)
 PG_KEYWORD("bit", BIT, COL_NAME_KEYWORD)
+PG_KEYWORD("bitwise", BITWISE, UNRESERVED_KEYWORD)
 PG_KEYWORD("boolean", BOOLEAN_P, COL_NAME_KEYWORD)
 PG_KEYWORD("both", BOTH, RESERVED_KEYWORD)
 PG_KEYWORD("by", BY, UNRESERVED_KEYWORD)
commit 4b0eb505204b1be0bb7ba1171e288881e14a9b7c
Author: Anastasia <a.lubennik...@postgrespro.ru>
Date:   Mon Dec 23 19:43:57 2019 +0300

    v4-Opclass-bitwise-equality-0002.patch
    Mark nbtree opclasses as bitwise in pg_opclass.dat

diff --git a/src/include/catalog/pg_opclass.dat b/src/include/catalog/pg_opclass.dat
index 2d57510..72b563d 100644
--- a/src/include/catalog/pg_opclass.dat
+++ b/src/include/catalog/pg_opclass.dat
@@ -21,26 +21,26 @@
 { opcmethod => 'hash', opcname => 'array_ops', opcfamily => 'hash/array_ops',
   opcintype => 'anyarray' },
 { opcmethod => 'btree', opcname => 'bit_ops', opcfamily => 'btree/bit_ops',
-  opcintype => 'bit' },
+  opcintype => 'bit', opcisbitwise => 't' },
 { opcmethod => 'btree', opcname => 'bool_ops', opcfamily => 'btree/bool_ops',
-  opcintype => 'bool' },
+  opcintype => 'bool', opcisbitwise => 't' },
 { opcmethod => 'btree', opcname => 'bpchar_ops',
   opcfamily => 'btree/bpchar_ops', opcintype => 'bpchar' },
 { opcmethod => 'hash', opcname => 'bpchar_ops', opcfamily => 'hash/bpchar_ops',
   opcintype => 'bpchar' },
 { opcmethod => 'btree', opcname => 'bytea_ops', opcfamily => 'btree/bytea_ops',
-  opcintype => 'bytea' },
+  opcintype => 'bytea', opcisbitwise => 't' },
 { opcmethod => 'btree', opcname => 'char_ops', opcfamily => 'btree/char_ops',
-  opcintype => 'char' },
+  opcintype => 'char', opcisbitwise => 't' },
 { opcmethod => 'hash', opcname => 'char_ops', opcfamily => 'hash/char_ops',
   opcintype => 'char' },
 { opcmethod => 'btree', opcname => 'cidr_ops', opcfamily => 'btree/network_ops',
-  opcintype => 'inet', opcdefault => 'f' },
+  opcintype => 'inet', opcdefault => 'f', opcisbitwise => 't' },
 { opcmethod => 'hash', opcname => 'cidr_ops', opcfamily => 'hash/network_ops',
   opcintype => 'inet', opcdefault => 'f' },
 { oid => '3122', oid_symbol => 'DATE_BTREE_OPS_OID',
   opcmethod => 'btree', opcname => 'date_ops',
-  opcfamily => 'btree/datetime_ops', opcintype => 'date' },
+  opcfamily => 'btree/datetime_ops', opcintype => 'date', opcisbitwise => 't' },
 { opcmethod => 'hash', opcname => 'date_ops', opcfamily => 'hash/date_ops',
   opcintype => 'date' },
 { opcmethod => 'btree', opcname => 'float4_ops', opcfamily => 'btree/float_ops',
@@ -62,29 +62,29 @@
   opcfamily => 'spgist/network_ops', opcintype => 'inet' },
 { oid => '1979', oid_symbol => 'INT2_BTREE_OPS_OID',
   opcmethod => 'btree', opcname => 'int2_ops', opcfamily => 'btree/integer_ops',
-  opcintype => 'int2' },
+  opcintype => 'int2', opcisbitwise => 't' },
 { opcmethod => 'hash', opcname => 'int2_ops', opcfamily => 'hash/integer_ops',
   opcintype => 'int2' },
 { oid => '1978', oid_symbol => 'INT4_BTREE_OPS_OID',
   opcmethod => 'btree', opcname => 'int4_ops', opcfamily => 'btree/integer_ops',
-  opcintype => 'int4' },
+  opcintype => 'int4', opcisbitwise => 't' },
 { opcmethod => 'hash', opcname => 'int4_ops', opcfamily => 'hash/integer_ops',
   opcintype => 'int4' },
 { oid => '3124', oid_symbol => 'INT8_BTREE_OPS_OID',
   opcmethod => 'btree', opcname => 'int8_ops', opcfamily => 'btree/integer_ops',
-  opcintype => 'int8' },
+  opcintype => 'int8', opcisbitwise => 't' },
 { opcmethod => 'hash', opcname => 'int8_ops', opcfamily => 'hash/integer_ops',
   opcintype => 'int8' },
 { opcmethod => 'btree', opcname => 'interval_ops',
-  opcfamily => 'btree/interval_ops', opcintype => 'interval' },
+  opcfamily => 'btree/interval_ops', opcintype => 'interval', opcisbitwise => 't' },
 { opcmethod => 'hash', opcname => 'interval_ops',
   opcfamily => 'hash/interval_ops', opcintype => 'interval' },
 { opcmethod => 'btree', opcname => 'macaddr_ops',
-  opcfamily => 'btree/macaddr_ops', opcintype => 'macaddr' },
+  opcfamily => 'btree/macaddr_ops', opcintype => 'macaddr', opcisbitwise => 't' },
 { opcmethod => 'hash', opcname => 'macaddr_ops',
   opcfamily => 'hash/macaddr_ops', opcintype => 'macaddr' },
 { opcmethod => 'btree', opcname => 'macaddr8_ops',
-  opcfamily => 'btree/macaddr8_ops', opcintype => 'macaddr8' },
+  opcfamily => 'btree/macaddr8_ops', opcintype => 'macaddr8', opcisbitwise => 't' },
 { opcmethod => 'hash', opcname => 'macaddr8_ops',
   opcfamily => 'hash/macaddr8_ops', opcintype => 'macaddr8' },
 
@@ -105,11 +105,11 @@
   opcfamily => 'hash/numeric_ops', opcintype => 'numeric' },
 { oid => '1981', oid_symbol => 'OID_BTREE_OPS_OID',
   opcmethod => 'btree', opcname => 'oid_ops', opcfamily => 'btree/oid_ops',
-  opcintype => 'oid' },
+  opcintype => 'oid', opcisbitwise => 't' },
 { opcmethod => 'hash', opcname => 'oid_ops', opcfamily => 'hash/oid_ops',
   opcintype => 'oid' },
 { opcmethod => 'btree', opcname => 'oidvector_ops',
-  opcfamily => 'btree/oidvector_ops', opcintype => 'oidvector' },
+  opcfamily => 'btree/oidvector_ops', opcintype => 'oidvector', opcisbitwise => 't' },
 { opcmethod => 'hash', opcname => 'oidvector_ops',
   opcfamily => 'hash/oidvector_ops', opcintype => 'oidvector' },
 { opcmethod => 'btree', opcname => 'record_ops',
@@ -123,27 +123,27 @@
 { opcmethod => 'hash', opcname => 'text_ops', opcfamily => 'hash/text_ops',
   opcintype => 'text' },
 { opcmethod => 'btree', opcname => 'time_ops', opcfamily => 'btree/time_ops',
-  opcintype => 'time' },
+  opcintype => 'time', opcisbitwise => 't' },
 { opcmethod => 'hash', opcname => 'time_ops', opcfamily => 'hash/time_ops',
   opcintype => 'time' },
 { oid => '3127', oid_symbol => 'TIMESTAMPTZ_BTREE_OPS_OID',
   opcmethod => 'btree', opcname => 'timestamptz_ops',
-  opcfamily => 'btree/datetime_ops', opcintype => 'timestamptz' },
+  opcfamily => 'btree/datetime_ops', opcintype => 'timestamptz', opcisbitwise => 't' },
 { opcmethod => 'hash', opcname => 'timestamptz_ops',
   opcfamily => 'hash/timestamptz_ops', opcintype => 'timestamptz' },
 { opcmethod => 'btree', opcname => 'timetz_ops',
-  opcfamily => 'btree/timetz_ops', opcintype => 'timetz' },
+  opcfamily => 'btree/timetz_ops', opcintype => 'timetz', opcisbitwise => 't' },
 { opcmethod => 'hash', opcname => 'timetz_ops', opcfamily => 'hash/timetz_ops',
   opcintype => 'timetz' },
 { opcmethod => 'btree', opcname => 'varbit_ops',
-  opcfamily => 'btree/varbit_ops', opcintype => 'varbit' },
+  opcfamily => 'btree/varbit_ops', opcintype => 'varbit', opcisbitwise => 't' },
 { opcmethod => 'btree', opcname => 'varchar_ops', opcfamily => 'btree/text_ops',
   opcintype => 'text', opcdefault => 'f' },
 { opcmethod => 'hash', opcname => 'varchar_ops', opcfamily => 'hash/text_ops',
   opcintype => 'text', opcdefault => 'f' },
 { oid => '3128', oid_symbol => 'TIMESTAMP_BTREE_OPS_OID',
   opcmethod => 'btree', opcname => 'timestamp_ops',
-  opcfamily => 'btree/datetime_ops', opcintype => 'timestamp' },
+  opcfamily => 'btree/datetime_ops', opcintype => 'timestamp', opcisbitwise => 't' },
 { opcmethod => 'hash', opcname => 'timestamp_ops',
   opcfamily => 'hash/timestamp_ops', opcintype => 'timestamp' },
 { oid => '4217', oid_symbol => 'TEXT_BTREE_PATTERN_OPS_OID',
@@ -165,7 +165,7 @@
 { opcmethod => 'hash', opcname => 'bytea_ops', opcfamily => 'hash/bytea_ops',
   opcintype => 'bytea' },
 { opcmethod => 'btree', opcname => 'tid_ops', opcfamily => 'btree/tid_ops',
-  opcintype => 'tid' },
+  opcintype => 'tid', opcisbitwise => 't' },
 { opcmethod => 'hash', opcname => 'xid_ops', opcfamily => 'hash/xid_ops',
   opcintype => 'xid' },
 { opcmethod => 'hash', opcname => 'cid_ops', opcfamily => 'hash/cid_ops',
@@ -194,11 +194,11 @@
 { opcmethod => 'gin', opcname => 'array_ops', opcfamily => 'gin/array_ops',
   opcintype => 'anyarray', opckeytype => 'anyelement' },
 { opcmethod => 'btree', opcname => 'uuid_ops', opcfamily => 'btree/uuid_ops',
-  opcintype => 'uuid' },
+  opcintype => 'uuid', opcisbitwise => 't' },
 { opcmethod => 'hash', opcname => 'uuid_ops', opcfamily => 'hash/uuid_ops',
   opcintype => 'uuid' },
 { opcmethod => 'btree', opcname => 'pg_lsn_ops',
-  opcfamily => 'btree/pg_lsn_ops', opcintype => 'pg_lsn' },
+  opcfamily => 'btree/pg_lsn_ops', opcintype => 'pg_lsn', opcisbitwise => 't' },
 { opcmethod => 'hash', opcname => 'pg_lsn_ops', opcfamily => 'hash/pg_lsn_ops',
   opcintype => 'pg_lsn' },
 { opcmethod => 'btree', opcname => 'enum_ops', opcfamily => 'btree/enum_ops',
# 403 is btree am oid

  select opcname from pg_opclass where opcmethod= 403 and opcisbitwise = true;
     opcname     
-----------------
 bit_ops
 bool_ops
 bytea_ops
 char_ops
 cidr_ops
 date_ops
 int2_ops
 int4_ops
 int8_ops
 interval_ops
 macaddr_ops
 macaddr8_ops
 oid_ops
 oidvector_ops
 time_ops
 timestamptz_ops
 timetz_ops
 varbit_ops
 timestamp_ops
 tid_ops
 uuid_ops
 pg_lsn_ops
(22 rows)

 select opcname from pg_opclass where opcmethod= 403 and opcisbitwise = false;
       opcname       
---------------------
 array_ops
 bpchar_ops
 float4_ops
 float8_ops
 inet_ops
 name_ops
 numeric_ops
 record_ops
 record_image_ops
 text_ops
 varchar_ops
 text_pattern_ops
 varchar_pattern_ops
 bpchar_pattern_ops
 money_ops
 enum_ops
 tsvector_ops
 tsquery_ops
 range_ops
 jsonb_ops
(20 rows)

Reply via email to