mirror of
https://github.com/postgres/postgres.git
synced 2025-04-22 23:02:54 +03:00
Create the system catalog infrastructure needed for KNNGIST.
This commit adds columns amoppurpose and amopsortfamily to pg_amop, and column amcanorderbyop to pg_am. For the moment all the entries in amcanorderbyop are "false", since the underlying support isn't there yet. Also, extend the CREATE OPERATOR CLASS/ALTER OPERATOR FAMILY commands with [ FOR SEARCH | FOR ORDER BY sort_operator_family ] clauses to allow the new columns of pg_amop to be populated, and create pg_dump support for dumping that information. I also added some documentation, although it's perhaps a bit premature given that the feature doesn't do anything useful yet. Teodor Sigaev, Robert Haas, Tom Lane
This commit is contained in:
parent
4fc09ad00c
commit
725d52d0c2
@ -423,7 +423,16 @@
|
|||||||
<entry><structfield>amcanorder</structfield></entry>
|
<entry><structfield>amcanorder</structfield></entry>
|
||||||
<entry><type>bool</type></entry>
|
<entry><type>bool</type></entry>
|
||||||
<entry></entry>
|
<entry></entry>
|
||||||
<entry>Does the access method support ordered scans?</entry>
|
<entry>Does the access method support ordered scans sorted by the
|
||||||
|
indexed column's value?</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><structfield>amcanorderbyop</structfield></entry>
|
||||||
|
<entry><type>bool</type></entry>
|
||||||
|
<entry></entry>
|
||||||
|
<entry>Does the access method support ordered scans sorted by the result
|
||||||
|
of an operator on the indexed column?</entry>
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
<row>
|
<row>
|
||||||
@ -598,9 +607,13 @@
|
|||||||
<para>
|
<para>
|
||||||
The catalog <structname>pg_amop</structname> stores information about
|
The catalog <structname>pg_amop</structname> stores information about
|
||||||
operators associated with access method operator families. There is one
|
operators associated with access method operator families. There is one
|
||||||
row for each operator that is a member of an operator family. An operator
|
row for each operator that is a member of an operator family. A family
|
||||||
|
member can be either a <firstterm>search</> operator or an
|
||||||
|
<firstterm>ordering</> operator. An operator
|
||||||
can appear in more than one family, but cannot appear in more than one
|
can appear in more than one family, but cannot appear in more than one
|
||||||
position within a family.
|
search position nor more than one ordering position within a family.
|
||||||
|
(It is allowed, though unlikely, for an operator to be used for both
|
||||||
|
search and ordering purposes.)
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
@ -645,6 +658,14 @@
|
|||||||
<entry>Operator strategy number</entry>
|
<entry>Operator strategy number</entry>
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><structfield>amoppurpose</structfield></entry>
|
||||||
|
<entry><type>char</type></entry>
|
||||||
|
<entry></entry>
|
||||||
|
<entry>Operator purpose, either <literal>s</> for search or
|
||||||
|
<literal>o</> for ordering</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
<row>
|
<row>
|
||||||
<entry><structfield>amopopr</structfield></entry>
|
<entry><structfield>amopopr</structfield></entry>
|
||||||
<entry><type>oid</type></entry>
|
<entry><type>oid</type></entry>
|
||||||
@ -659,10 +680,52 @@
|
|||||||
<entry>Index access method operator family is for</entry>
|
<entry>Index access method operator family is for</entry>
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><structfield>amopsortfamily</structfield></entry>
|
||||||
|
<entry><type>oid</type></entry>
|
||||||
|
<entry><literal><link linkend="catalog-pg-opfamily"><structname>pg_opfamily</structname></link>.oid</literal></entry>
|
||||||
|
<entry>The btree operator family this entry sorts according to, if an
|
||||||
|
ordering operator; zero if a search operator</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</tgroup>
|
</tgroup>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
A <quote>search</> operator entry indicates that an index of this operator
|
||||||
|
family can be searched to find all rows satisfying
|
||||||
|
<literal>WHERE</>
|
||||||
|
<replaceable>indexed_column</>
|
||||||
|
<replaceable>operator</>
|
||||||
|
<replaceable>constant</>.
|
||||||
|
Obviously, such an operator must return boolean, and its left-hand input
|
||||||
|
type must match the index's column data type.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
An <quote>ordering</> operator entry indicates that an index of this
|
||||||
|
operator family can be scanned to return rows in the order represented by
|
||||||
|
<literal>ORDER BY</>
|
||||||
|
<replaceable>indexed_column</>
|
||||||
|
<replaceable>operator</>
|
||||||
|
<replaceable>constant</>.
|
||||||
|
Such an operator could return any sortable data type, though again
|
||||||
|
its left-hand input type must match the index's column data type.
|
||||||
|
The exact semantics of the <literal>ORDER BY</> are specified by the
|
||||||
|
<structfield>amopsortfamily</structfield> column, which must reference
|
||||||
|
a btree operator family for the operator's result type.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<note>
|
||||||
|
<para>
|
||||||
|
At present, it's assumed that the sort order for an ordering operator
|
||||||
|
is the default for the referenced opfamily, i.e., <literal>ASC NULLS
|
||||||
|
LAST</>. This might someday be relaxed by adding additional columns
|
||||||
|
to specify sort options explicitly.
|
||||||
|
</para>
|
||||||
|
</note>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
An entry's <structfield>amopmethod</> must match the
|
An entry's <structfield>amopmethod</> must match the
|
||||||
<structname>opfmethod</> of its containing operator family (including
|
<structname>opfmethod</> of its containing operator family (including
|
||||||
|
@ -22,7 +22,7 @@ PostgreSQL documentation
|
|||||||
<refsynopsisdiv>
|
<refsynopsisdiv>
|
||||||
<synopsis>
|
<synopsis>
|
||||||
ALTER OPERATOR FAMILY <replaceable>name</replaceable> USING <replaceable class="parameter">index_method</replaceable> ADD
|
ALTER OPERATOR FAMILY <replaceable>name</replaceable> USING <replaceable class="parameter">index_method</replaceable> ADD
|
||||||
{ 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> )
|
{ 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> [, ...] )
|
| 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> [, ...] )
|
||||||
} [, ... ]
|
} [, ... ]
|
||||||
ALTER OPERATOR FAMILY <replaceable>name</replaceable> USING <replaceable class="parameter">index_method</replaceable> DROP
|
ALTER OPERATOR FAMILY <replaceable>name</replaceable> USING <replaceable class="parameter">index_method</replaceable> DROP
|
||||||
@ -154,6 +154,22 @@ ALTER OPERATOR FAMILY <replaceable>name</replaceable> USING <replaceable class="
|
|||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><replaceable class="parameter">sort_family_name</replaceable></term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
The name (optionally schema-qualified) of an existing btree operator
|
||||||
|
family that describes the sort ordering associated with an ordering
|
||||||
|
operator.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
If neither <literal>FOR SEARCH</> nor <literal>FOR ORDER BY</> is
|
||||||
|
specified, <literal>FOR SEARCH</> is the default.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><replaceable class="parameter">support_number</replaceable></term>
|
<term><replaceable class="parameter">support_number</replaceable></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
|
@ -23,7 +23,7 @@ PostgreSQL documentation
|
|||||||
<synopsis>
|
<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 ] FOR TYPE <replaceable class="parameter">data_type</replaceable>
|
||||||
USING <replaceable class="parameter">index_method</replaceable> [ FAMILY <replaceable class="parameter">family_name</replaceable> ] AS
|
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> ) ]
|
{ 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> [, ...] )
|
| 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> [, ...] )
|
||||||
| STORAGE <replaceable class="parameter">storage_type</replaceable>
|
| STORAGE <replaceable class="parameter">storage_type</replaceable>
|
||||||
} [, ... ]
|
} [, ... ]
|
||||||
@ -180,6 +180,22 @@ CREATE OPERATOR CLASS <replaceable class="parameter">name</replaceable> [ DEFAUL
|
|||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><replaceable class="parameter">sort_family_name</replaceable></term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
The name (optionally schema-qualified) of an existing btree operator
|
||||||
|
family that describes the sort ordering associated with an ordering
|
||||||
|
operator.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
If neither <literal>FOR SEARCH</> nor <literal>FOR ORDER BY</> is
|
||||||
|
specified, <literal>FOR SEARCH</> is the default.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><replaceable class="parameter">support_number</replaceable></term>
|
<term><replaceable class="parameter">support_number</replaceable></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
|
@ -276,10 +276,13 @@
|
|||||||
</table>
|
</table>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Notice that all strategy operators return Boolean values. In
|
Notice that all the operators listed above return Boolean values. In
|
||||||
practice, all operators defined as index method strategies must
|
practice, all operators defined as index method search operators must
|
||||||
return type <type>boolean</type>, since they must appear at the top
|
return type <type>boolean</type>, since they must appear at the top
|
||||||
level of a <literal>WHERE</> clause to be used with an index.
|
level of a <literal>WHERE</> clause to be used with an index.
|
||||||
|
(Some index access methods also support <firstterm>ordering operators</>,
|
||||||
|
which typically don't return Boolean values; that feature is discussed
|
||||||
|
in <xref linkend="xindex-ordering-ops">.)
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
@ -464,7 +467,7 @@
|
|||||||
</table>
|
</table>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Unlike strategy operators, support functions return whichever data
|
Unlike search operators, support functions return whichever data
|
||||||
type the particular index method expects; for example in the case
|
type the particular index method expects; for example in the case
|
||||||
of the comparison function for B-trees, a signed integer. The number
|
of the comparison function for B-trees, a signed integer. The number
|
||||||
and types of the arguments to each support function are likewise
|
and types of the arguments to each support function are likewise
|
||||||
@ -921,6 +924,62 @@ ALTER OPERATOR FAMILY integer_ops USING btree ADD
|
|||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
|
<sect2 id="xindex-ordering-ops">
|
||||||
|
<title>Ordering Operators</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Some index access methods (currently, only GiST) support the concept of
|
||||||
|
<firstterm>ordering operators</>. What we have been discussing so far
|
||||||
|
are <firstterm>search operators</>. A search operator is one for which
|
||||||
|
the index can be searched to find all rows satisfying
|
||||||
|
<literal>WHERE</>
|
||||||
|
<replaceable>indexed_column</>
|
||||||
|
<replaceable>operator</>
|
||||||
|
<replaceable>constant</>.
|
||||||
|
Note that nothing is promised about the order in which the matching rows
|
||||||
|
will be returned. In contrast, an ordering operator does not restrict the
|
||||||
|
set of rows that can be returned, but instead determines their order.
|
||||||
|
An ordering operator is one for which the index can be scanned to return
|
||||||
|
rows in the order represented by
|
||||||
|
<literal>ORDER BY</>
|
||||||
|
<replaceable>indexed_column</>
|
||||||
|
<replaceable>operator</>
|
||||||
|
<replaceable>constant</>.
|
||||||
|
The reason for defining ordering operators that way is that it supports
|
||||||
|
nearest-neighbor searches, if the operator is one that measures distance.
|
||||||
|
For example, a query like
|
||||||
|
<programlisting><![CDATA[
|
||||||
|
SELECT * FROM places ORDER BY location <-> point '(101,456)' LIMIT 10;
|
||||||
|
]]>
|
||||||
|
</programlisting>
|
||||||
|
finds the ten places closest to a given target point. A GiST index
|
||||||
|
on the location column can do this efficiently because
|
||||||
|
<literal><-></> is an ordering operator.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
While search operators have to return Boolean results, ordering operators
|
||||||
|
usually return some other type, such as float or numeric for distances.
|
||||||
|
This type is normally not the same as the data type being indexed.
|
||||||
|
To avoid hard-wiring assumptions about the behavior of different data
|
||||||
|
types, the definition of an ordering operator is required to name
|
||||||
|
a B-tree operator family that specifies the sort ordering of the result
|
||||||
|
data type. As was stated in the previous section, B-tree operator families
|
||||||
|
define <productname>PostgreSQL</productname>'s notion of ordering, so
|
||||||
|
this is a natural representation. Since the point <literal><-></>
|
||||||
|
operator returns <type>float8</>, it could be specified in an operator
|
||||||
|
class creation command like this:
|
||||||
|
<programlisting><![CDATA[
|
||||||
|
OPERATOR 15 <-> (point, point) FOR ORDER BY float_ops
|
||||||
|
]]>
|
||||||
|
</programlisting>
|
||||||
|
where <literal>float_ops</> is the built-in operator family that includes
|
||||||
|
operations on <type>float8</>. This declaration states that the index
|
||||||
|
is able to return rows in order of increasing values of the
|
||||||
|
<literal><-></> operator.
|
||||||
|
</para>
|
||||||
|
</sect2>
|
||||||
|
|
||||||
<sect2 id="xindex-opclass-features">
|
<sect2 id="xindex-opclass-features">
|
||||||
<title>Special Features of Operator Classes</title>
|
<title>Special Features of Operator Classes</title>
|
||||||
|
|
||||||
|
@ -54,6 +54,7 @@ typedef struct
|
|||||||
int number; /* strategy or support proc number */
|
int number; /* strategy or support proc number */
|
||||||
Oid lefttype; /* lefttype */
|
Oid lefttype; /* lefttype */
|
||||||
Oid righttype; /* righttype */
|
Oid righttype; /* righttype */
|
||||||
|
Oid sortfamily; /* ordering operator's sort opfamily, or 0 */
|
||||||
} OpFamilyMember;
|
} OpFamilyMember;
|
||||||
|
|
||||||
|
|
||||||
@ -457,6 +458,7 @@ DefineOpClass(CreateOpClassStmt *stmt)
|
|||||||
CreateOpClassItem *item = lfirst(l);
|
CreateOpClassItem *item = lfirst(l);
|
||||||
Oid operOid;
|
Oid operOid;
|
||||||
Oid funcOid;
|
Oid funcOid;
|
||||||
|
Oid sortfamilyOid;
|
||||||
OpFamilyMember *member;
|
OpFamilyMember *member;
|
||||||
|
|
||||||
Assert(IsA(item, CreateOpClassItem));
|
Assert(IsA(item, CreateOpClassItem));
|
||||||
@ -486,6 +488,13 @@ DefineOpClass(CreateOpClassStmt *stmt)
|
|||||||
false, -1);
|
false, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (item->order_family)
|
||||||
|
sortfamilyOid = get_opfamily_oid(BTREE_AM_OID,
|
||||||
|
item->order_family,
|
||||||
|
false);
|
||||||
|
else
|
||||||
|
sortfamilyOid = InvalidOid;
|
||||||
|
|
||||||
#ifdef NOT_USED
|
#ifdef NOT_USED
|
||||||
/* XXX this is unnecessary given the superuser check above */
|
/* XXX this is unnecessary given the superuser check above */
|
||||||
/* Caller must own operator and its underlying function */
|
/* Caller must own operator and its underlying function */
|
||||||
@ -502,6 +511,7 @@ DefineOpClass(CreateOpClassStmt *stmt)
|
|||||||
member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
|
member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
|
||||||
member->object = operOid;
|
member->object = operOid;
|
||||||
member->number = item->number;
|
member->number = item->number;
|
||||||
|
member->sortfamily = sortfamilyOid;
|
||||||
assignOperTypes(member, amoid, typeoid);
|
assignOperTypes(member, amoid, typeoid);
|
||||||
addFamilyMember(&operators, member, false);
|
addFamilyMember(&operators, member, false);
|
||||||
break;
|
break;
|
||||||
@ -825,6 +835,7 @@ AlterOpFamilyAdd(List *opfamilyname, Oid amoid, Oid opfamilyoid,
|
|||||||
CreateOpClassItem *item = lfirst(l);
|
CreateOpClassItem *item = lfirst(l);
|
||||||
Oid operOid;
|
Oid operOid;
|
||||||
Oid funcOid;
|
Oid funcOid;
|
||||||
|
Oid sortfamilyOid;
|
||||||
OpFamilyMember *member;
|
OpFamilyMember *member;
|
||||||
|
|
||||||
Assert(IsA(item, CreateOpClassItem));
|
Assert(IsA(item, CreateOpClassItem));
|
||||||
@ -854,6 +865,13 @@ AlterOpFamilyAdd(List *opfamilyname, Oid amoid, Oid opfamilyoid,
|
|||||||
operOid = InvalidOid; /* keep compiler quiet */
|
operOid = InvalidOid; /* keep compiler quiet */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (item->order_family)
|
||||||
|
sortfamilyOid = get_opfamily_oid(BTREE_AM_OID,
|
||||||
|
item->order_family,
|
||||||
|
false);
|
||||||
|
else
|
||||||
|
sortfamilyOid = InvalidOid;
|
||||||
|
|
||||||
#ifdef NOT_USED
|
#ifdef NOT_USED
|
||||||
/* XXX this is unnecessary given the superuser check above */
|
/* XXX this is unnecessary given the superuser check above */
|
||||||
/* Caller must own operator and its underlying function */
|
/* Caller must own operator and its underlying function */
|
||||||
@ -870,6 +888,7 @@ AlterOpFamilyAdd(List *opfamilyname, Oid amoid, Oid opfamilyoid,
|
|||||||
member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
|
member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
|
||||||
member->object = operOid;
|
member->object = operOid;
|
||||||
member->number = item->number;
|
member->number = item->number;
|
||||||
|
member->sortfamily = sortfamilyOid;
|
||||||
assignOperTypes(member, amoid, InvalidOid);
|
assignOperTypes(member, amoid, InvalidOid);
|
||||||
addFamilyMember(&operators, member, false);
|
addFamilyMember(&operators, member, false);
|
||||||
break;
|
break;
|
||||||
@ -1043,16 +1062,51 @@ assignOperTypes(OpFamilyMember *member, Oid amoid, Oid typeoid)
|
|||||||
opform = (Form_pg_operator) GETSTRUCT(optup);
|
opform = (Form_pg_operator) GETSTRUCT(optup);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Opfamily operators must be binary ops returning boolean.
|
* Opfamily operators must be binary.
|
||||||
*/
|
*/
|
||||||
if (opform->oprkind != 'b')
|
if (opform->oprkind != 'b')
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
||||||
errmsg("index operators must be binary")));
|
errmsg("index operators must be binary")));
|
||||||
if (opform->oprresult != BOOLOID)
|
|
||||||
ereport(ERROR,
|
if (OidIsValid(member->sortfamily))
|
||||||
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
{
|
||||||
errmsg("index operators must return boolean")));
|
/*
|
||||||
|
* Ordering op, check index supports that. (We could perhaps also
|
||||||
|
* check that the operator returns a type supported by the sortfamily,
|
||||||
|
* but that seems more trouble than it's worth here. If it does not,
|
||||||
|
* the operator will never be matchable to any ORDER BY clause, but
|
||||||
|
* no worse consequences can ensue. Also, trying to check that would
|
||||||
|
* create an ordering hazard during dump/reload: it's possible that
|
||||||
|
* the family has been created but not yet populated with the required
|
||||||
|
* operators.)
|
||||||
|
*/
|
||||||
|
HeapTuple amtup;
|
||||||
|
Form_pg_am pg_am;
|
||||||
|
|
||||||
|
amtup = SearchSysCache1(AMOID, ObjectIdGetDatum(amoid));
|
||||||
|
if (amtup == NULL)
|
||||||
|
elog(ERROR, "cache lookup failed for access method %u", amoid);
|
||||||
|
pg_am = (Form_pg_am) GETSTRUCT(amtup);
|
||||||
|
|
||||||
|
if (!pg_am->amcanorderbyop)
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
||||||
|
errmsg("access method \"%s\" does not support ordering operators",
|
||||||
|
NameStr(pg_am->amname))));
|
||||||
|
|
||||||
|
ReleaseSysCache(amtup);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Search operators must return boolean.
|
||||||
|
*/
|
||||||
|
if (opform->oprresult != BOOLOID)
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
||||||
|
errmsg("index search operators must return boolean")));
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If lefttype/righttype isn't specified, use the operator's input types
|
* If lefttype/righttype isn't specified, use the operator's input types
|
||||||
@ -1206,6 +1260,7 @@ storeOperators(List *opfamilyname, Oid amoid,
|
|||||||
foreach(l, operators)
|
foreach(l, operators)
|
||||||
{
|
{
|
||||||
OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
|
OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
|
||||||
|
char oppurpose;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If adding to an existing family, check for conflict with an
|
* If adding to an existing family, check for conflict with an
|
||||||
@ -1225,6 +1280,8 @@ storeOperators(List *opfamilyname, Oid amoid,
|
|||||||
format_type_be(op->righttype),
|
format_type_be(op->righttype),
|
||||||
NameListToString(opfamilyname))));
|
NameListToString(opfamilyname))));
|
||||||
|
|
||||||
|
oppurpose = OidIsValid(op->sortfamily) ? AMOP_ORDER : AMOP_SEARCH;
|
||||||
|
|
||||||
/* Create the pg_amop entry */
|
/* Create the pg_amop entry */
|
||||||
memset(values, 0, sizeof(values));
|
memset(values, 0, sizeof(values));
|
||||||
memset(nulls, false, sizeof(nulls));
|
memset(nulls, false, sizeof(nulls));
|
||||||
@ -1233,8 +1290,10 @@ storeOperators(List *opfamilyname, Oid amoid,
|
|||||||
values[Anum_pg_amop_amoplefttype - 1] = ObjectIdGetDatum(op->lefttype);
|
values[Anum_pg_amop_amoplefttype - 1] = ObjectIdGetDatum(op->lefttype);
|
||||||
values[Anum_pg_amop_amoprighttype - 1] = ObjectIdGetDatum(op->righttype);
|
values[Anum_pg_amop_amoprighttype - 1] = ObjectIdGetDatum(op->righttype);
|
||||||
values[Anum_pg_amop_amopstrategy - 1] = Int16GetDatum(op->number);
|
values[Anum_pg_amop_amopstrategy - 1] = Int16GetDatum(op->number);
|
||||||
|
values[Anum_pg_amop_amoppurpose - 1] = CharGetDatum(oppurpose);
|
||||||
values[Anum_pg_amop_amopopr - 1] = ObjectIdGetDatum(op->object);
|
values[Anum_pg_amop_amopopr - 1] = ObjectIdGetDatum(op->object);
|
||||||
values[Anum_pg_amop_amopmethod - 1] = ObjectIdGetDatum(amoid);
|
values[Anum_pg_amop_amopmethod - 1] = ObjectIdGetDatum(amoid);
|
||||||
|
values[Anum_pg_amop_amopsortfamily - 1] = ObjectIdGetDatum(op->sortfamily);
|
||||||
|
|
||||||
tup = heap_form_tuple(rel->rd_att, values, nulls);
|
tup = heap_form_tuple(rel->rd_att, values, nulls);
|
||||||
|
|
||||||
@ -1275,6 +1334,15 @@ storeOperators(List *opfamilyname, Oid amoid,
|
|||||||
referenced.objectSubId = 0;
|
referenced.objectSubId = 0;
|
||||||
recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
|
recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* A search operator also needs a dep on the referenced opfamily */
|
||||||
|
if (OidIsValid(op->sortfamily))
|
||||||
|
{
|
||||||
|
referenced.classId = OperatorFamilyRelationId;
|
||||||
|
referenced.objectId = op->sortfamily;
|
||||||
|
referenced.objectSubId = 0;
|
||||||
|
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
heap_close(rel, RowExclusiveLock);
|
heap_close(rel, RowExclusiveLock);
|
||||||
|
@ -2991,6 +2991,7 @@ _copyCreateOpClassItem(CreateOpClassItem *from)
|
|||||||
COPY_NODE_FIELD(name);
|
COPY_NODE_FIELD(name);
|
||||||
COPY_NODE_FIELD(args);
|
COPY_NODE_FIELD(args);
|
||||||
COPY_SCALAR_FIELD(number);
|
COPY_SCALAR_FIELD(number);
|
||||||
|
COPY_NODE_FIELD(order_family);
|
||||||
COPY_NODE_FIELD(class_args);
|
COPY_NODE_FIELD(class_args);
|
||||||
COPY_NODE_FIELD(storedtype);
|
COPY_NODE_FIELD(storedtype);
|
||||||
|
|
||||||
|
@ -1464,6 +1464,7 @@ _equalCreateOpClassItem(CreateOpClassItem *a, CreateOpClassItem *b)
|
|||||||
COMPARE_NODE_FIELD(name);
|
COMPARE_NODE_FIELD(name);
|
||||||
COMPARE_NODE_FIELD(args);
|
COMPARE_NODE_FIELD(args);
|
||||||
COMPARE_SCALAR_FIELD(number);
|
COMPARE_SCALAR_FIELD(number);
|
||||||
|
COMPARE_NODE_FIELD(order_family);
|
||||||
COMPARE_NODE_FIELD(class_args);
|
COMPARE_NODE_FIELD(class_args);
|
||||||
COMPARE_NODE_FIELD(storedtype);
|
COMPARE_NODE_FIELD(storedtype);
|
||||||
|
|
||||||
|
@ -212,6 +212,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
|
|||||||
|
|
||||||
info->relam = indexRelation->rd_rel->relam;
|
info->relam = indexRelation->rd_rel->relam;
|
||||||
info->amcostestimate = indexRelation->rd_am->amcostestimate;
|
info->amcostestimate = indexRelation->rd_am->amcostestimate;
|
||||||
|
info->amcanorderbyop = indexRelation->rd_am->amcanorderbyop;
|
||||||
info->amoptionalkey = indexRelation->rd_am->amoptionalkey;
|
info->amoptionalkey = indexRelation->rd_am->amoptionalkey;
|
||||||
info->amsearchnulls = indexRelation->rd_am->amsearchnulls;
|
info->amsearchnulls = indexRelation->rd_am->amsearchnulls;
|
||||||
info->amhasgettuple = OidIsValid(indexRelation->rd_am->amgettuple);
|
info->amhasgettuple = OidIsValid(indexRelation->rd_am->amgettuple);
|
||||||
|
@ -1661,8 +1661,9 @@ get_btree_test_op(Oid pred_op, Oid clause_op, bool refute_it)
|
|||||||
* From the same opfamily, find a strategy number for the clause_op,
|
* From the same opfamily, find a strategy number for the clause_op,
|
||||||
* if possible
|
* if possible
|
||||||
*/
|
*/
|
||||||
clause_tuple = SearchSysCache2(AMOPOPID,
|
clause_tuple = SearchSysCache3(AMOPOPID,
|
||||||
ObjectIdGetDatum(clause_op),
|
ObjectIdGetDatum(clause_op),
|
||||||
|
CharGetDatum(AMOP_SEARCH),
|
||||||
ObjectIdGetDatum(opfamily_id));
|
ObjectIdGetDatum(opfamily_id));
|
||||||
if (HeapTupleIsValid(clause_tuple))
|
if (HeapTupleIsValid(clause_tuple))
|
||||||
{
|
{
|
||||||
@ -1677,8 +1678,9 @@ get_btree_test_op(Oid pred_op, Oid clause_op, bool refute_it)
|
|||||||
}
|
}
|
||||||
else if (OidIsValid(clause_op_negator))
|
else if (OidIsValid(clause_op_negator))
|
||||||
{
|
{
|
||||||
clause_tuple = SearchSysCache2(AMOPOPID,
|
clause_tuple = SearchSysCache3(AMOPOPID,
|
||||||
ObjectIdGetDatum(clause_op_negator),
|
ObjectIdGetDatum(clause_op_negator),
|
||||||
|
CharGetDatum(AMOP_SEARCH),
|
||||||
ObjectIdGetDatum(opfamily_id));
|
ObjectIdGetDatum(opfamily_id));
|
||||||
if (HeapTupleIsValid(clause_tuple))
|
if (HeapTupleIsValid(clause_tuple))
|
||||||
{
|
{
|
||||||
|
@ -295,7 +295,7 @@ static RangeVar *makeRangeVarFromAnyName(List *names, int position, core_yyscan_
|
|||||||
ctext_expr_list ctext_row def_list indirection opt_indirection
|
ctext_expr_list ctext_row def_list indirection opt_indirection
|
||||||
reloption_list group_clause TriggerFuncArgs select_limit
|
reloption_list group_clause TriggerFuncArgs select_limit
|
||||||
opt_select_limit opclass_item_list opclass_drop_list
|
opt_select_limit opclass_item_list opclass_drop_list
|
||||||
opt_opfamily transaction_mode_list_or_empty
|
opclass_purpose opt_opfamily transaction_mode_list_or_empty
|
||||||
OptTableFuncElementList TableFuncElementList opt_type_modifiers
|
OptTableFuncElementList TableFuncElementList opt_type_modifiers
|
||||||
prep_type_clause
|
prep_type_clause
|
||||||
execute_param_clause using_clause returning_clause
|
execute_param_clause using_clause returning_clause
|
||||||
@ -3935,22 +3935,25 @@ opclass_item_list:
|
|||||||
;
|
;
|
||||||
|
|
||||||
opclass_item:
|
opclass_item:
|
||||||
OPERATOR Iconst any_operator opt_recheck
|
OPERATOR Iconst any_operator opclass_purpose opt_recheck
|
||||||
{
|
{
|
||||||
CreateOpClassItem *n = makeNode(CreateOpClassItem);
|
CreateOpClassItem *n = makeNode(CreateOpClassItem);
|
||||||
n->itemtype = OPCLASS_ITEM_OPERATOR;
|
n->itemtype = OPCLASS_ITEM_OPERATOR;
|
||||||
n->name = $3;
|
n->name = $3;
|
||||||
n->args = NIL;
|
n->args = NIL;
|
||||||
n->number = $2;
|
n->number = $2;
|
||||||
|
n->order_family = $4;
|
||||||
$$ = (Node *) n;
|
$$ = (Node *) n;
|
||||||
}
|
}
|
||||||
| OPERATOR Iconst any_operator oper_argtypes opt_recheck
|
| OPERATOR Iconst any_operator oper_argtypes opclass_purpose
|
||||||
|
opt_recheck
|
||||||
{
|
{
|
||||||
CreateOpClassItem *n = makeNode(CreateOpClassItem);
|
CreateOpClassItem *n = makeNode(CreateOpClassItem);
|
||||||
n->itemtype = OPCLASS_ITEM_OPERATOR;
|
n->itemtype = OPCLASS_ITEM_OPERATOR;
|
||||||
n->name = $3;
|
n->name = $3;
|
||||||
n->args = $4;
|
n->args = $4;
|
||||||
n->number = $2;
|
n->number = $2;
|
||||||
|
n->order_family = $5;
|
||||||
$$ = (Node *) n;
|
$$ = (Node *) n;
|
||||||
}
|
}
|
||||||
| FUNCTION Iconst func_name func_args
|
| FUNCTION Iconst func_name func_args
|
||||||
@ -3989,6 +3992,11 @@ opt_opfamily: FAMILY any_name { $$ = $2; }
|
|||||||
| /*EMPTY*/ { $$ = NIL; }
|
| /*EMPTY*/ { $$ = NIL; }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
opclass_purpose: FOR SEARCH { $$ = NIL; }
|
||||||
|
| FOR ORDER BY any_name { $$ = $4; }
|
||||||
|
| /*EMPTY*/ { $$ = NIL; }
|
||||||
|
;
|
||||||
|
|
||||||
opt_recheck: RECHECK
|
opt_recheck: RECHECK
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
15
src/backend/utils/cache/lsyscache.c
vendored
15
src/backend/utils/cache/lsyscache.c
vendored
@ -46,12 +46,15 @@ get_attavgwidth_hook_type get_attavgwidth_hook = NULL;
|
|||||||
* op_in_opfamily
|
* op_in_opfamily
|
||||||
*
|
*
|
||||||
* Return t iff operator 'opno' is in operator family 'opfamily'.
|
* Return t iff operator 'opno' is in operator family 'opfamily'.
|
||||||
|
*
|
||||||
|
* This function only considers search operators, not ordering operators.
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
op_in_opfamily(Oid opno, Oid opfamily)
|
op_in_opfamily(Oid opno, Oid opfamily)
|
||||||
{
|
{
|
||||||
return SearchSysCacheExists2(AMOPOPID,
|
return SearchSysCacheExists3(AMOPOPID,
|
||||||
ObjectIdGetDatum(opno),
|
ObjectIdGetDatum(opno),
|
||||||
|
CharGetDatum(AMOP_SEARCH),
|
||||||
ObjectIdGetDatum(opfamily));
|
ObjectIdGetDatum(opfamily));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,6 +63,8 @@ op_in_opfamily(Oid opno, Oid opfamily)
|
|||||||
*
|
*
|
||||||
* Get the operator's strategy number within the specified opfamily,
|
* Get the operator's strategy number within the specified opfamily,
|
||||||
* or 0 if it's not a member of the opfamily.
|
* or 0 if it's not a member of the opfamily.
|
||||||
|
*
|
||||||
|
* This function only considers search operators, not ordering operators.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
get_op_opfamily_strategy(Oid opno, Oid opfamily)
|
get_op_opfamily_strategy(Oid opno, Oid opfamily)
|
||||||
@ -68,8 +73,9 @@ get_op_opfamily_strategy(Oid opno, Oid opfamily)
|
|||||||
Form_pg_amop amop_tup;
|
Form_pg_amop amop_tup;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
tp = SearchSysCache2(AMOPOPID,
|
tp = SearchSysCache3(AMOPOPID,
|
||||||
ObjectIdGetDatum(opno),
|
ObjectIdGetDatum(opno),
|
||||||
|
CharGetDatum(AMOP_SEARCH),
|
||||||
ObjectIdGetDatum(opfamily));
|
ObjectIdGetDatum(opfamily));
|
||||||
if (!HeapTupleIsValid(tp))
|
if (!HeapTupleIsValid(tp))
|
||||||
return 0;
|
return 0;
|
||||||
@ -85,6 +91,8 @@ get_op_opfamily_strategy(Oid opno, Oid opfamily)
|
|||||||
* Get the operator's strategy number and declared input data types
|
* Get the operator's strategy number and declared input data types
|
||||||
* within the specified opfamily.
|
* within the specified opfamily.
|
||||||
*
|
*
|
||||||
|
* This function only considers search operators, not ordering operators.
|
||||||
|
*
|
||||||
* Caller should already have verified that opno is a member of opfamily,
|
* Caller should already have verified that opno is a member of opfamily,
|
||||||
* therefore we raise an error if the tuple is not found.
|
* therefore we raise an error if the tuple is not found.
|
||||||
*/
|
*/
|
||||||
@ -97,8 +105,9 @@ get_op_opfamily_properties(Oid opno, Oid opfamily,
|
|||||||
HeapTuple tp;
|
HeapTuple tp;
|
||||||
Form_pg_amop amop_tup;
|
Form_pg_amop amop_tup;
|
||||||
|
|
||||||
tp = SearchSysCache2(AMOPOPID,
|
tp = SearchSysCache3(AMOPOPID,
|
||||||
ObjectIdGetDatum(opno),
|
ObjectIdGetDatum(opno),
|
||||||
|
CharGetDatum(AMOP_SEARCH),
|
||||||
ObjectIdGetDatum(opfamily));
|
ObjectIdGetDatum(opfamily));
|
||||||
if (!HeapTupleIsValid(tp))
|
if (!HeapTupleIsValid(tp))
|
||||||
elog(ERROR, "operator %u is not a member of opfamily %u",
|
elog(ERROR, "operator %u is not a member of opfamily %u",
|
||||||
|
4
src/backend/utils/cache/syscache.c
vendored
4
src/backend/utils/cache/syscache.c
vendored
@ -135,11 +135,11 @@ static const struct cachedesc cacheinfo[] = {
|
|||||||
},
|
},
|
||||||
{AccessMethodOperatorRelationId, /* AMOPOPID */
|
{AccessMethodOperatorRelationId, /* AMOPOPID */
|
||||||
AccessMethodOperatorIndexId,
|
AccessMethodOperatorIndexId,
|
||||||
2,
|
3,
|
||||||
{
|
{
|
||||||
Anum_pg_amop_amopopr,
|
Anum_pg_amop_amopopr,
|
||||||
|
Anum_pg_amop_amoppurpose,
|
||||||
Anum_pg_amop_amopfamily,
|
Anum_pg_amop_amopfamily,
|
||||||
0,
|
|
||||||
0
|
0
|
||||||
},
|
},
|
||||||
64
|
64
|
||||||
|
@ -8815,22 +8815,28 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
|
|||||||
int i_opckeytype;
|
int i_opckeytype;
|
||||||
int i_opcdefault;
|
int i_opcdefault;
|
||||||
int i_opcfamily;
|
int i_opcfamily;
|
||||||
|
int i_opcfamilyname;
|
||||||
int i_opcfamilynsp;
|
int i_opcfamilynsp;
|
||||||
int i_amname;
|
int i_amname;
|
||||||
int i_amopstrategy;
|
int i_amopstrategy;
|
||||||
int i_amopreqcheck;
|
int i_amopreqcheck;
|
||||||
int i_amopopr;
|
int i_amopopr;
|
||||||
|
int i_sortfamily;
|
||||||
|
int i_sortfamilynsp;
|
||||||
int i_amprocnum;
|
int i_amprocnum;
|
||||||
int i_amproc;
|
int i_amproc;
|
||||||
char *opcintype;
|
char *opcintype;
|
||||||
char *opckeytype;
|
char *opckeytype;
|
||||||
char *opcdefault;
|
char *opcdefault;
|
||||||
char *opcfamily;
|
char *opcfamily;
|
||||||
|
char *opcfamilyname;
|
||||||
char *opcfamilynsp;
|
char *opcfamilynsp;
|
||||||
char *amname;
|
char *amname;
|
||||||
char *amopstrategy;
|
char *amopstrategy;
|
||||||
char *amopreqcheck;
|
char *amopreqcheck;
|
||||||
char *amopopr;
|
char *amopopr;
|
||||||
|
char *sortfamily;
|
||||||
|
char *sortfamilynsp;
|
||||||
char *amprocnum;
|
char *amprocnum;
|
||||||
char *amproc;
|
char *amproc;
|
||||||
bool needComma;
|
bool needComma;
|
||||||
@ -8860,8 +8866,8 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
|
|||||||
{
|
{
|
||||||
appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
|
appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
|
||||||
"opckeytype::pg_catalog.regtype, "
|
"opckeytype::pg_catalog.regtype, "
|
||||||
"opcdefault, "
|
"opcdefault, opcfamily, "
|
||||||
"opfname AS opcfamily, "
|
"opfname AS opcfamilyname, "
|
||||||
"nspname AS opcfamilynsp, "
|
"nspname AS opcfamilynsp, "
|
||||||
"(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
|
"(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
|
||||||
"FROM pg_catalog.pg_opclass c "
|
"FROM pg_catalog.pg_opclass c "
|
||||||
@ -8874,8 +8880,8 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
|
|||||||
{
|
{
|
||||||
appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
|
appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
|
||||||
"opckeytype::pg_catalog.regtype, "
|
"opckeytype::pg_catalog.regtype, "
|
||||||
"opcdefault, "
|
"opcdefault, NULL AS opcfamily, "
|
||||||
"NULL AS opcfamily, "
|
"NULL AS opcfamilyname, "
|
||||||
"NULL AS opcfamilynsp, "
|
"NULL AS opcfamilynsp, "
|
||||||
"(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcamid) AS amname "
|
"(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcamid) AS amname "
|
||||||
"FROM pg_catalog.pg_opclass "
|
"FROM pg_catalog.pg_opclass "
|
||||||
@ -8901,13 +8907,16 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
|
|||||||
i_opckeytype = PQfnumber(res, "opckeytype");
|
i_opckeytype = PQfnumber(res, "opckeytype");
|
||||||
i_opcdefault = PQfnumber(res, "opcdefault");
|
i_opcdefault = PQfnumber(res, "opcdefault");
|
||||||
i_opcfamily = PQfnumber(res, "opcfamily");
|
i_opcfamily = PQfnumber(res, "opcfamily");
|
||||||
|
i_opcfamilyname = PQfnumber(res, "opcfamilyname");
|
||||||
i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
|
i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
|
||||||
i_amname = PQfnumber(res, "amname");
|
i_amname = PQfnumber(res, "amname");
|
||||||
|
|
||||||
opcintype = PQgetvalue(res, 0, i_opcintype);
|
opcintype = PQgetvalue(res, 0, i_opcintype);
|
||||||
opckeytype = PQgetvalue(res, 0, i_opckeytype);
|
opckeytype = PQgetvalue(res, 0, i_opckeytype);
|
||||||
opcdefault = PQgetvalue(res, 0, i_opcdefault);
|
opcdefault = PQgetvalue(res, 0, i_opcdefault);
|
||||||
opcfamily = PQgetvalue(res, 0, i_opcfamily);
|
/* opcfamily will still be needed after we PQclear res */
|
||||||
|
opcfamily = strdup(PQgetvalue(res, 0, i_opcfamily));
|
||||||
|
opcfamilyname = PQgetvalue(res, 0, i_opcfamilyname);
|
||||||
opcfamilynsp = PQgetvalue(res, 0, i_opcfamilynsp);
|
opcfamilynsp = PQgetvalue(res, 0, i_opcfamilynsp);
|
||||||
/* amname will still be needed after we PQclear res */
|
/* amname will still be needed after we PQclear res */
|
||||||
amname = strdup(PQgetvalue(res, 0, i_amname));
|
amname = strdup(PQgetvalue(res, 0, i_amname));
|
||||||
@ -8930,14 +8939,14 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
|
|||||||
appendPQExpBuffer(q, "FOR TYPE %s USING %s",
|
appendPQExpBuffer(q, "FOR TYPE %s USING %s",
|
||||||
opcintype,
|
opcintype,
|
||||||
fmtId(amname));
|
fmtId(amname));
|
||||||
if (strlen(opcfamily) > 0 &&
|
if (strlen(opcfamilyname) > 0 &&
|
||||||
(strcmp(opcfamily, opcinfo->dobj.name) != 0 ||
|
(strcmp(opcfamilyname, opcinfo->dobj.name) != 0 ||
|
||||||
strcmp(opcfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0))
|
strcmp(opcfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0))
|
||||||
{
|
{
|
||||||
appendPQExpBuffer(q, " FAMILY ");
|
appendPQExpBuffer(q, " FAMILY ");
|
||||||
if (strcmp(opcfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0)
|
if (strcmp(opcfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0)
|
||||||
appendPQExpBuffer(q, "%s.", fmtId(opcfamilynsp));
|
appendPQExpBuffer(q, "%s.", fmtId(opcfamilynsp));
|
||||||
appendPQExpBuffer(q, "%s", fmtId(opcfamily));
|
appendPQExpBuffer(q, "%s", fmtId(opcfamilyname));
|
||||||
}
|
}
|
||||||
appendPQExpBuffer(q, " AS\n ");
|
appendPQExpBuffer(q, " AS\n ");
|
||||||
|
|
||||||
@ -8954,23 +8963,41 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Now fetch and print the OPERATOR entries (pg_amop rows).
|
* Now fetch and print the OPERATOR entries (pg_amop rows).
|
||||||
|
*
|
||||||
|
* Print only those opfamily members that are tied to the opclass by
|
||||||
|
* pg_depend entries.
|
||||||
|
*
|
||||||
|
* XXX RECHECK is gone as of 8.4, but we'll still print it if dumping
|
||||||
|
* an older server's opclass in which it is used. This is to avoid
|
||||||
|
* hard-to-detect breakage if a newer pg_dump is used to dump from an
|
||||||
|
* older server and then reload into that old version. This can go
|
||||||
|
* away once 8.3 is so old as to not be of interest to anyone.
|
||||||
*/
|
*/
|
||||||
resetPQExpBuffer(query);
|
resetPQExpBuffer(query);
|
||||||
|
|
||||||
if (g_fout->remoteVersion >= 80400)
|
if (g_fout->remoteVersion >= 90100)
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
* Print only those opfamily members that are tied to the opclass by
|
|
||||||
* pg_depend entries.
|
|
||||||
*
|
|
||||||
* XXX RECHECK is gone as of 8.4, but we'll still print it if dumping
|
|
||||||
* an older server's opclass in which it is used. This is to avoid
|
|
||||||
* hard-to-detect breakage if a newer pg_dump is used to dump from an
|
|
||||||
* older server and then reload into that old version. This can go
|
|
||||||
* away once 8.3 is so old as to not be of interest to anyone.
|
|
||||||
*/
|
|
||||||
appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
|
appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
|
||||||
"amopopr::pg_catalog.regoperator "
|
"amopopr::pg_catalog.regoperator, "
|
||||||
|
"opfname AS sortfamily, "
|
||||||
|
"nspname AS sortfamilynsp "
|
||||||
|
"FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
|
||||||
|
"(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
|
||||||
|
"LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
|
||||||
|
"LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
|
||||||
|
"WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
|
||||||
|
"AND refobjid = '%u'::pg_catalog.oid "
|
||||||
|
"AND amopfamily = '%s'::pg_catalog.oid "
|
||||||
|
"ORDER BY amopstrategy",
|
||||||
|
opcinfo->dobj.catId.oid,
|
||||||
|
opcfamily);
|
||||||
|
}
|
||||||
|
else if (g_fout->remoteVersion >= 80400)
|
||||||
|
{
|
||||||
|
appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
|
||||||
|
"amopopr::pg_catalog.regoperator, "
|
||||||
|
"NULL AS sortfamily, "
|
||||||
|
"NULL AS sortfamilynsp "
|
||||||
"FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
|
"FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
|
||||||
"WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
|
"WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
|
||||||
"AND refobjid = '%u'::pg_catalog.oid "
|
"AND refobjid = '%u'::pg_catalog.oid "
|
||||||
@ -8981,12 +9008,10 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
|
|||||||
}
|
}
|
||||||
else if (g_fout->remoteVersion >= 80300)
|
else if (g_fout->remoteVersion >= 80300)
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
* Print only those opfamily members that are tied to the opclass by
|
|
||||||
* pg_depend entries.
|
|
||||||
*/
|
|
||||||
appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
|
appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
|
||||||
"amopopr::pg_catalog.regoperator "
|
"amopopr::pg_catalog.regoperator, "
|
||||||
|
"NULL AS sortfamily, "
|
||||||
|
"NULL AS sortfamilynsp "
|
||||||
"FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
|
"FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
|
||||||
"WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
|
"WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
|
||||||
"AND refobjid = '%u'::pg_catalog.oid "
|
"AND refobjid = '%u'::pg_catalog.oid "
|
||||||
@ -8997,8 +9022,14 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
* Here, we print all entries since there are no opfamilies and
|
||||||
|
* hence no loose operators to worry about.
|
||||||
|
*/
|
||||||
appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
|
appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
|
||||||
"amopopr::pg_catalog.regoperator "
|
"amopopr::pg_catalog.regoperator, "
|
||||||
|
"NULL AS sortfamily, "
|
||||||
|
"NULL AS sortfamilynsp "
|
||||||
"FROM pg_catalog.pg_amop "
|
"FROM pg_catalog.pg_amop "
|
||||||
"WHERE amopclaid = '%u'::pg_catalog.oid "
|
"WHERE amopclaid = '%u'::pg_catalog.oid "
|
||||||
"ORDER BY amopstrategy",
|
"ORDER BY amopstrategy",
|
||||||
@ -9013,18 +9044,31 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
|
|||||||
i_amopstrategy = PQfnumber(res, "amopstrategy");
|
i_amopstrategy = PQfnumber(res, "amopstrategy");
|
||||||
i_amopreqcheck = PQfnumber(res, "amopreqcheck");
|
i_amopreqcheck = PQfnumber(res, "amopreqcheck");
|
||||||
i_amopopr = PQfnumber(res, "amopopr");
|
i_amopopr = PQfnumber(res, "amopopr");
|
||||||
|
i_sortfamily = PQfnumber(res, "sortfamily");
|
||||||
|
i_sortfamilynsp = PQfnumber(res, "sortfamilynsp");
|
||||||
|
|
||||||
for (i = 0; i < ntups; i++)
|
for (i = 0; i < ntups; i++)
|
||||||
{
|
{
|
||||||
amopstrategy = PQgetvalue(res, i, i_amopstrategy);
|
amopstrategy = PQgetvalue(res, i, i_amopstrategy);
|
||||||
amopreqcheck = PQgetvalue(res, i, i_amopreqcheck);
|
amopreqcheck = PQgetvalue(res, i, i_amopreqcheck);
|
||||||
amopopr = PQgetvalue(res, i, i_amopopr);
|
amopopr = PQgetvalue(res, i, i_amopopr);
|
||||||
|
sortfamily = PQgetvalue(res, i, i_sortfamily);
|
||||||
|
sortfamilynsp = PQgetvalue(res, i, i_sortfamilynsp);
|
||||||
|
|
||||||
if (needComma)
|
if (needComma)
|
||||||
appendPQExpBuffer(q, " ,\n ");
|
appendPQExpBuffer(q, " ,\n ");
|
||||||
|
|
||||||
appendPQExpBuffer(q, "OPERATOR %s %s",
|
appendPQExpBuffer(q, "OPERATOR %s %s",
|
||||||
amopstrategy, amopopr);
|
amopstrategy, amopopr);
|
||||||
|
|
||||||
|
if (strlen(sortfamily) > 0)
|
||||||
|
{
|
||||||
|
appendPQExpBuffer(q, " FOR ORDER BY ");
|
||||||
|
if (strcmp(sortfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0)
|
||||||
|
appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
|
||||||
|
appendPQExpBuffer(q, "%s", fmtId(sortfamily));
|
||||||
|
}
|
||||||
|
|
||||||
if (strcmp(amopreqcheck, "t") == 0)
|
if (strcmp(amopreqcheck, "t") == 0)
|
||||||
appendPQExpBuffer(q, " RECHECK");
|
appendPQExpBuffer(q, " RECHECK");
|
||||||
|
|
||||||
@ -9035,15 +9079,14 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Now fetch and print the FUNCTION entries (pg_amproc rows).
|
* Now fetch and print the FUNCTION entries (pg_amproc rows).
|
||||||
|
*
|
||||||
|
* Print only those opfamily members that are tied to the opclass by
|
||||||
|
* pg_depend entries.
|
||||||
*/
|
*/
|
||||||
resetPQExpBuffer(query);
|
resetPQExpBuffer(query);
|
||||||
|
|
||||||
if (g_fout->remoteVersion >= 80300)
|
if (g_fout->remoteVersion >= 80300)
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
* Print only those opfamily members that are tied to the opclass by
|
|
||||||
* pg_depend entries.
|
|
||||||
*/
|
|
||||||
appendPQExpBuffer(query, "SELECT amprocnum, "
|
appendPQExpBuffer(query, "SELECT amprocnum, "
|
||||||
"amproc::pg_catalog.regprocedure "
|
"amproc::pg_catalog.regprocedure "
|
||||||
"FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
|
"FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
|
||||||
@ -9119,6 +9162,9 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
|
|||||||
/*
|
/*
|
||||||
* dumpOpfamily
|
* dumpOpfamily
|
||||||
* write out a single operator family definition
|
* write out a single operator family definition
|
||||||
|
*
|
||||||
|
* Note: this also dumps any "loose" operator members that aren't bound to a
|
||||||
|
* specific opclass within the opfamily.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
|
dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
|
||||||
@ -9134,6 +9180,8 @@ dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
|
|||||||
int i_amopstrategy;
|
int i_amopstrategy;
|
||||||
int i_amopreqcheck;
|
int i_amopreqcheck;
|
||||||
int i_amopopr;
|
int i_amopopr;
|
||||||
|
int i_sortfamily;
|
||||||
|
int i_sortfamilynsp;
|
||||||
int i_amprocnum;
|
int i_amprocnum;
|
||||||
int i_amproc;
|
int i_amproc;
|
||||||
int i_amproclefttype;
|
int i_amproclefttype;
|
||||||
@ -9142,6 +9190,8 @@ dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
|
|||||||
char *amopstrategy;
|
char *amopstrategy;
|
||||||
char *amopreqcheck;
|
char *amopreqcheck;
|
||||||
char *amopopr;
|
char *amopopr;
|
||||||
|
char *sortfamily;
|
||||||
|
char *sortfamilynsp;
|
||||||
char *amprocnum;
|
char *amprocnum;
|
||||||
char *amproc;
|
char *amproc;
|
||||||
char *amproclefttype;
|
char *amproclefttype;
|
||||||
@ -9172,18 +9222,36 @@ dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
|
|||||||
/*
|
/*
|
||||||
* Fetch only those opfamily members that are tied directly to the
|
* Fetch only those opfamily members that are tied directly to the
|
||||||
* opfamily by pg_depend entries.
|
* opfamily by pg_depend entries.
|
||||||
|
*
|
||||||
|
* XXX RECHECK is gone as of 8.4, but we'll still print it if dumping
|
||||||
|
* an older server's opclass in which it is used. This is to avoid
|
||||||
|
* hard-to-detect breakage if a newer pg_dump is used to dump from an
|
||||||
|
* older server and then reload into that old version. This can go
|
||||||
|
* away once 8.3 is so old as to not be of interest to anyone.
|
||||||
*/
|
*/
|
||||||
if (g_fout->remoteVersion >= 80400)
|
if (g_fout->remoteVersion >= 90100)
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
* XXX RECHECK is gone as of 8.4, but we'll still print it if dumping
|
|
||||||
* an older server's opclass in which it is used. This is to avoid
|
|
||||||
* hard-to-detect breakage if a newer pg_dump is used to dump from an
|
|
||||||
* older server and then reload into that old version. This can go
|
|
||||||
* away once 8.3 is so old as to not be of interest to anyone.
|
|
||||||
*/
|
|
||||||
appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
|
appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
|
||||||
"amopopr::pg_catalog.regoperator "
|
"amopopr::pg_catalog.regoperator, "
|
||||||
|
"opfname AS sortfamily, "
|
||||||
|
"nspname AS sortfamilynsp "
|
||||||
|
"FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
|
||||||
|
"(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
|
||||||
|
"LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
|
||||||
|
"LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
|
||||||
|
"WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
|
||||||
|
"AND refobjid = '%u'::pg_catalog.oid "
|
||||||
|
"AND amopfamily = '%u'::pg_catalog.oid "
|
||||||
|
"ORDER BY amopstrategy",
|
||||||
|
opfinfo->dobj.catId.oid,
|
||||||
|
opfinfo->dobj.catId.oid);
|
||||||
|
}
|
||||||
|
else if (g_fout->remoteVersion >= 80400)
|
||||||
|
{
|
||||||
|
appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
|
||||||
|
"amopopr::pg_catalog.regoperator, "
|
||||||
|
"NULL AS sortfamily, "
|
||||||
|
"NULL AS sortfamilynsp "
|
||||||
"FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
|
"FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
|
||||||
"WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
|
"WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
|
||||||
"AND refobjid = '%u'::pg_catalog.oid "
|
"AND refobjid = '%u'::pg_catalog.oid "
|
||||||
@ -9195,7 +9263,9 @@ dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
|
appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
|
||||||
"amopopr::pg_catalog.regoperator "
|
"amopopr::pg_catalog.regoperator, "
|
||||||
|
"NULL AS sortfamily, "
|
||||||
|
"NULL AS sortfamilynsp "
|
||||||
"FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
|
"FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
|
||||||
"WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
|
"WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
|
||||||
"AND refobjid = '%u'::pg_catalog.oid "
|
"AND refobjid = '%u'::pg_catalog.oid "
|
||||||
@ -9323,18 +9393,31 @@ dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
|
|||||||
i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
|
i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
|
||||||
i_amopreqcheck = PQfnumber(res_ops, "amopreqcheck");
|
i_amopreqcheck = PQfnumber(res_ops, "amopreqcheck");
|
||||||
i_amopopr = PQfnumber(res_ops, "amopopr");
|
i_amopopr = PQfnumber(res_ops, "amopopr");
|
||||||
|
i_sortfamily = PQfnumber(res_ops, "sortfamily");
|
||||||
|
i_sortfamilynsp = PQfnumber(res_ops, "sortfamilynsp");
|
||||||
|
|
||||||
for (i = 0; i < ntups; i++)
|
for (i = 0; i < ntups; i++)
|
||||||
{
|
{
|
||||||
amopstrategy = PQgetvalue(res_ops, i, i_amopstrategy);
|
amopstrategy = PQgetvalue(res_ops, i, i_amopstrategy);
|
||||||
amopreqcheck = PQgetvalue(res_ops, i, i_amopreqcheck);
|
amopreqcheck = PQgetvalue(res_ops, i, i_amopreqcheck);
|
||||||
amopopr = PQgetvalue(res_ops, i, i_amopopr);
|
amopopr = PQgetvalue(res_ops, i, i_amopopr);
|
||||||
|
sortfamily = PQgetvalue(res_ops, i, i_sortfamily);
|
||||||
|
sortfamilynsp = PQgetvalue(res_ops, i, i_sortfamilynsp);
|
||||||
|
|
||||||
if (needComma)
|
if (needComma)
|
||||||
appendPQExpBuffer(q, " ,\n ");
|
appendPQExpBuffer(q, " ,\n ");
|
||||||
|
|
||||||
appendPQExpBuffer(q, "OPERATOR %s %s",
|
appendPQExpBuffer(q, "OPERATOR %s %s",
|
||||||
amopstrategy, amopopr);
|
amopstrategy, amopopr);
|
||||||
|
|
||||||
|
if (strlen(sortfamily) > 0)
|
||||||
|
{
|
||||||
|
appendPQExpBuffer(q, " FOR ORDER BY ");
|
||||||
|
if (strcmp(sortfamilynsp, opfinfo->dobj.namespace->dobj.name) != 0)
|
||||||
|
appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
|
||||||
|
appendPQExpBuffer(q, "%s", fmtId(sortfamily));
|
||||||
|
}
|
||||||
|
|
||||||
if (strcmp(amopreqcheck, "t") == 0)
|
if (strcmp(amopreqcheck, "t") == 0)
|
||||||
appendPQExpBuffer(q, " RECHECK");
|
appendPQExpBuffer(q, " RECHECK");
|
||||||
|
|
||||||
|
@ -53,6 +53,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* yyyymmddN */
|
/* yyyymmddN */
|
||||||
#define CATALOG_VERSION_NO 201011211
|
#define CATALOG_VERSION_NO 201011241
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -67,7 +67,7 @@ DECLARE_UNIQUE_INDEX(pg_am_oid_index, 2652, on pg_am using btree(oid oid_ops));
|
|||||||
|
|
||||||
DECLARE_UNIQUE_INDEX(pg_amop_fam_strat_index, 2653, on pg_amop using btree(amopfamily oid_ops, amoplefttype oid_ops, amoprighttype oid_ops, amopstrategy int2_ops));
|
DECLARE_UNIQUE_INDEX(pg_amop_fam_strat_index, 2653, on pg_amop using btree(amopfamily oid_ops, amoplefttype oid_ops, amoprighttype oid_ops, amopstrategy int2_ops));
|
||||||
#define AccessMethodStrategyIndexId 2653
|
#define AccessMethodStrategyIndexId 2653
|
||||||
DECLARE_UNIQUE_INDEX(pg_amop_opr_fam_index, 2654, on pg_amop using btree(amopopr oid_ops, amopfamily oid_ops));
|
DECLARE_UNIQUE_INDEX(pg_amop_opr_fam_index, 2654, on pg_amop using btree(amopopr oid_ops, amoppurpose char_ops, amopfamily oid_ops));
|
||||||
#define AccessMethodOperatorIndexId 2654
|
#define AccessMethodOperatorIndexId 2654
|
||||||
DECLARE_UNIQUE_INDEX(pg_amop_oid_index, 2756, on pg_amop using btree(oid oid_ops));
|
DECLARE_UNIQUE_INDEX(pg_amop_oid_index, 2756, on pg_amop using btree(oid oid_ops));
|
||||||
#define AccessMethodOperatorOidIndexId 2756
|
#define AccessMethodOperatorOidIndexId 2756
|
||||||
|
@ -40,7 +40,8 @@ CATALOG(pg_am,2601)
|
|||||||
* assignments. */
|
* assignments. */
|
||||||
int2 amsupport; /* total number of support functions that this
|
int2 amsupport; /* total number of support functions that this
|
||||||
* AM uses */
|
* AM uses */
|
||||||
bool amcanorder; /* does AM support ordered scan results? */
|
bool amcanorder; /* does AM support order by column value? */
|
||||||
|
bool amcanorderbyop; /* does AM support order by operator result? */
|
||||||
bool amcanbackward; /* does AM support backward scan? */
|
bool amcanbackward; /* does AM support backward scan? */
|
||||||
bool amcanunique; /* does AM support UNIQUE indexes? */
|
bool amcanunique; /* does AM support UNIQUE indexes? */
|
||||||
bool amcanmulticol; /* does AM support multi-column indexes? */
|
bool amcanmulticol; /* does AM support multi-column indexes? */
|
||||||
@ -76,49 +77,50 @@ typedef FormData_pg_am *Form_pg_am;
|
|||||||
* compiler constants for pg_am
|
* compiler constants for pg_am
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
#define Natts_pg_am 26
|
#define Natts_pg_am 27
|
||||||
#define Anum_pg_am_amname 1
|
#define Anum_pg_am_amname 1
|
||||||
#define Anum_pg_am_amstrategies 2
|
#define Anum_pg_am_amstrategies 2
|
||||||
#define Anum_pg_am_amsupport 3
|
#define Anum_pg_am_amsupport 3
|
||||||
#define Anum_pg_am_amcanorder 4
|
#define Anum_pg_am_amcanorder 4
|
||||||
#define Anum_pg_am_amcanbackward 5
|
#define Anum_pg_am_amcanorderbyop 5
|
||||||
#define Anum_pg_am_amcanunique 6
|
#define Anum_pg_am_amcanbackward 6
|
||||||
#define Anum_pg_am_amcanmulticol 7
|
#define Anum_pg_am_amcanunique 7
|
||||||
#define Anum_pg_am_amoptionalkey 8
|
#define Anum_pg_am_amcanmulticol 8
|
||||||
#define Anum_pg_am_amindexnulls 9
|
#define Anum_pg_am_amoptionalkey 9
|
||||||
#define Anum_pg_am_amsearchnulls 10
|
#define Anum_pg_am_amindexnulls 10
|
||||||
#define Anum_pg_am_amstorage 11
|
#define Anum_pg_am_amsearchnulls 11
|
||||||
#define Anum_pg_am_amclusterable 12
|
#define Anum_pg_am_amstorage 12
|
||||||
#define Anum_pg_am_amkeytype 13
|
#define Anum_pg_am_amclusterable 13
|
||||||
#define Anum_pg_am_aminsert 14
|
#define Anum_pg_am_amkeytype 14
|
||||||
#define Anum_pg_am_ambeginscan 15
|
#define Anum_pg_am_aminsert 15
|
||||||
#define Anum_pg_am_amgettuple 16
|
#define Anum_pg_am_ambeginscan 16
|
||||||
#define Anum_pg_am_amgetbitmap 17
|
#define Anum_pg_am_amgettuple 17
|
||||||
#define Anum_pg_am_amrescan 18
|
#define Anum_pg_am_amgetbitmap 18
|
||||||
#define Anum_pg_am_amendscan 19
|
#define Anum_pg_am_amrescan 19
|
||||||
#define Anum_pg_am_ammarkpos 20
|
#define Anum_pg_am_amendscan 20
|
||||||
#define Anum_pg_am_amrestrpos 21
|
#define Anum_pg_am_ammarkpos 21
|
||||||
#define Anum_pg_am_ambuild 22
|
#define Anum_pg_am_amrestrpos 22
|
||||||
#define Anum_pg_am_ambulkdelete 23
|
#define Anum_pg_am_ambuild 23
|
||||||
#define Anum_pg_am_amvacuumcleanup 24
|
#define Anum_pg_am_ambulkdelete 24
|
||||||
#define Anum_pg_am_amcostestimate 25
|
#define Anum_pg_am_amvacuumcleanup 25
|
||||||
#define Anum_pg_am_amoptions 26
|
#define Anum_pg_am_amcostestimate 26
|
||||||
|
#define Anum_pg_am_amoptions 27
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* initial contents of pg_am
|
* initial contents of pg_am
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
DATA(insert OID = 403 ( btree 5 1 t t t t t t t f t 0 btinsert btbeginscan btgettuple btgetbitmap btrescan btendscan btmarkpos btrestrpos btbuild btbulkdelete btvacuumcleanup btcostestimate btoptions ));
|
DATA(insert OID = 403 ( btree 5 1 t f t t t t t t f t 0 btinsert btbeginscan btgettuple btgetbitmap btrescan btendscan btmarkpos btrestrpos btbuild btbulkdelete btvacuumcleanup btcostestimate btoptions ));
|
||||||
DESCR("b-tree index access method");
|
DESCR("b-tree index access method");
|
||||||
#define BTREE_AM_OID 403
|
#define BTREE_AM_OID 403
|
||||||
DATA(insert OID = 405 ( hash 1 1 f t f f f f f f f 23 hashinsert hashbeginscan hashgettuple hashgetbitmap hashrescan hashendscan hashmarkpos hashrestrpos hashbuild hashbulkdelete hashvacuumcleanup hashcostestimate hashoptions ));
|
DATA(insert OID = 405 ( hash 1 1 f f t f f f f f f f 23 hashinsert hashbeginscan hashgettuple hashgetbitmap hashrescan hashendscan hashmarkpos hashrestrpos hashbuild hashbulkdelete hashvacuumcleanup hashcostestimate hashoptions ));
|
||||||
DESCR("hash index access method");
|
DESCR("hash index access method");
|
||||||
#define HASH_AM_OID 405
|
#define HASH_AM_OID 405
|
||||||
DATA(insert OID = 783 ( gist 0 7 f f f t t t t t t 0 gistinsert gistbeginscan gistgettuple gistgetbitmap gistrescan gistendscan gistmarkpos gistrestrpos gistbuild gistbulkdelete gistvacuumcleanup gistcostestimate gistoptions ));
|
DATA(insert OID = 783 ( gist 0 7 f f f f t t t t t t 0 gistinsert gistbeginscan gistgettuple gistgetbitmap gistrescan gistendscan gistmarkpos gistrestrpos gistbuild gistbulkdelete gistvacuumcleanup gistcostestimate gistoptions ));
|
||||||
DESCR("GiST index access method");
|
DESCR("GiST index access method");
|
||||||
#define GIST_AM_OID 783
|
#define GIST_AM_OID 783
|
||||||
DATA(insert OID = 2742 ( gin 0 5 f f f t t f f t f 0 gininsert ginbeginscan - gingetbitmap ginrescan ginendscan ginmarkpos ginrestrpos ginbuild ginbulkdelete ginvacuumcleanup gincostestimate ginoptions ));
|
DATA(insert OID = 2742 ( gin 0 5 f f f f t t f f t f 0 gininsert ginbeginscan - gingetbitmap ginrescan ginendscan ginmarkpos ginrestrpos ginbuild ginbulkdelete ginvacuumcleanup gincostestimate ginoptions ));
|
||||||
DESCR("GIN index access method");
|
DESCR("GIN index access method");
|
||||||
#define GIN_AM_OID 2742
|
#define GIN_AM_OID 2742
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1776,6 +1776,7 @@ typedef struct CreateOpClassItem
|
|||||||
List *name; /* operator or function name */
|
List *name; /* operator or function name */
|
||||||
List *args; /* argument types */
|
List *args; /* argument types */
|
||||||
int number; /* strategy num or support proc num */
|
int number; /* strategy num or support proc num */
|
||||||
|
List *order_family; /* only used for ordering operators */
|
||||||
List *class_args; /* only used for functions */
|
List *class_args; /* only used for functions */
|
||||||
/* fields used for a storagetype item: */
|
/* fields used for a storagetype item: */
|
||||||
TypeName *storedtype; /* datatype stored in index */
|
TypeName *storedtype; /* datatype stored in index */
|
||||||
|
@ -469,6 +469,7 @@ typedef struct IndexOptInfo
|
|||||||
|
|
||||||
bool predOK; /* true if predicate matches query */
|
bool predOK; /* true if predicate matches query */
|
||||||
bool unique; /* true if a unique index */
|
bool unique; /* true if a unique index */
|
||||||
|
bool amcanorderbyop; /* does AM support order by operator result? */
|
||||||
bool amoptionalkey; /* can query omit key for the first column? */
|
bool amoptionalkey; /* can query omit key for the first column? */
|
||||||
bool amsearchnulls; /* can AM search for NULL/NOT NULL entries? */
|
bool amsearchnulls; /* can AM search for NULL/NOT NULL entries? */
|
||||||
bool amhasgettuple; /* does AM have amgettuple interface? */
|
bool amhasgettuple; /* does AM have amgettuple interface? */
|
||||||
|
@ -849,6 +849,14 @@ WHERE p1.amopfamily = 0 OR p1.amoplefttype = 0 OR p1.amoprighttype = 0
|
|||||||
------------+--------------
|
------------+--------------
|
||||||
(0 rows)
|
(0 rows)
|
||||||
|
|
||||||
|
SELECT p1.amopfamily, p1.amopstrategy
|
||||||
|
FROM pg_amop as p1
|
||||||
|
WHERE NOT ((p1.amoppurpose = 's' AND p1.amopsortfamily = 0) OR
|
||||||
|
(p1.amoppurpose = 'o' AND p1.amopsortfamily <> 0));
|
||||||
|
amopfamily | amopstrategy
|
||||||
|
------------+--------------
|
||||||
|
(0 rows)
|
||||||
|
|
||||||
-- amoplefttype/amoprighttype must match the operator
|
-- amoplefttype/amoprighttype must match the operator
|
||||||
SELECT p1.oid, p2.oid
|
SELECT p1.oid, p2.oid
|
||||||
FROM pg_amop AS p1, pg_operator AS p2
|
FROM pg_amop AS p1, pg_operator AS p2
|
||||||
@ -866,6 +874,25 @@ WHERE p1.amopfamily = p2.oid AND p1.amopmethod != p2.opfmethod;
|
|||||||
-----+-----
|
-----+-----
|
||||||
(0 rows)
|
(0 rows)
|
||||||
|
|
||||||
|
-- amopsortfamily, if present, must reference a btree family
|
||||||
|
SELECT p1.amopfamily, p1.amopstrategy
|
||||||
|
FROM pg_amop AS p1
|
||||||
|
WHERE p1.amopsortfamily <> 0 AND NOT EXISTS
|
||||||
|
(SELECT 1 from pg_opfamily op WHERE op.oid = p1.amopsortfamily
|
||||||
|
AND op.opfmethod = (SELECT oid FROM pg_am WHERE amname = 'btree'));
|
||||||
|
amopfamily | amopstrategy
|
||||||
|
------------+--------------
|
||||||
|
(0 rows)
|
||||||
|
|
||||||
|
-- check for ordering operators not supported by parent AM
|
||||||
|
SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
|
||||||
|
FROM pg_amop AS p1, pg_am AS p2
|
||||||
|
WHERE p1.amopmethod = p2.oid AND
|
||||||
|
p1.amoppurpose = 'o' AND NOT p2.amcanorderbyop;
|
||||||
|
amopfamily | amopopr | oid | amname
|
||||||
|
------------+---------+-----+--------
|
||||||
|
(0 rows)
|
||||||
|
|
||||||
-- Cross-check amopstrategy index against parent AM
|
-- Cross-check amopstrategy index against parent AM
|
||||||
SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
|
SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
|
||||||
FROM pg_amop AS p1, pg_am AS p2
|
FROM pg_amop AS p1, pg_am AS p2
|
||||||
@ -885,17 +912,45 @@ WHERE p2.amopmethod = p1.oid AND
|
|||||||
p1.amstrategies != (SELECT count(*) FROM pg_amop AS p3
|
p1.amstrategies != (SELECT count(*) FROM pg_amop AS p3
|
||||||
WHERE p3.amopfamily = p2.amopfamily AND
|
WHERE p3.amopfamily = p2.amopfamily AND
|
||||||
p3.amoplefttype = p2.amoplefttype AND
|
p3.amoplefttype = p2.amoplefttype AND
|
||||||
p3.amoprighttype = p2.amoprighttype);
|
p3.amoprighttype = p2.amoprighttype AND
|
||||||
|
p3.amoppurpose = 's');
|
||||||
amname | amoplefttype | amoprighttype
|
amname | amoplefttype | amoprighttype
|
||||||
--------+--------------+---------------
|
--------+--------------+---------------
|
||||||
(0 rows)
|
(0 rows)
|
||||||
|
|
||||||
|
-- Currently, none of the AMs with fixed strategy sets support ordering ops.
|
||||||
|
SELECT p1.amname, p2.amopfamily, p2.amopstrategy
|
||||||
|
FROM pg_am AS p1, pg_amop AS p2
|
||||||
|
WHERE p2.amopmethod = p1.oid AND
|
||||||
|
p1.amstrategies <> 0 AND p2.amoppurpose <> 's';
|
||||||
|
amname | amopfamily | amopstrategy
|
||||||
|
--------+------------+--------------
|
||||||
|
(0 rows)
|
||||||
|
|
||||||
-- Check that amopopr points at a reasonable-looking operator, ie a binary
|
-- Check that amopopr points at a reasonable-looking operator, ie a binary
|
||||||
-- operator yielding boolean.
|
-- operator. If it's a search operator it had better yield boolean,
|
||||||
|
-- otherwise an input type of its sort opfamily.
|
||||||
SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.oprname
|
SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.oprname
|
||||||
FROM pg_amop AS p1, pg_operator AS p2
|
FROM pg_amop AS p1, pg_operator AS p2
|
||||||
WHERE p1.amopopr = p2.oid AND
|
WHERE p1.amopopr = p2.oid AND
|
||||||
(p2.oprkind != 'b' OR p2.oprresult != 'bool'::regtype);
|
p2.oprkind != 'b';
|
||||||
|
amopfamily | amopopr | oid | oprname
|
||||||
|
------------+---------+-----+---------
|
||||||
|
(0 rows)
|
||||||
|
|
||||||
|
SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.oprname
|
||||||
|
FROM pg_amop AS p1, pg_operator AS p2
|
||||||
|
WHERE p1.amopopr = p2.oid AND p1.amoppurpose = 's' AND
|
||||||
|
p2.oprresult != 'bool'::regtype;
|
||||||
|
amopfamily | amopopr | oid | oprname
|
||||||
|
------------+---------+-----+---------
|
||||||
|
(0 rows)
|
||||||
|
|
||||||
|
SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.oprname
|
||||||
|
FROM pg_amop AS p1, pg_operator AS p2
|
||||||
|
WHERE p1.amopopr = p2.oid AND p1.amoppurpose = 'o' AND NOT EXISTS
|
||||||
|
(SELECT 1 FROM pg_opclass op
|
||||||
|
WHERE opcfamily = p1.amopsortfamily AND opcintype = p2.oprresult);
|
||||||
amopfamily | amopopr | oid | oprname
|
amopfamily | amopopr | oid | oprname
|
||||||
------------+---------+-----+---------
|
------------+---------+-----+---------
|
||||||
(0 rows)
|
(0 rows)
|
||||||
@ -950,12 +1005,12 @@ ORDER BY 1, 2, 3;
|
|||||||
2742 | 4 | =
|
2742 | 4 | =
|
||||||
(39 rows)
|
(39 rows)
|
||||||
|
|
||||||
-- Check that all operators linked to by opclass entries have selectivity
|
-- Check that all opclass search operators have selectivity estimators.
|
||||||
-- estimators. This is not absolutely required, but it seems a reasonable
|
-- This is not absolutely required, but it seems a reasonable thing
|
||||||
-- thing to insist on for all standard datatypes.
|
-- to insist on for all standard datatypes.
|
||||||
SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.oprname
|
SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.oprname
|
||||||
FROM pg_amop AS p1, pg_operator AS p2
|
FROM pg_amop AS p1, pg_operator AS p2
|
||||||
WHERE p1.amopopr = p2.oid AND
|
WHERE p1.amopopr = p2.oid AND p1.amoppurpose = 's' AND
|
||||||
(p2.oprrest = 0 OR p2.oprjoin = 0);
|
(p2.oprrest = 0 OR p2.oprjoin = 0);
|
||||||
amopfamily | amopopr | oid | oprname
|
amopfamily | amopopr | oid | oprname
|
||||||
------------+---------+-----+---------
|
------------+---------+-----+---------
|
||||||
|
@ -685,6 +685,11 @@ FROM pg_amop as p1
|
|||||||
WHERE p1.amopfamily = 0 OR p1.amoplefttype = 0 OR p1.amoprighttype = 0
|
WHERE p1.amopfamily = 0 OR p1.amoplefttype = 0 OR p1.amoprighttype = 0
|
||||||
OR p1.amopopr = 0 OR p1.amopmethod = 0 OR p1.amopstrategy < 1;
|
OR p1.amopopr = 0 OR p1.amopmethod = 0 OR p1.amopstrategy < 1;
|
||||||
|
|
||||||
|
SELECT p1.amopfamily, p1.amopstrategy
|
||||||
|
FROM pg_amop as p1
|
||||||
|
WHERE NOT ((p1.amoppurpose = 's' AND p1.amopsortfamily = 0) OR
|
||||||
|
(p1.amoppurpose = 'o' AND p1.amopsortfamily <> 0));
|
||||||
|
|
||||||
-- amoplefttype/amoprighttype must match the operator
|
-- amoplefttype/amoprighttype must match the operator
|
||||||
|
|
||||||
SELECT p1.oid, p2.oid
|
SELECT p1.oid, p2.oid
|
||||||
@ -698,6 +703,21 @@ SELECT p1.oid, p2.oid
|
|||||||
FROM pg_amop AS p1, pg_opfamily AS p2
|
FROM pg_amop AS p1, pg_opfamily AS p2
|
||||||
WHERE p1.amopfamily = p2.oid AND p1.amopmethod != p2.opfmethod;
|
WHERE p1.amopfamily = p2.oid AND p1.amopmethod != p2.opfmethod;
|
||||||
|
|
||||||
|
-- amopsortfamily, if present, must reference a btree family
|
||||||
|
|
||||||
|
SELECT p1.amopfamily, p1.amopstrategy
|
||||||
|
FROM pg_amop AS p1
|
||||||
|
WHERE p1.amopsortfamily <> 0 AND NOT EXISTS
|
||||||
|
(SELECT 1 from pg_opfamily op WHERE op.oid = p1.amopsortfamily
|
||||||
|
AND op.opfmethod = (SELECT oid FROM pg_am WHERE amname = 'btree'));
|
||||||
|
|
||||||
|
-- check for ordering operators not supported by parent AM
|
||||||
|
|
||||||
|
SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
|
||||||
|
FROM pg_amop AS p1, pg_am AS p2
|
||||||
|
WHERE p1.amopmethod = p2.oid AND
|
||||||
|
p1.amoppurpose = 'o' AND NOT p2.amcanorderbyop;
|
||||||
|
|
||||||
-- Cross-check amopstrategy index against parent AM
|
-- Cross-check amopstrategy index against parent AM
|
||||||
|
|
||||||
SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
|
SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
|
||||||
@ -716,15 +736,35 @@ WHERE p2.amopmethod = p1.oid AND
|
|||||||
p1.amstrategies != (SELECT count(*) FROM pg_amop AS p3
|
p1.amstrategies != (SELECT count(*) FROM pg_amop AS p3
|
||||||
WHERE p3.amopfamily = p2.amopfamily AND
|
WHERE p3.amopfamily = p2.amopfamily AND
|
||||||
p3.amoplefttype = p2.amoplefttype AND
|
p3.amoplefttype = p2.amoplefttype AND
|
||||||
p3.amoprighttype = p2.amoprighttype);
|
p3.amoprighttype = p2.amoprighttype AND
|
||||||
|
p3.amoppurpose = 's');
|
||||||
|
|
||||||
|
-- Currently, none of the AMs with fixed strategy sets support ordering ops.
|
||||||
|
|
||||||
|
SELECT p1.amname, p2.amopfamily, p2.amopstrategy
|
||||||
|
FROM pg_am AS p1, pg_amop AS p2
|
||||||
|
WHERE p2.amopmethod = p1.oid AND
|
||||||
|
p1.amstrategies <> 0 AND p2.amoppurpose <> 's';
|
||||||
|
|
||||||
-- Check that amopopr points at a reasonable-looking operator, ie a binary
|
-- Check that amopopr points at a reasonable-looking operator, ie a binary
|
||||||
-- operator yielding boolean.
|
-- operator. If it's a search operator it had better yield boolean,
|
||||||
|
-- otherwise an input type of its sort opfamily.
|
||||||
|
|
||||||
SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.oprname
|
SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.oprname
|
||||||
FROM pg_amop AS p1, pg_operator AS p2
|
FROM pg_amop AS p1, pg_operator AS p2
|
||||||
WHERE p1.amopopr = p2.oid AND
|
WHERE p1.amopopr = p2.oid AND
|
||||||
(p2.oprkind != 'b' OR p2.oprresult != 'bool'::regtype);
|
p2.oprkind != 'b';
|
||||||
|
|
||||||
|
SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.oprname
|
||||||
|
FROM pg_amop AS p1, pg_operator AS p2
|
||||||
|
WHERE p1.amopopr = p2.oid AND p1.amoppurpose = 's' AND
|
||||||
|
p2.oprresult != 'bool'::regtype;
|
||||||
|
|
||||||
|
SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.oprname
|
||||||
|
FROM pg_amop AS p1, pg_operator AS p2
|
||||||
|
WHERE p1.amopopr = p2.oid AND p1.amoppurpose = 'o' AND NOT EXISTS
|
||||||
|
(SELECT 1 FROM pg_opclass op
|
||||||
|
WHERE opcfamily = p1.amopsortfamily AND opcintype = p2.oprresult);
|
||||||
|
|
||||||
-- Make a list of all the distinct operator names being used in particular
|
-- Make a list of all the distinct operator names being used in particular
|
||||||
-- strategy slots. This is a bit hokey, since the list might need to change
|
-- strategy slots. This is a bit hokey, since the list might need to change
|
||||||
@ -735,13 +775,13 @@ SELECT DISTINCT amopmethod, amopstrategy, oprname
|
|||||||
FROM pg_amop p1 LEFT JOIN pg_operator p2 ON amopopr = p2.oid
|
FROM pg_amop p1 LEFT JOIN pg_operator p2 ON amopopr = p2.oid
|
||||||
ORDER BY 1, 2, 3;
|
ORDER BY 1, 2, 3;
|
||||||
|
|
||||||
-- Check that all operators linked to by opclass entries have selectivity
|
-- Check that all opclass search operators have selectivity estimators.
|
||||||
-- estimators. This is not absolutely required, but it seems a reasonable
|
-- This is not absolutely required, but it seems a reasonable thing
|
||||||
-- thing to insist on for all standard datatypes.
|
-- to insist on for all standard datatypes.
|
||||||
|
|
||||||
SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.oprname
|
SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.oprname
|
||||||
FROM pg_amop AS p1, pg_operator AS p2
|
FROM pg_amop AS p1, pg_operator AS p2
|
||||||
WHERE p1.amopopr = p2.oid AND
|
WHERE p1.amopopr = p2.oid AND p1.amoppurpose = 's' AND
|
||||||
(p2.oprrest = 0 OR p2.oprjoin = 0);
|
(p2.oprrest = 0 OR p2.oprjoin = 0);
|
||||||
|
|
||||||
-- Check that each opclass in an opfamily has associated operators, that is
|
-- Check that each opclass in an opfamily has associated operators, that is
|
||||||
|
Loading…
x
Reference in New Issue
Block a user