Implement CREATE/DROP OPERATOR CLASS. Work still remains: need more

documentation (xindex.sgml should be rewritten), need to teach pg_dump
about it, need to update contrib modules that currently build pg_opclass
entries by hand.  Original patch by Bill Studenmund, grammar adjustments
and general update for 7.3 by Tom Lane.
This commit is contained in:
Tom Lane 2002-07-29 22:14:11 +00:00
parent b9459c6adb
commit ea4686e3e1
26 changed files with 1697 additions and 373 deletions

View File

@ -2,6 +2,10 @@
--
BEGIN TRANSACTION;
-- Adjust this setting to control where the operators, functions, and
-- opclasses get created.
SET search_path = public;
-- Query type
CREATE FUNCTION bqarr_in(opaque)
RETURNS opaque
@ -143,137 +147,22 @@ CREATE FUNCTION g_int_same(_int4, _int4, opaque) RETURNS opaque
AS 'MODULE_PATHNAME' LANGUAGE 'c';
-- register the default opclass for indexing
INSERT INTO pg_opclass (opcamid, opcname, opcnamespace, opcowner, opcintype, opcdefault, opckeytype)
VALUES (
(SELECT oid FROM pg_am WHERE amname = 'gist'),
'gist__int_ops',
(SELECT oid FROM pg_namespace WHERE nspname = 'pg_catalog'),
1, -- UID of superuser is hardwired to 1 as of PG 7.3
(SELECT oid FROM pg_type WHERE typname = '_int4'),
true,
0);
-- Create the operator class for indexing
-- get the comparators for _intments and store them in a tmp table
SELECT o.oid AS opoid, o.oprname
INTO TEMP TABLE _int_ops_tmp
FROM pg_operator o, pg_type t, pg_type tq
WHERE o.oprleft = t.oid and ( o.oprright = t.oid or o.oprright=tq.oid )
and t.typname = '_int4'
and tq.typname='query_int';
-- make sure we have the right operators
-- SELECT * from _int_ops_tmp;
-- using the tmp table, generate the amop entries
-- _int_overlap
INSERT INTO pg_amop (amopclaid, amopstrategy, amopreqcheck, amopopr)
SELECT opcl.oid, 3, false, c.opoid
FROM pg_opclass opcl, _int_ops_tmp c
WHERE
opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
and opcname = 'gist__int_ops'
and c.oprname = '&&';
-- _int_same
INSERT INTO pg_amop (amopclaid, amopstrategy, amopreqcheck, amopopr)
SELECT opcl.oid, 6, true, c.opoid
FROM pg_opclass opcl, _int_ops_tmp c
WHERE
opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
and opcname = 'gist__int_ops'
and c.oprname = '=';
-- _int_contains
INSERT INTO pg_amop (amopclaid, amopstrategy, amopreqcheck, amopopr)
SELECT opcl.oid, 7, false, c.opoid
FROM pg_opclass opcl, _int_ops_tmp c
WHERE
opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
and opcname = 'gist__int_ops'
and c.oprname = '@';
-- _int_contained
INSERT INTO pg_amop (amopclaid, amopstrategy, amopreqcheck, amopopr)
SELECT opcl.oid, 8, false, c.opoid
FROM pg_opclass opcl, _int_ops_tmp c
WHERE
opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
and opcname = 'gist__int_ops'
and c.oprname = '~';
--boolean search
INSERT INTO pg_amop (amopclaid, amopstrategy, amopreqcheck, amopopr)
SELECT opcl.oid, 20, false, c.opoid
FROM pg_opclass opcl, _int_ops_tmp c
WHERE
opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
and opcname = 'gist__int_ops'
and c.oprname = '@@';
DROP TABLE _int_ops_tmp;
-- add the entries to amproc for the support methods
-- note the amprocnum numbers associated with each are specific!
INSERT INTO pg_amproc (amopclaid, amprocnum, amproc)
SELECT opcl.oid, 1, pro.oid
FROM pg_opclass opcl, pg_proc pro
WHERE
opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
and opcname = 'gist__int_ops'
and proname = 'g_int_consistent';
INSERT INTO pg_amproc (amopclaid, amprocnum, amproc)
SELECT opcl.oid, 2, pro.oid
FROM pg_opclass opcl, pg_proc pro
WHERE
opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
and opcname = 'gist__int_ops'
and proname = 'g_int_union';
INSERT INTO pg_amproc (amopclaid, amprocnum, amproc)
SELECT opcl.oid, 3, pro.oid
FROM pg_opclass opcl, pg_proc pro
WHERE
opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
and opcname = 'gist__int_ops'
and proname = 'g_int_compress';
INSERT INTO pg_amproc (amopclaid, amprocnum, amproc)
SELECT opcl.oid, 4, pro.oid
FROM pg_opclass opcl, pg_proc pro
WHERE
opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
and opcname = 'gist__int_ops'
and proname = 'g_int_decompress';
INSERT INTO pg_amproc (amopclaid, amprocnum, amproc)
SELECT opcl.oid, 5, pro.oid
FROM pg_opclass opcl, pg_proc pro
WHERE
opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
and opcname = 'gist__int_ops'
and proname = 'g_int_penalty';
INSERT INTO pg_amproc (amopclaid, amprocnum, amproc)
SELECT opcl.oid, 6, pro.oid
FROM pg_opclass opcl, pg_proc pro
WHERE
opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
and opcname = 'gist__int_ops'
and proname = 'g_int_picksplit';
INSERT INTO pg_amproc (amopclaid, amprocnum, amproc)
SELECT opcl.oid, 7, pro.oid
FROM pg_opclass opcl, pg_proc pro
WHERE
opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
and opcname = 'gist__int_ops'
and proname = 'g_int_same';
CREATE OPERATOR CLASS gist__int_ops
DEFAULT FOR TYPE _int4 USING gist AS
OPERATOR 3 &&,
OPERATOR 6 = RECHECK,
OPERATOR 7 @,
OPERATOR 8 ~,
OPERATOR 20 @@ (_int4, query_int),
FUNCTION 1 g_int_consistent (opaque, _int4, int4),
FUNCTION 2 g_int_union (bytea, opaque),
FUNCTION 3 g_int_compress (opaque),
FUNCTION 4 g_int_decompress (opaque),
FUNCTION 5 g_int_penalty (opaque, opaque, opaque),
FUNCTION 6 g_int_picksplit (opaque, opaque),
FUNCTION 7 g_int_same (_int4, _int4, opaque);
---------------------------------------------
@ -302,136 +191,20 @@ CREATE FUNCTION g_intbig_same(_int4, _int4, opaque) RETURNS opaque
AS 'MODULE_PATHNAME' LANGUAGE 'c';
-- register the opclass for indexing (not as default)
INSERT INTO pg_opclass (opcamid, opcname, opcnamespace, opcowner, opcintype, opcdefault, opckeytype)
VALUES (
(SELECT oid FROM pg_am WHERE amname = 'gist'),
'gist__intbig_ops',
(SELECT oid FROM pg_namespace WHERE nspname = 'pg_catalog'),
1, -- UID of superuser is hardwired to 1 as of PG 7.3
(SELECT oid FROM pg_type WHERE typname = '_int4'),
false,
0);
-- get the comparators for _intments and store them in a tmp table
SELECT o.oid AS opoid, o.oprname
INTO TEMP TABLE _int_ops_tmp
FROM pg_operator o, pg_type t, pg_type tq
WHERE o.oprleft = t.oid and ( o.oprright = t.oid or o.oprright=tq.oid )
and t.typname = '_int4'
and tq.typname='query_int';
-- make sure we have the right operators
-- SELECT * from _int_ops_tmp;
-- using the tmp table, generate the amop entries
-- note: these operators are all lossy
-- _int_overlap
INSERT INTO pg_amop (amopclaid, amopstrategy, amopreqcheck, amopopr)
SELECT opcl.oid, 3, true, c.opoid
FROM pg_opclass opcl, _int_ops_tmp c
WHERE
opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
and opcname = 'gist__intbig_ops'
and c.oprname = '&&';
-- _int_contains
INSERT INTO pg_amop (amopclaid, amopstrategy, amopreqcheck, amopopr)
SELECT opcl.oid, 7, true, c.opoid
FROM pg_opclass opcl, _int_ops_tmp c
WHERE
opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
and opcname = 'gist__intbig_ops'
and c.oprname = '@';
-- _int_contained
INSERT INTO pg_amop (amopclaid, amopstrategy, amopreqcheck, amopopr)
SELECT opcl.oid, 8, true, c.opoid
FROM pg_opclass opcl, _int_ops_tmp c
WHERE
opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
and opcname = 'gist__intbig_ops'
and c.oprname = '~';
-- _int_same
INSERT INTO pg_amop (amopclaid, amopstrategy, amopreqcheck, amopopr)
SELECT opcl.oid, 6, true, c.opoid
FROM pg_opclass opcl, _int_ops_tmp c
WHERE
opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
and opcname = 'gist__intbig_ops'
and c.oprname = '=';
--boolean search
INSERT INTO pg_amop (amopclaid, amopstrategy, amopreqcheck, amopopr)
SELECT opcl.oid, 20, true, c.opoid
FROM pg_opclass opcl, _int_ops_tmp c
WHERE
opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
and opcname = 'gist__intbig_ops'
and c.oprname = '@@';
DROP TABLE _int_ops_tmp;
-- add the entries to amproc for the support methods
-- note the amprocnum numbers associated with each are specific!
INSERT INTO pg_amproc (amopclaid, amprocnum, amproc)
SELECT opcl.oid, 1, pro.oid
FROM pg_opclass opcl, pg_proc pro
WHERE
opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
and opcname = 'gist__intbig_ops'
and proname = 'g_intbig_consistent';
INSERT INTO pg_amproc (amopclaid, amprocnum, amproc)
SELECT opcl.oid, 2, pro.oid
FROM pg_opclass opcl, pg_proc pro
WHERE
opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
and opcname = 'gist__intbig_ops'
and proname = 'g_intbig_union';
INSERT INTO pg_amproc (amopclaid, amprocnum, amproc)
SELECT opcl.oid, 3, pro.oid
FROM pg_opclass opcl, pg_proc pro
WHERE
opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
and opcname = 'gist__intbig_ops'
and proname = 'g_intbig_compress';
INSERT INTO pg_amproc (amopclaid, amprocnum, amproc)
SELECT opcl.oid, 4, pro.oid
FROM pg_opclass opcl, pg_proc pro
WHERE
opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
and opcname = 'gist__intbig_ops'
and proname = 'g_intbig_decompress';
INSERT INTO pg_amproc (amopclaid, amprocnum, amproc)
SELECT opcl.oid, 5, pro.oid
FROM pg_opclass opcl, pg_proc pro
WHERE
opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
and opcname = 'gist__intbig_ops'
and proname = 'g_intbig_penalty';
INSERT INTO pg_amproc (amopclaid, amprocnum, amproc)
SELECT opcl.oid, 6, pro.oid
FROM pg_opclass opcl, pg_proc pro
WHERE
opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
and opcname = 'gist__intbig_ops'
and proname = 'g_intbig_picksplit';
INSERT INTO pg_amproc (amopclaid, amprocnum, amproc)
SELECT opcl.oid, 7, pro.oid
FROM pg_opclass opcl, pg_proc pro
WHERE
opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
and opcname = 'gist__intbig_ops'
and proname = 'g_intbig_same';
CREATE OPERATOR CLASS gist__intbig_ops
FOR TYPE _int4 USING gist AS
OPERATOR 3 && RECHECK,
OPERATOR 6 = RECHECK,
OPERATOR 7 @ RECHECK,
OPERATOR 8 ~ RECHECK,
OPERATOR 20 @@ (_int4, query_int) RECHECK,
FUNCTION 1 g_intbig_consistent (opaque, _int4, int4),
FUNCTION 2 g_intbig_union (bytea, opaque),
FUNCTION 3 g_intbig_compress (opaque),
FUNCTION 4 g_intbig_decompress (opaque),
FUNCTION 5 g_intbig_penalty (opaque, opaque, opaque),
FUNCTION 6 g_intbig_picksplit (opaque, opaque),
FUNCTION 7 g_intbig_same (_int4, _int4, opaque);
END TRANSACTION;

View File

@ -1,5 +1,5 @@
<!--
$Header: /cvsroot/pgsql/doc/src/sgml/ref/allfiles.sgml,v 1.42 2002/07/22 08:57:15 ishii Exp $
$Header: /cvsroot/pgsql/doc/src/sgml/ref/allfiles.sgml,v 1.43 2002/07/29 22:14:10 tgl Exp $
PostgreSQL documentation
Complete list of usable sgml source files in this directory.
-->
@ -61,6 +61,7 @@ Complete list of usable sgml source files in this directory.
<!entity createIndex system "create_index.sgml">
<!entity createLanguage system "create_language.sgml">
<!entity createOperator system "create_operator.sgml">
<!entity createOperatorClass system "create_opclass.sgml">
<!entity createRule system "create_rule.sgml">
<!entity createSchema system "create_schema.sgml">
<!entity createSequence system "create_sequence.sgml">
@ -82,6 +83,7 @@ Complete list of usable sgml source files in this directory.
<!entity dropIndex system "drop_index.sgml">
<!entity dropLanguage system "drop_language.sgml">
<!entity dropOperator system "drop_operator.sgml">
<!entity dropOperatorClass system "drop_opclass.sgml">
<!entity dropRule system "drop_rule.sgml">
<!entity dropSchema system "drop_schema.sgml">
<!entity dropSequence system "drop_sequence.sgml">

View File

@ -0,0 +1,316 @@
<!--
$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_opclass.sgml,v 1.1 2002/07/29 22:14:10 tgl Exp $
PostgreSQL documentation
-->
<refentry id="SQL-CREATEOPCLASS">
<refmeta>
<refentrytitle id="sql-createopclass-title">CREATE OPERATOR CLASS</refentrytitle>
<refmiscinfo>SQL - Language Statements</refmiscinfo>
</refmeta>
<refnamediv>
<refname>
CREATE OPERATOR CLASS
</refname>
<refpurpose>
define a new operator class for indexes
</refpurpose>
</refnamediv>
<refsynopsisdiv>
<refsynopsisdivinfo>
<date>2002-07-28</date>
</refsynopsisdivinfo>
<synopsis>
CREATE OPERATOR CLASS <replaceable class="parameter">name</replaceable> [ DEFAULT ] FOR TYPE <replaceable class="parameter">data_type</replaceable> USING <replaceable class="parameter">access_method</replaceable> AS
{ OPERATOR <replaceable class="parameter">strategy_number</replaceable> <replaceable class="parameter">operator_id</replaceable> [ ( <replaceable class="parameter">type</replaceable>, <replaceable class="parameter">type</replaceable> ) ] [ RECHECK ]
| FUNCTION <replaceable class="parameter">support_number</replaceable> <replaceable class="parameter">func_name</replaceable> ( <replaceable class="parameter">parameter_types</replaceable> )
| STORAGE <replaceable class="parameter">storage_type</replaceable>
} [, ... ]
</synopsis>
<refsect2 id="R2-SQL-CREATEOPCLASS-1">
<refsect2info>
<date>2002-07-28</date>
</refsect2info>
<title>
Inputs
</title>
<para>
<variablelist>
<varlistentry>
<term><replaceable class="parameter">name</replaceable></term>
<listitem>
<para>
The name of the operator class to be created.
The name may be schema-qualified.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>DEFAULT</></term>
<listitem>
<para>
If present, the operator class will become the default index
operator class for its datatype. At most one operator class
can be the default for a specific datatype and access method.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">data_type</replaceable></term>
<listitem>
<para>
The column datatype that this operator class is for.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">access_method</replaceable></term>
<listitem>
<para>
The name of the index access method this operator class is for.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">strategy_number</replaceable></term>
<listitem>
<para>
The index access method's strategy number for an operator associated
with the operator class.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">operator_id</replaceable></term>
<listitem>
<para>
The identifier (optionally schema-qualified) of an operator associated
with the operator class.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">type</replaceable></term>
<listitem>
<para>
The input datatype(s) of an operator, or <literal>NONE</> to
signify a left-unary or right-unary operator. The input datatypes
may be omitted in the normal case where they are the same as the
operator class's datatype.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>RECHECK</></term>
<listitem>
<para>
If present, the index is <quote>lossy</> for this operator,
and so the tuples retrieved using the index must be rechecked
to verify that they actually satisfy the qualification clause
involving this operator.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">support_number</replaceable></term>
<listitem>
<para>
The index access method's support procedure number for a function
associated with the operator class.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">func_name</replaceable></term>
<listitem>
<para>
The name (optionally schema-qualified) of a function that is
an index access method support procedure for the operator class.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">parameter_types</replaceable></term>
<listitem>
<para>
The parameter datatype(s) of the function.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">storage_type</replaceable></term>
<listitem>
<para>
The datatype actually stored in the index. Normally this is the
same as the column datatype, but some index access methods (only
GIST at this writing) allow it to be different. The
<literal>STORAGE</> clause must be omitted unless the index access
method allows a different type to be used.
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
</refsect2>
<refsect2 id="R2-SQL-CREATEOPCLASS-2">
<refsect2info>
<date>2002-07-28</date>
</refsect2info>
<title>
Outputs
</title>
<para>
<variablelist>
<varlistentry>
<term><computeroutput>
CREATE OPERATOR CLASS
</computeroutput></term>
<listitem>
<para>
Message returned if the operator class is successfully created.
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
</refsect2>
</refsynopsisdiv>
<refsect1 id="R1-SQL-CREATEOPCLASS-1">
<refsect1info>
<date>2002-07-28</date>
</refsect1info>
<title>
Description
</title>
<para>
<command>CREATE OPERATOR CLASS</command> defines a new operator class,
<replaceable class="parameter">name</replaceable>.
</para>
<para>
An operator class defines how a particular datatype can be used with
an index. The operator class specifies that certain operators will fill
particular roles or <quote>strategies</> for this datatype and this
access method. The operator class also specifies the support procedures to
be used by
the index access method when the operator class is selected for an
index column. All the operators and functions used by an operator
class must be defined before the operator class is created.
</para>
<para>
If a schema name is given then the operator class is created in the
specified schema. Otherwise it is created in the current schema (the one
at the front of the search path; see <literal>CURRENT_SCHEMA()</>).
Two operator classes in the same schema can have the same name only if they
are for different index access methods.
</para>
<para>
The user who defines an operator class becomes its owner. The user
must own the datatype for which the operator class is being defined,
and must have execute permission for all referenced operators and functions.
</para>
<para>
<command>CREATE OPERATOR CLASS</command> does not presently check
whether the class definition includes all the operators and functions
required by the index access method. It is the user's
responsibility to define a valid operator class.
</para>
<para>
Refer to the chapter on interfacing extensions to indexes in the
<citetitle>PostgreSQL Programmer's Guide</citetitle>
for further information.
</para>
<refsect2 id="R2-SQL-CREATEOPCLASS-3">
<refsect2info>
<date>2002-07-28</date>
</refsect2info>
<title>
Notes
</title>
<para>
Refer to
<xref linkend="sql-dropopclass" endterm="sql-dropopclass-title">
to delete user-defined operator classes from a database.
</para>
</refsect2>
</refsect1>
<refsect1 id="R1-SQL-CREATEOPCLASS-2">
<title>
Usage
</title>
<para>
The following example command defines a GiST index operator class
for datatype <literal>_int4</> (array of int4). See
<filename>contrib/intarray/</> for the complete example.
</para>
<programlisting>
CREATE OPERATOR CLASS gist__int_ops
DEFAULT FOR TYPE _int4 USING gist AS
OPERATOR 3 &&,
OPERATOR 6 = RECHECK,
OPERATOR 7 @,
OPERATOR 8 ~,
OPERATOR 20 @@ (_int4, query_int),
FUNCTION 1 g_int_consistent (opaque, _int4, int4),
FUNCTION 2 g_int_union (bytea, opaque),
FUNCTION 3 g_int_compress (opaque),
FUNCTION 4 g_int_decompress (opaque),
FUNCTION 5 g_int_penalty (opaque, opaque, opaque),
FUNCTION 6 g_int_picksplit (opaque, opaque),
FUNCTION 7 g_int_same (_int4, _int4, opaque);
</programlisting>
<para>
The <literal>OPERATOR</>, <literal>FUNCTION</>, and <literal>STORAGE</>
clauses may appear in any order.
</para>
</refsect1>
<refsect1 id="R1-SQL-CREATEOPCLASS-3">
<title>
Compatibility
</title>
<refsect2 id="R2-SQL-CREATEOPCLASS-4">
<refsect2info>
<date>2002-07-28</date>
</refsect2info>
<title>
SQL92
</title>
<para>
<command>CREATE OPERATOR CLASS</command>
is a <productname>PostgreSQL</productname> extension.
There is no <command>CREATE OPERATOR CLASS</command>
statement in <acronym>SQL92</acronym>.
</para>
</refsect2>
</refsect1>
</refentry>
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:nil
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
sgml-parent-document:nil
sgml-default-dtd-file:"../reference.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:"/usr/lib/sgml/catalog"
sgml-local-ecat-files:nil
End:
-->

View File

@ -0,0 +1,184 @@
<!--
$Header: /cvsroot/pgsql/doc/src/sgml/ref/drop_opclass.sgml,v 1.1 2002/07/29 22:14:10 tgl Exp $
PostgreSQL documentation
-->
<refentry id="SQL-DROPOPCLASS">
<refmeta>
<refentrytitle id="SQL-DROPOPCLASS-TITLE">DROP OPERATOR CLASS</refentrytitle>
<refmiscinfo>SQL - Language Statements</refmiscinfo>
</refmeta>
<refnamediv>
<refname>
DROP OPERATOR CLASS
</refname>
<refpurpose>
remove a user-defined operator class
</refpurpose>
</refnamediv>
<refsynopsisdiv>
<refsynopsisdivinfo>
<date>2002-07-28</date>
</refsynopsisdivinfo>
<synopsis>
DROP OPERATOR CLASS <replaceable class="PARAMETER">name</replaceable> USING <replaceable class="PARAMETER">access_method</replaceable> [ CASCADE | RESTRICT ]
</synopsis>
<refsect2 id="R2-SQL-DROPOPCLASS-1">
<refsect2info>
<date>2002-07-28</date>
</refsect2info>
<title>
Inputs
</title>
<para>
<variablelist>
<varlistentry>
<term><replaceable class="parameter">name</replaceable></term>
<listitem>
<para>
The name (optionally schema-qualified) of an existing operator class.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">access_method</replaceable></term>
<listitem>
<para>
The name of the index access method the operator class is for.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>CASCADE</term>
<listitem>
<para>
Automatically drop objects that depend on the operator class.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>RESTRICT</term>
<listitem>
<para>
Refuse to drop the operator class if there are any dependent objects.
This is the default.
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
</refsect2>
<refsect2 id="R2-SQL-DROPOPCLASS-2">
<refsect2info>
<date>2002-07-28</date>
</refsect2info>
<title>
Outputs
</title>
<para>
<variablelist>
<varlistentry>
<term><computeroutput>
DROP OPERATOR CLASS
</computeroutput></term>
<listitem>
<para>
The message returned if the command is successful.
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
</refsect2>
</refsynopsisdiv>
<refsect1 id="R1-SQL-DROPOPCLASS-1">
<refsect1info>
<date>2002-07-28</date>
</refsect1info>
<title>
Description
</title>
<para>
<command>DROP OPERATOR CLASS</command> drops an existing operator class
from the database.
To execute this command you must be the owner of the operator class.
</para>
<refsect2 id="R2-SQL-DROPOPCLASS-3">
<refsect2info>
<date>2002-07-28</date>
</refsect2info>
<title>
Notes
</title>
<para>
The <command>DROP OPERATOR CLASS</command> statement is a
<productname>PostgreSQL</productname>
language extension.
</para>
<para>
Refer to
<xref linkend="sql-createopclass" endterm="sql-createopclass-title">
for information on how to create operator classes.
</para>
</refsect2>
</refsect1>
<refsect1 id="R1-SQL-DROPOPCLASS-2">
<title>
Usage
</title>
<para>
Remove btree operator class <literal>widget_ops</literal>:
<programlisting>
DROP OPERATOR CLASS widget_ops USING btree;
</programlisting>
This command will not execute if there are any existing indexes
that use the operator class. Add <literal>CASCADE</> to drop
such indexes along with the operator class.
</para>
</refsect1>
<refsect1 id="R1-SQL-DROPOPCLASS-3">
<title>
Compatibility
</title>
<refsect2 id="R2-SQL-DROPOPCLASS-4">
<refsect2info>
<date>2002-07-28</date>
</refsect2info>
<title>
SQL92
</title>
<para>
There is no <command>DROP OPERATOR CLASS</command> in
<acronym>SQL92</acronym>.
</para>
</refsect2>
</refsect1>
</refentry>
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:nil
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
sgml-parent-document:nil
sgml-default-dtd-file:"../reference.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:"/usr/lib/sgml/catalog"
sgml-local-ecat-files:nil
End:
-->

View File

@ -1,5 +1,5 @@
<!--
$Header: /cvsroot/pgsql/doc/src/sgml/ref/drop_operator.sgml,v 1.17 2002/07/12 18:43:13 tgl Exp $
$Header: /cvsroot/pgsql/doc/src/sgml/ref/drop_operator.sgml,v 1.18 2002/07/29 22:14:10 tgl Exp $
PostgreSQL documentation
-->
@ -172,10 +172,6 @@ ERROR: RemoveOperator: right unary operator '<replaceable class="PARAMETER">oper
<xref linkend="sql-createoperator" endterm="sql-createoperator-title">
for information on how to create operators.
</para>
<para>
It is the user's responsibility to remove any access method
operator classes that rely on the deleted operator.
</para>
</refsect2>
</refsect1>

View File

@ -1,5 +1,5 @@
<!-- reference.sgml
$Header: /cvsroot/pgsql/doc/src/sgml/reference.sgml,v 1.31 2002/07/22 08:57:15 ishii Exp $
$Header: /cvsroot/pgsql/doc/src/sgml/reference.sgml,v 1.32 2002/07/29 22:14:10 tgl Exp $
PostgreSQL Reference Manual
-->
@ -70,6 +70,7 @@ PostgreSQL Reference Manual
&createIndex;
&createLanguage;
&createOperator;
&createOperatorClass;
&createRule;
&createSchema;
&createSequence;
@ -91,6 +92,7 @@ PostgreSQL Reference Manual
&dropIndex;
&dropLanguage;
&dropOperator;
&dropOperatorClass;
&dropRule;
&dropSchema;
&dropSequence;

View File

@ -1,5 +1,5 @@
<!--
$Header: /cvsroot/pgsql/doc/src/sgml/release.sgml,v 1.143 2002/07/20 15:12:55 tgl Exp $
$Header: /cvsroot/pgsql/doc/src/sgml/release.sgml,v 1.144 2002/07/29 22:14:10 tgl Exp $
-->
<appendix id="release">
@ -24,6 +24,7 @@ CDATA means the content is "SGML-free", so you can write without
worries about funny characters.
-->
<literallayout><![CDATA[
CREATE OPERATOR CLASS/DROP OPERATOR CLASS
CREATE CAST/DROP CAST
Sequences created by SERIAL column definitions now auto-drop with the column
Most forms of DROP now support RESTRICT and CASCADE options

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.71 2002/07/20 05:16:56 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.72 2002/07/29 22:14:10 tgl Exp $
*
* NOTES
* See acl.h.
@ -26,6 +26,7 @@
#include "catalog/pg_group.h"
#include "catalog/pg_language.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_shadow.h"
@ -1369,3 +1370,30 @@ pg_namespace_ownercheck(Oid nsp_oid, Oid userid)
return userid == owner_id;
}
/*
* Ownership check for an operator class (specified by OID).
*/
bool
pg_opclass_ownercheck(Oid opc_oid, Oid userid)
{
HeapTuple tuple;
AclId owner_id;
/* Superusers bypass all permission checking. */
if (superuser_arg(userid))
return true;
tuple = SearchSysCache(CLAOID,
ObjectIdGetDatum(opc_oid),
0, 0, 0);
if (!HeapTupleIsValid(tuple))
elog(ERROR, "pg_opclass_ownercheck: operator class %u not found",
opc_oid);
owner_id = ((Form_pg_opclass) GETSTRUCT(tuple))->opcowner;
ReleaseSysCache(tuple);
return userid == owner_id;
}

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/dependency.c,v 1.6 2002/07/25 10:07:10 ishii Exp $
* $Header: /cvsroot/pgsql/src/backend/catalog/dependency.c,v 1.7 2002/07/29 22:14:10 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -21,15 +21,16 @@
#include "catalog/heap.h"
#include "catalog/index.h"
#include "catalog/indexing.h"
#include "catalog/namespace.h"
#include "catalog/pg_attrdef.h"
#include "catalog/pg_cast.h"
#include "catalog/pg_constraint.h"
#include "catalog/pg_conversion.h"
#include "catalog/pg_depend.h"
#include "catalog/pg_language.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_rewrite.h"
#include "catalog/pg_trigger.h"
#include "catalog/pg_type.h"
#include "commands/comment.h"
#include "commands/defrem.h"
#include "commands/proclang.h"
@ -40,6 +41,7 @@
#include "optimizer/clauses.h"
#include "parser/parsetree.h"
#include "rewrite/rewriteRemove.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
@ -48,15 +50,16 @@
/* This enum covers all system catalogs whose OIDs can appear in classid. */
typedef enum ObjectClasses
{
OCLASS_CAST, /* pg_cast */
OCLASS_CLASS, /* pg_class */
OCLASS_PROC, /* pg_proc */
OCLASS_TYPE, /* pg_type */
OCLASS_CAST, /* pg_cast */
OCLASS_CONSTRAINT, /* pg_constraint */
OCLASS_CONVERSION, /* pg_conversion */
OCLASS_DEFAULT, /* pg_attrdef */
OCLASS_LANGUAGE, /* pg_language */
OCLASS_OPERATOR, /* pg_operator */
OCLASS_OPCLASS, /* pg_opclass */
OCLASS_REWRITE, /* pg_rewrite */
OCLASS_TRIGGER, /* pg_trigger */
OCLASS_SCHEMA, /* pg_namespace */
@ -579,6 +582,10 @@ doDeletion(const ObjectAddress *object)
RemoveTypeById(object->objectId);
break;
case OCLASS_CAST:
DropCastById(object->objectId);
break;
case OCLASS_CONSTRAINT:
RemoveConstraintById(object->objectId);
break;
@ -599,6 +606,10 @@ doDeletion(const ObjectAddress *object)
RemoveOperatorById(object->objectId);
break;
case OCLASS_OPCLASS:
RemoveOpClassById(object->objectId);
break;
case OCLASS_REWRITE:
RemoveRewriteRuleById(object->objectId);
break;
@ -611,10 +622,6 @@ doDeletion(const ObjectAddress *object)
RemoveSchemaById(object->objectId);
break;
case OCLASS_CAST:
DropCastById(object->objectId);
break;
default:
elog(ERROR, "doDeletion: Unsupported object class %u",
object->classId);
@ -990,15 +997,16 @@ term_object_addresses(ObjectAddresses *addrs)
static void
init_object_classes(void)
{
object_classes[OCLASS_CAST] = get_system_catalog_relid(CastRelationName);
object_classes[OCLASS_CLASS] = RelOid_pg_class;
object_classes[OCLASS_PROC] = RelOid_pg_proc;
object_classes[OCLASS_TYPE] = RelOid_pg_type;
object_classes[OCLASS_CAST] = get_system_catalog_relid(CastRelationName);
object_classes[OCLASS_CONSTRAINT] = get_system_catalog_relid(ConstraintRelationName);
object_classes[OCLASS_CONVERSION] = get_system_catalog_relid(ConversionRelationName);
object_classes[OCLASS_DEFAULT] = get_system_catalog_relid(AttrDefaultRelationName);
object_classes[OCLASS_LANGUAGE] = get_system_catalog_relid(LanguageRelationName);
object_classes[OCLASS_OPERATOR] = get_system_catalog_relid(OperatorRelationName);
object_classes[OCLASS_OPCLASS] = get_system_catalog_relid(OperatorClassRelationName);
object_classes[OCLASS_REWRITE] = get_system_catalog_relid(RewriteRelationName);
object_classes[OCLASS_TRIGGER] = get_system_catalog_relid(TriggerRelationName);
object_classes[OCLASS_SCHEMA] = get_system_catalog_relid(NamespaceRelationName);
@ -1066,6 +1074,11 @@ getObjectClass(const ObjectAddress *object)
Assert(object->objectSubId == 0);
return OCLASS_OPERATOR;
}
if (object->classId == object_classes[OCLASS_OPCLASS])
{
Assert(object->objectSubId == 0);
return OCLASS_OPCLASS;
}
if (object->classId == object_classes[OCLASS_REWRITE])
{
Assert(object->objectSubId == 0);
@ -1101,10 +1114,6 @@ getObjectDescription(const ObjectAddress *object)
switch (getObjectClass(object))
{
case OCLASS_CAST:
appendStringInfo(&buffer, "cast");
break;
case OCLASS_CLASS:
getRelationDescription(&buffer, object->objectId);
if (object->objectSubId != 0)
@ -1114,24 +1123,46 @@ getObjectDescription(const ObjectAddress *object)
break;
case OCLASS_PROC:
/* XXX could improve on this */
appendStringInfo(&buffer, "function %s",
get_func_name(object->objectId));
format_procedure(object->objectId));
break;
case OCLASS_TYPE:
{
HeapTuple typeTup;
typeTup = SearchSysCache(TYPEOID,
ObjectIdGetDatum(object->objectId),
0, 0, 0);
if (!HeapTupleIsValid(typeTup))
elog(ERROR, "getObjectDescription: Type %u does not exist",
object->objectId);
appendStringInfo(&buffer, "type %s",
NameStr(((Form_pg_type) GETSTRUCT(typeTup))->typname));
ReleaseSysCache(typeTup);
format_type_be(object->objectId));
break;
case OCLASS_CAST:
{
Relation castDesc;
ScanKeyData skey[1];
SysScanDesc rcscan;
HeapTuple tup;
Form_pg_cast castForm;
castDesc = heap_openr(CastRelationName, AccessShareLock);
ScanKeyEntryInitialize(&skey[0], 0x0,
ObjectIdAttributeNumber, F_OIDEQ,
ObjectIdGetDatum(object->objectId));
rcscan = systable_beginscan(castDesc, CastOidIndex, true,
SnapshotNow, 1, skey);
tup = systable_getnext(rcscan);
if (!HeapTupleIsValid(tup))
elog(ERROR, "getObjectDescription: Cast %u does not exist",
object->objectId);
castForm = (Form_pg_cast) GETSTRUCT(tup);
appendStringInfo(&buffer, "cast from %s to %s",
format_type_be(castForm->castsource),
format_type_be(castForm->casttarget));
systable_endscan(rcscan);
heap_close(castDesc, AccessShareLock);
break;
}
@ -1248,11 +1279,52 @@ getObjectDescription(const ObjectAddress *object)
}
case OCLASS_OPERATOR:
/* XXX could improve on this */
appendStringInfo(&buffer, "operator %s",
get_opname(object->objectId));
format_operator(object->objectId));
break;
case OCLASS_OPCLASS:
{
HeapTuple opcTup;
Form_pg_opclass opcForm;
HeapTuple amTup;
Form_pg_am amForm;
char *nspname;
opcTup = SearchSysCache(CLAOID,
ObjectIdGetDatum(object->objectId),
0, 0, 0);
if (!HeapTupleIsValid(opcTup))
elog(ERROR, "cache lookup of opclass %u failed",
object->objectId);
opcForm = (Form_pg_opclass) GETSTRUCT(opcTup);
/* Qualify the name if not visible in search path */
if (OpclassIsVisible(object->objectId))
nspname = NULL;
else
nspname = get_namespace_name(opcForm->opcnamespace);
appendStringInfo(&buffer, "operator class %s",
quote_qualified_identifier(nspname,
NameStr(opcForm->opcname)));
amTup = SearchSysCache(AMOID,
ObjectIdGetDatum(opcForm->opcamid),
0, 0, 0);
if (!HeapTupleIsValid(amTup))
elog(ERROR, "syscache lookup for AM %u failed",
opcForm->opcamid);
amForm = (Form_pg_am) GETSTRUCT(amTup);
appendStringInfo(&buffer, " for %s",
NameStr(amForm->amname));
ReleaseSysCache(amTup);
ReleaseSysCache(opcTup);
break;
}
case OCLASS_REWRITE:
{
Relation ruleDesc;
@ -1323,17 +1395,13 @@ getObjectDescription(const ObjectAddress *object)
case OCLASS_SCHEMA:
{
HeapTuple schemaTup;
char *nspname;
schemaTup = SearchSysCache(NAMESPACEOID,
ObjectIdGetDatum(object->objectId),
0, 0, 0);
if (!HeapTupleIsValid(schemaTup))
nspname = get_namespace_name(object->objectId);
if (!nspname)
elog(ERROR, "getObjectDescription: Schema %u does not exist",
object->objectId);
appendStringInfo(&buffer, "schema %s",
NameStr(((Form_pg_namespace) GETSTRUCT(schemaTup))->nspname));
ReleaseSysCache(schemaTup);
appendStringInfo(&buffer, "schema %s", nspname);
break;
}
@ -1356,49 +1424,58 @@ getRelationDescription(StringInfo buffer, Oid relid)
{
HeapTuple relTup;
Form_pg_class relForm;
char *nspname;
char *relname;
relTup = SearchSysCache(RELOID,
ObjectIdGetDatum(relid),
0, 0, 0);
if (!HeapTupleIsValid(relTup))
elog(ERROR, "getObjectDescription: Relation %u does not exist",
relid);
elog(ERROR, "cache lookup of relation %u failed", relid);
relForm = (Form_pg_class) GETSTRUCT(relTup);
/* Qualify the name if not visible in search path */
if (RelationIsVisible(relid))
nspname = NULL;
else
nspname = get_namespace_name(relForm->relnamespace);
relname = quote_qualified_identifier(nspname, NameStr(relForm->relname));
switch (relForm->relkind)
{
case RELKIND_RELATION:
appendStringInfo(buffer, "table %s",
NameStr(relForm->relname));
relname);
break;
case RELKIND_INDEX:
appendStringInfo(buffer, "index %s",
NameStr(relForm->relname));
relname);
break;
case RELKIND_SPECIAL:
appendStringInfo(buffer, "special system relation %s",
NameStr(relForm->relname));
relname);
break;
case RELKIND_SEQUENCE:
appendStringInfo(buffer, "sequence %s",
NameStr(relForm->relname));
relname);
break;
case RELKIND_UNCATALOGED:
appendStringInfo(buffer, "uncataloged table %s",
NameStr(relForm->relname));
relname);
break;
case RELKIND_TOASTVALUE:
appendStringInfo(buffer, "toast table %s",
NameStr(relForm->relname));
relname);
break;
case RELKIND_VIEW:
appendStringInfo(buffer, "view %s",
NameStr(relForm->relname));
relname);
break;
default:
/* shouldn't get here */
appendStringInfo(buffer, "relation %s",
NameStr(relForm->relname));
relname);
break;
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.186 2002/07/20 05:16:56 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.187 2002/07/29 22:14:10 tgl Exp $
*
*
* INTERFACE ROUTINES
@ -712,7 +712,7 @@ index_create(Oid heapRelationId,
false, /* isDeferred */
heapRelationId,
indexInfo->ii_KeyAttrNumbers,
indexInfo->ii_NumIndexAttrs,
indexInfo->ii_NumKeyAttrs,
InvalidOid, /* no domain */
InvalidOid, /* no foreign key */
NULL,
@ -732,7 +732,7 @@ index_create(Oid heapRelationId,
}
else
{
for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
for (i = 0; i < indexInfo->ii_NumKeyAttrs; i++)
{
referenced.classId = RelOid_pg_class;
referenced.objectId = heapRelationId;
@ -742,6 +742,16 @@ index_create(Oid heapRelationId,
}
}
/* Store dependency on operator classes */
referenced.classId = get_system_catalog_relid(OperatorClassRelationName);
for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
{
referenced.objectId = classObjectId[i];
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
}
/* Store the dependency on the function (if appropriate) */
if (OidIsValid(indexInfo->ii_FuncOid))
{

View File

@ -4,7 +4,7 @@
# Makefile for backend/commands
#
# IDENTIFICATION
# $Header: /cvsroot/pgsql/src/backend/commands/Makefile,v 1.29 2002/07/11 07:39:27 ishii Exp $
# $Header: /cvsroot/pgsql/src/backend/commands/Makefile,v 1.30 2002/07/29 22:14:10 tgl Exp $
#
#-------------------------------------------------------------------------
@ -15,7 +15,8 @@ include $(top_builddir)/src/Makefile.global
OBJS = aggregatecmds.o analyze.o async.o cluster.o comment.o \
conversioncmds.o copy.o \
dbcommands.o define.o explain.o functioncmds.o \
indexcmds.o lockcmds.o operatorcmds.o portalcmds.o proclang.o \
indexcmds.o lockcmds.o operatorcmds.o opclasscmds.o \
portalcmds.o proclang.o \
schemacmds.o sequence.o tablecmds.o trigger.o typecmds.o user.o \
vacuum.o vacuumlazy.o variable.o view.o

View File

@ -0,0 +1,639 @@
/*-------------------------------------------------------------------------
*
* opclasscmds.c
*
* Routines for opclass manipulation commands
*
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/opclasscmds.c,v 1.1 2002/07/29 22:14:10 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/genam.h"
#include "access/heapam.h"
#include "catalog/catname.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/namespace.h"
#include "catalog/pg_am.h"
#include "catalog/pg_amop.h"
#include "catalog/pg_amproc.h"
#include "catalog/pg_opclass.h"
#include "commands/defrem.h"
#include "miscadmin.h"
#include "parser/parse_func.h"
#include "parser/parse_oper.h"
#include "parser/parse_type.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
static void storeOperators(Oid opclassoid, int numOperators,
Oid *operators, bool *recheck);
static void storeProcedures(Oid opclassoid, int numProcs, Oid *procedures);
/*
* DefineOpClass
* Define a new index operator class.
*/
void
DefineOpClass(CreateOpClassStmt *stmt)
{
char *opcname; /* name of opclass we're creating */
Oid amoid, /* our AM's oid */
typeoid, /* indexable datatype oid */
storageoid, /* storage datatype oid, if any */
namespaceoid, /* namespace to create opclass in */
opclassoid; /* oid of opclass we create */
int numOperators, /* amstrategies value */
numProcs; /* amsupport value */
Oid *operators, /* oids of operators, by strategy num */
*procedures; /* oids of support procs */
bool *recheck; /* do operators need recheck */
List *iteml;
Relation rel;
HeapTuple tup;
Datum values[Natts_pg_opclass];
char nulls[Natts_pg_opclass];
AclResult aclresult;
NameData opcName;
int i;
ObjectAddress myself,
referenced;
/* Convert list of names to a name and namespace */
namespaceoid = QualifiedNameGetCreationNamespace(stmt->opclassname,
&opcname);
/* Check we have creation rights in target namespace */
aclresult = pg_namespace_aclcheck(namespaceoid, GetUserId(), ACL_CREATE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, get_namespace_name(namespaceoid));
/* Get necessary info about access method */
tup = SearchSysCache(AMNAME,
CStringGetDatum(stmt->amname),
0, 0, 0);
if (!HeapTupleIsValid(tup))
elog(ERROR, "DefineOpClass: access method \"%s\" not found",
stmt->amname);
amoid = HeapTupleGetOid(tup);
numOperators = ((Form_pg_am) GETSTRUCT(tup))->amstrategies;
numProcs = ((Form_pg_am) GETSTRUCT(tup))->amsupport;
/* XXX Should we make any privilege check against the AM? */
ReleaseSysCache(tup);
/* Look up the datatype */
typeoid = typenameTypeId(stmt->datatype);
/* Check we have ownership of the datatype */
if (!pg_type_ownercheck(typeoid, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, format_type_be(typeoid));
/* Storage datatype is optional */
storageoid = InvalidOid;
/*
* Create work arrays to hold info about operators and procedures.
* We do this mainly so that we can detect duplicate strategy
* numbers and support-proc numbers.
*/
operators = (Oid *) palloc(sizeof(Oid) * numOperators);
MemSet(operators, 0, sizeof(Oid) * numOperators);
procedures = (Oid *) palloc(sizeof(Oid) * numProcs);
MemSet(procedures, 0, sizeof(Oid) * numProcs);
recheck = (bool *) palloc(sizeof(bool) * numOperators);
MemSet(recheck, 0, sizeof(bool) * numOperators);
/*
* Scan the "items" list to obtain additional info.
*/
foreach(iteml, stmt->items)
{
CreateOpClassItem *item = lfirst(iteml);
Oid operOid;
Oid funcOid;
AclResult aclresult;
Assert(IsA(item, CreateOpClassItem));
switch (item->itemtype)
{
case OPCLASS_ITEM_OPERATOR:
if (item->number <= 0 || item->number > numOperators)
elog(ERROR, "DefineOpClass: invalid operator number %d,"
" must be between 1 and %d",
item->number, numOperators);
if (operators[item->number - 1] != InvalidOid)
elog(ERROR, "DefineOpClass: operator number %d appears more than once",
item->number);
if (item->args != NIL)
{
TypeName *typeName1 = (TypeName *) lfirst(item->args);
TypeName *typeName2 = (TypeName *) lsecond(item->args);
operOid = LookupOperNameTypeNames(item->name,
typeName1, typeName2,
"DefineOpClass");
/* No need to check for error */
}
else
{
/* Default to binary op on input datatype */
operOid = LookupOperName(item->name, typeoid, typeoid);
if (!OidIsValid(operOid))
elog(ERROR, "DefineOpClass: Operator '%s' for types '%s' and '%s' does not exist",
NameListToString(item->name),
format_type_be(typeoid),
format_type_be(typeoid));
}
/* Caller must have execute permission on operators */
funcOid = get_opcode(operOid);
aclresult = pg_proc_aclcheck(funcOid, GetUserId(),
ACL_EXECUTE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, get_func_name(funcOid));
operators[item->number - 1] = operOid;
recheck[item->number - 1] = item->recheck;
break;
case OPCLASS_ITEM_FUNCTION:
if (item->number <= 0 || item->number > numProcs)
elog(ERROR, "DefineOpClass: invalid procedure number %d,"
" must be between 1 and %d",
item->number, numProcs);
if (procedures[item->number - 1] != InvalidOid)
elog(ERROR, "DefineOpClass: procedure number %d appears more than once",
item->number);
funcOid = LookupFuncNameTypeNames(item->name, item->args,
true, "DefineOpClass");
/* Caller must have execute permission on functions */
aclresult = pg_proc_aclcheck(funcOid, GetUserId(),
ACL_EXECUTE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, get_func_name(funcOid));
procedures[item->number - 1] = funcOid;
break;
case OPCLASS_ITEM_STORAGETYPE:
if (OidIsValid(storageoid))
elog(ERROR, "DefineOpClass: storage type specified more than once");
storageoid = typenameTypeId(item->storedtype);
break;
default:
elog(ERROR, "DefineOpClass: bogus item type %d",
item->itemtype);
break;
}
}
/*
* If storagetype is specified, make sure it's legal.
*/
if (OidIsValid(storageoid))
{
/* Just drop the spec if same as column datatype */
if (storageoid == typeoid)
storageoid = InvalidOid;
else
{
/*
* Currently, only GiST allows storagetype different from
* datatype. This hardcoded test should be eliminated in
* favor of adding another boolean column to pg_am ...
*/
if (amoid != GIST_AM_OID)
elog(ERROR, "Storage type may not be different from datatype for access method %s",
stmt->amname);
}
}
rel = heap_openr(OperatorClassRelationName, RowExclusiveLock);
/*
* Make sure there is no existing opclass of this name (this is
* just to give a more friendly error message than "duplicate key").
*/
if (SearchSysCacheExists(CLAAMNAMENSP,
ObjectIdGetDatum(amoid),
CStringGetDatum(opcname),
ObjectIdGetDatum(namespaceoid),
0))
elog(ERROR, "Operator class \"%s\" already exists for access method \"%s\"",
opcname, stmt->amname);
/*
* If we are creating a default opclass, check there isn't one already.
* (XXX should we restrict this test to visible opclasses?)
*/
if (stmt->isDefault)
{
ScanKeyData skey[1];
SysScanDesc scan;
ScanKeyEntryInitialize(&skey[0], 0x0,
Anum_pg_opclass_opcamid, F_OIDEQ,
ObjectIdGetDatum(amoid));
scan = systable_beginscan(rel, OpclassAmNameNspIndex, true,
SnapshotNow, 1, skey);
while (HeapTupleIsValid(tup = systable_getnext(scan)))
{
Form_pg_opclass opclass = (Form_pg_opclass) GETSTRUCT(tup);
if (opclass->opcintype == typeoid && opclass->opcdefault)
elog(ERROR, "Can't add class \"%s\" as default for type %s"
"\n\tclass \"%s\" already is the default",
opcname,
TypeNameToString(stmt->datatype),
NameStr(opclass->opcname));
}
systable_endscan(scan);
}
/*
* Okay, let's create the pg_opclass entry.
*/
for (i = 0; i < Natts_pg_opclass; ++i)
{
nulls[i] = ' ';
values[i] = (Datum) NULL; /* redundant, but safe */
}
i = 0;
values[i++] = ObjectIdGetDatum(amoid); /* opcamid */
namestrcpy(&opcName, opcname);
values[i++] = NameGetDatum(&opcName); /* opcname */
values[i++] = ObjectIdGetDatum(namespaceoid); /* opcnamespace */
values[i++] = Int32GetDatum(GetUserId()); /* opcowner */
values[i++] = ObjectIdGetDatum(typeoid); /* opcintype */
values[i++] = BoolGetDatum(stmt->isDefault); /* opcdefault */
values[i++] = ObjectIdGetDatum(storageoid); /* opckeytype */
tup = heap_formtuple(rel->rd_att, values, nulls);
opclassoid = simple_heap_insert(rel, tup);
if (RelationGetForm(rel)->relhasindex)
{
Relation idescs[Num_pg_opclass_indices];
CatalogOpenIndices(Num_pg_opclass_indices, Name_pg_opclass_indices,
idescs);
CatalogIndexInsert(idescs, Num_pg_opclass_indices, rel, tup);
CatalogCloseIndices(Num_pg_opclass_indices, idescs);
}
heap_freetuple(tup);
/*
* Now add tuples to pg_amop and pg_amproc tying in the
* operators and functions.
*/
storeOperators(opclassoid, numOperators, operators, recheck);
storeProcedures(opclassoid, numProcs, procedures);
/*
* Create dependencies. Note: we do not create a dependency link to
* the AM, because we don't currently support DROP ACCESS METHOD.
*/
myself.classId = RelationGetRelid(rel);
myself.objectId = opclassoid;
myself.objectSubId = 0;
/* dependency on namespace */
referenced.classId = get_system_catalog_relid(NamespaceRelationName);
referenced.objectId = namespaceoid;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
/* dependency on indexed datatype */
referenced.classId = RelOid_pg_type;
referenced.objectId = typeoid;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
/* dependency on storage datatype */
if (OidIsValid(storageoid))
{
referenced.classId = RelOid_pg_type;
referenced.objectId = storageoid;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
}
/* dependencies on operators */
referenced.classId = get_system_catalog_relid(OperatorRelationName);
for (i = 0; i < numOperators; i++)
{
if (operators[i] == InvalidOid)
continue;
referenced.objectId = operators[i];
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
}
/* dependencies on procedures */
for (i = 0; i < numProcs; i++)
{
if (procedures[i] == InvalidOid)
continue;
referenced.classId = RelOid_pg_proc;
referenced.objectId = procedures[i];
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
}
heap_close(rel, RowExclusiveLock);
}
/*
* Dump the operators to pg_amop
*/
static void
storeOperators(Oid opclassoid, int numOperators,
Oid *operators, bool *recheck)
{
Relation rel;
Datum values[Natts_pg_amop];
char nulls[Natts_pg_amop];
HeapTuple tup;
int i, j;
rel = heap_openr(AccessMethodOperatorRelationName, RowExclusiveLock);
for (j = 0; j < numOperators; j++)
{
if (operators[j] == InvalidOid)
continue;
for (i = 0; i < Natts_pg_amop; ++i)
{
nulls[i] = ' ';
values[i] = (Datum) NULL;
}
i = 0;
values[i++] = ObjectIdGetDatum(opclassoid); /* amopclaid */
values[i++] = Int16GetDatum(j + 1); /* amopstrategy */
values[i++] = BoolGetDatum(recheck[j]); /* amopreqcheck */
values[i++] = ObjectIdGetDatum(operators[j]); /* amopopr */
tup = heap_formtuple(rel->rd_att, values, nulls);
simple_heap_insert(rel, tup);
if (RelationGetForm(rel)->relhasindex)
{
Relation idescs[Num_pg_amop_indices];
CatalogOpenIndices(Num_pg_amop_indices, Name_pg_amop_indices,
idescs);
CatalogIndexInsert(idescs, Num_pg_amop_indices, rel, tup);
CatalogCloseIndices(Num_pg_amop_indices, idescs);
}
heap_freetuple(tup);
}
heap_close(rel, RowExclusiveLock);
}
/*
* Dump the procedures (support routines) to pg_amproc
*/
static void
storeProcedures(Oid opclassoid, int numProcs, Oid *procedures)
{
Relation rel;
Datum values[Natts_pg_amproc];
char nulls[Natts_pg_amproc];
HeapTuple tup;
int i, j;
rel = heap_openr(AccessMethodProcedureRelationName, RowExclusiveLock);
for (j = 0; j < numProcs; j++)
{
if (procedures[j] == InvalidOid)
continue;
for (i = 0; i < Natts_pg_amproc; ++i)
{
nulls[i] = ' ';
values[i] = (Datum) NULL;
}
i = 0;
values[i++] = ObjectIdGetDatum(opclassoid); /* amopclaid */
values[i++] = Int16GetDatum(j + 1); /* amprocnum */
values[i++] = ObjectIdGetDatum(procedures[j]); /* amproc */
tup = heap_formtuple(rel->rd_att, values, nulls);
simple_heap_insert(rel, tup);
if (RelationGetForm(rel)->relhasindex)
{
Relation idescs[Num_pg_amproc_indices];
CatalogOpenIndices(Num_pg_amproc_indices, Name_pg_amproc_indices,
idescs);
CatalogIndexInsert(idescs, Num_pg_amproc_indices, rel, tup);
CatalogCloseIndices(Num_pg_amproc_indices, idescs);
}
heap_freetuple(tup);
}
heap_close(rel, RowExclusiveLock);
}
/*
* RemoveOpClass
* Deletes an opclass.
*/
void
RemoveOpClass(RemoveOpClassStmt *stmt)
{
Oid amID, opcID;
char *catalogname;
char *schemaname = NULL;
char *opcname = NULL;
HeapTuple tuple;
ObjectAddress object;
/*
* Get the access method's OID.
*/
amID = GetSysCacheOid(AMNAME,
CStringGetDatum(stmt->amname),
0, 0, 0);
if (!OidIsValid(amID))
elog(ERROR, "RemoveOpClass: access method \"%s\" not found",
stmt->amname);
/*
* Look up the opclass.
*/
/* deconstruct the name list */
switch (length(stmt->opclassname))
{
case 1:
opcname = strVal(lfirst(stmt->opclassname));
break;
case 2:
schemaname = strVal(lfirst(stmt->opclassname));
opcname = strVal(lsecond(stmt->opclassname));
break;
case 3:
catalogname = strVal(lfirst(stmt->opclassname));
schemaname = strVal(lsecond(stmt->opclassname));
opcname = strVal(lfirst(lnext(lnext(stmt->opclassname))));
/*
* We check the catalog name and then ignore it.
*/
if (strcmp(catalogname, DatabaseName) != 0)
elog(ERROR, "Cross-database references are not implemented");
break;
default:
elog(ERROR, "Improper opclass name (too many dotted names): %s",
NameListToString(stmt->opclassname));
break;
}
if (schemaname)
{
/* Look in specific schema only */
Oid namespaceId;
namespaceId = GetSysCacheOid(NAMESPACENAME,
CStringGetDatum(schemaname),
0, 0, 0);
if (!OidIsValid(namespaceId))
elog(ERROR, "Namespace \"%s\" does not exist",
schemaname);
tuple = SearchSysCache(CLAAMNAMENSP,
ObjectIdGetDatum(amID),
PointerGetDatum(opcname),
ObjectIdGetDatum(namespaceId),
0);
}
else
{
/* Unqualified opclass name, so search the search path */
opcID = OpclassnameGetOpcid(amID, opcname);
if (!OidIsValid(opcID))
elog(ERROR, "RemoveOpClass: operator class \"%s\" not supported by access method \"%s\"",
opcname, stmt->amname);
tuple = SearchSysCache(CLAOID,
ObjectIdGetDatum(opcID),
0, 0, 0);
}
if (!HeapTupleIsValid(tuple))
elog(ERROR, "RemoveOpClass: operator class \"%s\" not supported by access method \"%s\"",
NameListToString(stmt->opclassname), stmt->amname);
opcID = HeapTupleGetOid(tuple);
/* Permission check: must own opclass or its namespace */
if (!pg_opclass_ownercheck(opcID, GetUserId()) &&
!pg_namespace_ownercheck(((Form_pg_opclass) GETSTRUCT(tuple))->opcnamespace,
GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER,
NameListToString(stmt->opclassname));
ReleaseSysCache(tuple);
/*
* Do the deletion
*/
object.classId = get_system_catalog_relid(OperatorClassRelationName);
object.objectId = opcID;
object.objectSubId = 0;
performDeletion(&object, stmt->behavior);
}
/*
* Guts of opclass deletion.
*/
void
RemoveOpClassById(Oid opclassOid)
{
Relation rel;
HeapTuple tup;
ScanKeyData skey[1];
SysScanDesc scan;
/*
* First remove the pg_opclass entry itself.
*/
rel = heap_openr(OperatorClassRelationName, RowExclusiveLock);
tup = SearchSysCache(CLAOID,
ObjectIdGetDatum(opclassOid),
0, 0, 0);
if (!HeapTupleIsValid(tup)) /* should not happen */
elog(ERROR, "RemoveOpClassById: couldn't find pg_class entry %u",
opclassOid);
simple_heap_delete(rel, &tup->t_self);
ReleaseSysCache(tup);
heap_close(rel, RowExclusiveLock);
/*
* Remove associated entries in pg_amop.
*/
ScanKeyEntryInitialize(&skey[0], 0,
Anum_pg_amop_amopclaid, F_OIDEQ,
ObjectIdGetDatum(opclassOid));
rel = heap_openr(AccessMethodOperatorRelationName, RowExclusiveLock);
scan = systable_beginscan(rel, AccessMethodStrategyIndex, true,
SnapshotNow, 1, skey);
while (HeapTupleIsValid(tup = systable_getnext(scan)))
{
simple_heap_delete(rel, &tup->t_self);
}
systable_endscan(scan);
heap_close(rel, RowExclusiveLock);
/*
* Remove associated entries in pg_amproc.
*/
ScanKeyEntryInitialize(&skey[0], 0,
Anum_pg_amproc_amopclaid, F_OIDEQ,
ObjectIdGetDatum(opclassOid));
rel = heap_openr(AccessMethodProcedureRelationName, RowExclusiveLock);
scan = systable_beginscan(rel, AccessMethodProcedureIndex, true,
SnapshotNow, 1, skey);
while (HeapTupleIsValid(tup = systable_getnext(scan)))
{
simple_heap_delete(rel, &tup->t_self);
}
systable_endscan(scan);
heap_close(rel, RowExclusiveLock);
}

View File

@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.197 2002/07/24 19:11:10 petere Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.198 2002/07/29 22:14:10 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -2147,6 +2147,19 @@ _copyRemoveOperStmt(RemoveOperStmt *from)
return newnode;
}
static RemoveOpClassStmt *
_copyRemoveOpClassStmt(RemoveOpClassStmt *from)
{
RemoveOpClassStmt *newnode = makeNode(RemoveOpClassStmt);
Node_Copy(from, newnode, opclassname);
if (from->amname)
newnode->amname = pstrdup(from->amname);
newnode->behavior = from->behavior;
return newnode;
}
static RenameStmt *
_copyRenameStmt(RenameStmt *from)
{
@ -2252,6 +2265,36 @@ _copyCreateDomainStmt(CreateDomainStmt *from)
return newnode;
}
static CreateOpClassStmt *
_copyCreateOpClassStmt(CreateOpClassStmt *from)
{
CreateOpClassStmt *newnode = makeNode(CreateOpClassStmt);
Node_Copy(from, newnode, opclassname);
if (from->amname)
newnode->amname = pstrdup(from->amname);
Node_Copy(from, newnode, datatype);
Node_Copy(from, newnode, items);
newnode->isDefault = from->isDefault;
return newnode;
}
static CreateOpClassItem *
_copyCreateOpClassItem(CreateOpClassItem *from)
{
CreateOpClassItem *newnode = makeNode(CreateOpClassItem);
newnode->itemtype = from->itemtype;
Node_Copy(from, newnode, name);
Node_Copy(from, newnode, args);
newnode->number = from->number;
newnode->recheck = from->recheck;
Node_Copy(from, newnode, storedtype);
return newnode;
}
static CreatedbStmt *
_copyCreatedbStmt(CreatedbStmt *from)
{
@ -2872,6 +2915,9 @@ copyObject(void *from)
case T_RemoveOperStmt:
retval = _copyRemoveOperStmt(from);
break;
case T_RemoveOpClassStmt:
retval = _copyRemoveOpClassStmt(from);
break;
case T_RenameStmt:
retval = _copyRenameStmt(from);
break;
@ -2899,6 +2945,12 @@ copyObject(void *from)
case T_CreateDomainStmt:
retval = _copyCreateDomainStmt(from);
break;
case T_CreateOpClassStmt:
retval = _copyCreateOpClassStmt(from);
break;
case T_CreateOpClassItem:
retval = _copyCreateOpClassItem(from);
break;
case T_CreatedbStmt:
retval = _copyCreatedbStmt(from);
break;

View File

@ -20,7 +20,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.144 2002/07/24 19:11:10 petere Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.145 2002/07/29 22:14:10 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -976,6 +976,18 @@ _equalRemoveOperStmt(RemoveOperStmt *a, RemoveOperStmt *b)
return true;
}
static bool
_equalRemoveOpClassStmt(RemoveOpClassStmt *a, RemoveOpClassStmt *b)
{
if (!equal(a->opclassname, b->opclassname))
return false;
if (!equalstr(a->amname, b->amname))
return false;
if (a->behavior != b->behavior)
return false;
return true;
}
static bool
_equalRenameStmt(RenameStmt *a, RenameStmt *b)
@ -1082,6 +1094,42 @@ _equalCreateDomainStmt(CreateDomainStmt *a, CreateDomainStmt *b)
return true;
}
static bool
_equalCreateOpClassStmt(CreateOpClassStmt *a, CreateOpClassStmt *b)
{
if (!equal(a->opclassname, b->opclassname))
return false;
if (!equalstr(a->amname, b->amname))
return false;
if (!equal(a->datatype, b->datatype))
return false;
if (!equal(a->items, b->items))
return false;
if (a->isDefault != b->isDefault)
return false;
return true;
}
static bool
_equalCreateOpClassItem(CreateOpClassItem *a, CreateOpClassItem *b)
{
if (a->itemtype != b->itemtype)
return false;
if (!equal(a->name, b->name))
return false;
if (!equal(a->args, b->args))
return false;
if (a->number != b->number)
return false;
if (a->recheck != b->recheck)
return false;
if (!equal(a->storedtype, b->storedtype))
return false;
return true;
}
static bool
_equalCreatedbStmt(CreatedbStmt *a, CreatedbStmt *b)
{
@ -2036,6 +2084,9 @@ equal(void *a, void *b)
case T_RemoveOperStmt:
retval = _equalRemoveOperStmt(a, b);
break;
case T_RemoveOpClassStmt:
retval = _equalRemoveOpClassStmt(a, b);
break;
case T_RenameStmt:
retval = _equalRenameStmt(a, b);
break;
@ -2063,6 +2114,12 @@ equal(void *a, void *b)
case T_CreateDomainStmt:
retval = _equalCreateDomainStmt(a, b);
break;
case T_CreateOpClassStmt:
retval = _equalCreateOpClassStmt(a, b);
break;
case T_CreateOpClassItem:
retval = _equalCreateOpClassItem(a, b);
break;
case T_CreatedbStmt:
retval = _equalCreatedbStmt(a, b);
break;

View File

@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.349 2002/07/24 19:11:10 petere Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.350 2002/07/29 22:14:10 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@ -136,11 +136,11 @@ static void doNegateFloat(Value *v);
AlterTableStmt, AlterUserStmt, AlterUserSetStmt,
AnalyzeStmt, ClosePortalStmt, ClusterStmt, CommentStmt,
ConstraintsSetStmt, CopyStmt, CreateAsStmt, CreateCastStmt,
CreateDomainStmt, CreateGroupStmt, CreatePLangStmt,
CreateDomainStmt, CreateGroupStmt, CreateOpClassStmt, CreatePLangStmt,
CreateSchemaStmt, CreateSeqStmt, CreateStmt,
CreateAssertStmt, CreateTrigStmt, CreateUserStmt,
CreatedbStmt, CursorStmt, DefineStmt, DeleteStmt,
DropGroupStmt, DropPLangStmt, DropStmt,
DropGroupStmt, DropOpClassStmt, DropPLangStmt, DropStmt,
DropAssertStmt, DropTrigStmt, DropRuleStmt, DropCastStmt,
DropUserStmt, DropdbStmt, ExplainStmt, FetchStmt,
GrantStmt, IndexStmt, InsertStmt, ListenStmt, LoadStmt,
@ -156,7 +156,7 @@ static void doNegateFloat(Value *v);
%type <node> select_no_parens, select_with_parens, select_clause,
simple_select
%type <node> alter_column_default
%type <node> alter_column_default, opclass_item
%type <ival> add_drop
%type <dbehavior> opt_drop_behavior
@ -218,7 +218,7 @@ static void doNegateFloat(Value *v);
target_list, update_target_list, insert_column_list,
insert_target_list, def_list, opt_indirection,
group_clause, TriggerFuncArgs, select_limit,
opt_select_limit
opt_select_limit, opclass_item_list
%type <range> into_clause, OptTempTableName
@ -240,7 +240,7 @@ static void doNegateFloat(Value *v);
%type <boolean> opt_instead, opt_cursor
%type <boolean> index_opt_unique, opt_verbose, opt_full
%type <boolean> opt_freeze, opt_default
%type <boolean> opt_freeze, opt_default, opt_recheck
%type <defelt> opt_binary, opt_oids, copy_delimiter
%type <boolean> copy_from
@ -326,7 +326,7 @@ static void doNegateFloat(Value *v);
BOOLEAN, BY,
CACHE, CALLED, CASCADE, CASE, CAST, CHAIN, CHAR_P,
CHARACTER, CHARACTERISTICS, CHECK, CHECKPOINT, CLOSE,
CHARACTER, CHARACTERISTICS, CHECK, CHECKPOINT, CLASS, CLOSE,
CLUSTER, COALESCE, COLLATE, COLUMN, COMMENT, COMMIT,
COMMITTED, CONSTRAINT, CONSTRAINTS, CONVERSION_P, COPY, CREATE, CREATEDB,
CREATEUSER, CROSS, CURRENT_DATE, CURRENT_TIME,
@ -371,7 +371,7 @@ static void doNegateFloat(Value *v);
PRECISION, PRIMARY, PRIOR, PRIVILEGES, PROCEDURE,
PROCEDURAL,
READ, REAL, REFERENCES, REINDEX, RELATIVE, RENAME, REPLACE,
READ, REAL, RECHECK, REFERENCES, REINDEX, RELATIVE, RENAME, REPLACE,
RESET, RESTRICT, RETURNS, REVOKE, RIGHT, ROLLBACK, ROW,
RULE,
@ -481,6 +481,7 @@ stmt :
| CreateSchemaStmt
| CreateGroupStmt
| CreateSeqStmt
| CreateOpClassStmt
| CreatePLangStmt
| CreateAssertStmt
| CreateTrigStmt
@ -492,6 +493,7 @@ stmt :
| CommentStmt
| DropCastStmt
| DropGroupStmt
| DropOpClassStmt
| DropPLangStmt
| DropAssertStmt
| DropTrigStmt
@ -2265,6 +2267,93 @@ def_arg: func_return { $$ = (Node *)$1; }
;
/*****************************************************************************
*
* QUERIES :
* CREATE OPERATOR CLASS ...
* DROP OPERATOR CLASS ...
*
*****************************************************************************/
CreateOpClassStmt:
CREATE OPERATOR CLASS any_name opt_default FOR TYPE_P Typename
USING access_method AS opclass_item_list
{
CreateOpClassStmt *n = makeNode(CreateOpClassStmt);
n->opclassname = $4;
n->isDefault = $5;
n->datatype = $8;
n->amname = $10;
n->items = $12;
$$ = (Node *) n;
}
;
opclass_item_list:
opclass_item { $$ = makeList1($1); }
| opclass_item_list ',' opclass_item { $$ = lappend($1, $3); }
;
opclass_item:
OPERATOR Iconst any_operator opt_recheck
{
CreateOpClassItem *n = makeNode(CreateOpClassItem);
n->itemtype = OPCLASS_ITEM_OPERATOR;
n->name = $3;
n->args = NIL;
n->number = $2;
n->recheck = $4;
$$ = (Node *) n;
}
| OPERATOR Iconst any_operator '(' oper_argtypes ')' opt_recheck
{
CreateOpClassItem *n = makeNode(CreateOpClassItem);
n->itemtype = OPCLASS_ITEM_OPERATOR;
n->name = $3;
n->args = $5;
n->number = $2;
n->recheck = $7;
$$ = (Node *) n;
}
| FUNCTION Iconst func_name func_args
{
CreateOpClassItem *n = makeNode(CreateOpClassItem);
n->itemtype = OPCLASS_ITEM_FUNCTION;
n->name = $3;
n->args = $4;
n->number = $2;
$$ = (Node *) n;
}
| STORAGE Typename
{
CreateOpClassItem *n = makeNode(CreateOpClassItem);
n->itemtype = OPCLASS_ITEM_STORAGETYPE;
n->storedtype = $2;
$$ = (Node *) n;
}
;
opt_default: DEFAULT { $$ = TRUE; }
| /*EMPTY*/ { $$ = FALSE; }
;
opt_recheck: RECHECK { $$ = TRUE; }
| /*EMPTY*/ { $$ = FALSE; }
;
DropOpClassStmt:
DROP OPERATOR CLASS any_name USING access_method opt_drop_behavior
{
RemoveOpClassStmt *n = makeNode(RemoveOpClassStmt);
n->opclassname = $4;
n->amname = $6;
n->behavior = $7;
$$ = (Node *) n;
}
;
/*****************************************************************************
*
* QUERY:
@ -3655,10 +3744,6 @@ CreateConversionStmt:
}
;
opt_default: DEFAULT { $$ = TRUE; }
| /*EMPTY*/ { $$ = FALSE; }
;
/*****************************************************************************
*
* QUERY:
@ -6624,6 +6709,7 @@ unreserved_keyword:
| CHAIN
| CHARACTERISTICS
| CHECKPOINT
| CLASS
| CLOSE
| CLUSTER
| COMMENT
@ -6715,6 +6801,7 @@ unreserved_keyword:
| PROCEDURAL
| PROCEDURE
| READ
| RECHECK
| REINDEX
| RELATIVE
| RENAME

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.122 2002/07/18 23:11:28 petere Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.123 2002/07/29 22:14:11 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -68,6 +68,7 @@ static const ScanKeyword ScanKeywords[] = {
{"characteristics", CHARACTERISTICS},
{"check", CHECK},
{"checkpoint", CHECKPOINT},
{"class", CLASS},
{"close", CLOSE},
{"cluster", CLUSTER},
{"coalesce", COALESCE},
@ -232,6 +233,7 @@ static const ScanKeyword ScanKeywords[] = {
{"procedure", PROCEDURE},
{"read", READ},
{"real", REAL},
{"recheck", RECHECK},
{"references", REFERENCES},
{"reindex", REINDEX},
{"relative", RELATIVE},

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.272 2002/07/18 23:11:28 petere Exp $
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.273 2002/07/29 22:14:11 tgl Exp $
*
* NOTES
* this is the "main" module of the postgres backend and
@ -1693,7 +1693,7 @@ PostgresMain(int argc, char *argv[], const char *username)
if (!IsUnderPostmaster)
{
puts("\nPOSTGRES backend interactive interface ");
puts("$Revision: 1.272 $ $Date: 2002/07/18 23:11:28 $\n");
puts("$Revision: 1.273 $ $Date: 2002/07/29 22:14:11 $\n");
}
/*
@ -2452,6 +2452,14 @@ CreateCommandTag(Node *parsetree)
tag = "DROP CAST";
break;
case T_CreateOpClassStmt:
tag = "CREATE OPERATOR CLASS";
break;
case T_RemoveOpClassStmt:
tag = "DROP OPERATOR CLASS";
break;
default:
elog(LOG, "CreateCommandTag: unknown parse node type %d",
nodeTag(parsetree));

View File

@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.165 2002/07/25 10:07:11 ishii Exp $
* $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.166 2002/07/29 22:14:11 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -836,6 +836,14 @@ ProcessUtility(Node *parsetree,
DropCast((DropCastStmt *) parsetree);
break;
case T_CreateOpClassStmt:
DefineOpClass((CreateOpClassStmt *) parsetree);
break;
case T_RemoveOpClassStmt:
RemoveOpClass((RemoveOpClassStmt *) parsetree);
break;
default:
elog(ERROR, "ProcessUtility: command #%d unsupported",
nodeTag(parsetree));

View File

@ -13,7 +13,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/regproc.c,v 1.71 2002/07/20 05:16:58 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/adt/regproc.c,v 1.72 2002/07/29 22:14:11 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -280,23 +280,19 @@ regprocedurein(PG_FUNCTION_ARGS)
}
/*
* regprocedureout - converts proc OID to "pro_name(args)"
* format_procedure - converts proc OID to "pro_name(args)"
*
* This exports the useful functionality of regprocedureout for use
* in other backend modules. The result is a palloc'd string.
*/
Datum
regprocedureout(PG_FUNCTION_ARGS)
char *
format_procedure(Oid procedure_oid)
{
RegProcedure proid = PG_GETARG_OID(0);
char *result;
HeapTuple proctup;
if (proid == InvalidOid)
{
result = pstrdup("-");
PG_RETURN_CSTRING(result);
}
proctup = SearchSysCache(PROCOID,
ObjectIdGetDatum(proid),
ObjectIdGetDatum(procedure_oid),
0, 0, 0);
if (HeapTupleIsValid(proctup))
@ -316,7 +312,7 @@ regprocedureout(PG_FUNCTION_ARGS)
* Would this proc be found (given the right args) by regprocedurein?
* If not, we need to qualify it.
*/
if (FunctionIsVisible(proid))
if (FunctionIsVisible(procedure_oid))
nspname = NULL;
else
nspname = get_namespace_name(procform->pronamespace);
@ -344,9 +340,26 @@ regprocedureout(PG_FUNCTION_ARGS)
{
/* If OID doesn't match any pg_proc entry, return it numerically */
result = (char *) palloc(NAMEDATALEN);
snprintf(result, NAMEDATALEN, "%u", proid);
snprintf(result, NAMEDATALEN, "%u", procedure_oid);
}
return result;
}
/*
* regprocedureout - converts proc OID to "pro_name(args)"
*/
Datum
regprocedureout(PG_FUNCTION_ARGS)
{
RegProcedure proid = PG_GETARG_OID(0);
char *result;
if (proid == InvalidOid)
result = pstrdup("-");
else
result = format_procedure(proid);
PG_RETURN_CSTRING(result);
}
@ -602,23 +615,19 @@ regoperatorin(PG_FUNCTION_ARGS)
}
/*
* regoperatorout - converts operator OID to "opr_name(args)"
* format_operator - converts operator OID to "opr_name(args)"
*
* This exports the useful functionality of regoperatorout for use
* in other backend modules. The result is a palloc'd string.
*/
Datum
regoperatorout(PG_FUNCTION_ARGS)
char *
format_operator(Oid operator_oid)
{
Oid oprid = PG_GETARG_OID(0);
char *result;
HeapTuple opertup;
if (oprid == InvalidOid)
{
result = pstrdup("0");
PG_RETURN_CSTRING(result);
}
opertup = SearchSysCache(OPEROID,
ObjectIdGetDatum(oprid),
ObjectIdGetDatum(operator_oid),
0, 0, 0);
if (HeapTupleIsValid(opertup))
@ -636,7 +645,7 @@ regoperatorout(PG_FUNCTION_ARGS)
* Would this oper be found (given the right args) by regoperatorin?
* If not, we need to qualify it.
*/
if (!OperatorIsVisible(oprid))
if (!OperatorIsVisible(operator_oid))
{
nspname = get_namespace_name(operform->oprnamespace);
appendStringInfo(&buf, "%s.",
@ -665,9 +674,26 @@ regoperatorout(PG_FUNCTION_ARGS)
{
/* If OID doesn't match any pg_operator entry, return it numerically */
result = (char *) palloc(NAMEDATALEN);
snprintf(result, NAMEDATALEN, "%u", oprid);
snprintf(result, NAMEDATALEN, "%u", operator_oid);
}
return result;
}
/*
* regoperatorout - converts operator OID to "opr_name(args)"
*/
Datum
regoperatorout(PG_FUNCTION_ARGS)
{
Oid oprid = PG_GETARG_OID(0);
char *result;
if (oprid == InvalidOid)
result = pstrdup("0");
else
result = format_operator(oprid);
PG_RETURN_CSTRING(result);
}

View File

@ -27,7 +27,7 @@
# Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
# Portions Copyright (c) 1994, Regents of the University of California
#
# $Header: /cvsroot/pgsql/src/bin/initdb/Attic/initdb.sh,v 1.162 2002/07/24 19:11:11 petere Exp $
# $Header: /cvsroot/pgsql/src/bin/initdb/Attic/initdb.sh,v 1.163 2002/07/29 22:14:11 tgl Exp $
#
#-------------------------------------------------------------------------
@ -708,14 +708,15 @@ $ECHO_N "initializing pg_depend... "$ECHO_C
-- First delete any already-made entries; PINs override all else, and must
-- be the only entries for their objects.
DELETE FROM pg_depend;
INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' FROM pg_cast;
INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' FROM pg_class;
INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' FROM pg_proc;
INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' FROM pg_type;
INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' FROM pg_cast;
INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' FROM pg_constraint;
INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' FROM pg_attrdef;
INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' FROM pg_language;
INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' FROM pg_operator;
INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' FROM pg_opclass;
INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' FROM pg_rewrite;
INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' FROM pg_trigger;
-- restriction here to avoid pinning the public namespace

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: pg_am.h,v 1.22 2002/06/20 20:29:43 momjian Exp $
* $Id: pg_am.h,v 1.23 2002/07/29 22:14:11 tgl Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
@ -107,5 +107,6 @@ DATA(insert OID = 405 ( hash PGUID 1 1 0 f f f t hashgettuple hashinsert hashbe
DESCR("hash index access method");
DATA(insert OID = 783 ( gist PGUID 100 7 0 f t f f gistgettuple gistinsert gistbeginscan gistrescan gistendscan gistmarkpos gistrestrpos gistbuild gistbulkdelete gistcostestimate ));
DESCR("GiST index access method");
#define GIST_AM_OID 783
#endif /* PG_AM_H */

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: defrem.h,v 1.42 2002/07/18 23:11:32 petere Exp $
* $Id: defrem.h,v 1.43 2002/07/29 22:14:11 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -59,6 +59,10 @@ extern void RemoveTypeById(Oid typeOid);
extern void DefineDomain(CreateDomainStmt *stmt);
extern void RemoveDomain(List *names, DropBehavior behavior);
extern void DefineOpClass(CreateOpClassStmt *stmt);
extern void RemoveOpClass(RemoveOpClassStmt *stmt);
extern void RemoveOpClassById(Oid opclassOid);
/* support routines in commands/define.c */

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: nodes.h,v 1.113 2002/07/18 23:11:32 petere Exp $
* $Id: nodes.h,v 1.114 2002/07/29 22:14:11 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -201,6 +201,8 @@ typedef enum NodeTag
T_CreateConversionStmt,
T_CreateCastStmt,
T_DropCastStmt,
T_CreateOpClassStmt,
T_RemoveOpClassStmt,
T_A_Expr = 700,
T_ColumnRef,
@ -235,6 +237,7 @@ typedef enum NodeTag
T_FuncWithArgs,
T_PrivTarget,
T_InsertDefault,
T_CreateOpClassItem,
/*
* TAGS FOR FUNCTION-CALL CONTEXT AND RESULTINFO NODES (see fmgr.h)

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: parsenodes.h,v 1.194 2002/07/24 19:11:14 petere Exp $
* $Id: parsenodes.h,v 1.195 2002/07/29 22:14:11 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -1115,6 +1115,37 @@ typedef struct CreateDomainStmt
List *constraints; /* constraints (list of Constraint nodes) */
} CreateDomainStmt;
/* ----------------------
* Create Operator Class Statement
* ----------------------
*/
typedef struct CreateOpClassStmt
{
NodeTag type;
List *opclassname; /* qualified name (list of Value strings) */
char *amname; /* name of index AM opclass is for */
TypeName *datatype; /* datatype of indexed column */
List *items; /* List of CreateOpClassItem nodes */
bool isDefault; /* Should be marked as default for type? */
} CreateOpClassStmt;
#define OPCLASS_ITEM_OPERATOR 1
#define OPCLASS_ITEM_FUNCTION 2
#define OPCLASS_ITEM_STORAGETYPE 3
typedef struct CreateOpClassItem
{
NodeTag type;
int itemtype; /* see codes above */
/* fields used for an operator or function item: */
List *name; /* operator or function name */
List *args; /* argument types */
int number; /* strategy num or support proc num */
bool recheck; /* only used for operators */
/* fields used for a storagetype item: */
TypeName *storedtype; /* datatype stored in index */
} CreateOpClassItem;
/* ----------------------
* Drop Table|Sequence|View|Index|Type|Domain|Conversion|Schema Statement
* ----------------------
@ -1288,6 +1319,18 @@ typedef struct RemoveOperStmt
DropBehavior behavior; /* RESTRICT or CASCADE behavior */
} RemoveOperStmt;
/* ----------------------
* Drop Operator Class Statement
* ----------------------
*/
typedef struct RemoveOpClassStmt
{
NodeTag type;
List *opclassname; /* qualified name (list of Value strings) */
char *amname; /* name of index AM opclass is for */
DropBehavior behavior; /* RESTRICT or CASCADE behavior */
} RemoveOpClassStmt;
/* ----------------------
* Alter Object Rename Statement
* ----------------------

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: acl.h,v 1.45 2002/06/20 20:29:52 momjian Exp $
* $Id: acl.h,v 1.46 2002/07/29 22:14:11 tgl Exp $
*
* NOTES
* For backward-compatibility purposes we have to allow there
@ -209,5 +209,6 @@ extern bool pg_type_ownercheck(Oid type_oid, Oid userid);
extern bool pg_oper_ownercheck(Oid oper_oid, Oid userid);
extern bool pg_proc_ownercheck(Oid proc_oid, Oid userid);
extern bool pg_namespace_ownercheck(Oid nsp_oid, Oid userid);
extern bool pg_opclass_ownercheck(Oid opc_oid, Oid userid);
#endif /* ACL_H */

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: builtins.h,v 1.187 2002/07/20 05:49:28 momjian Exp $
* $Id: builtins.h,v 1.188 2002/07/29 22:14:11 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -343,6 +343,8 @@ extern Datum regclassout(PG_FUNCTION_ARGS);
extern Datum regtypein(PG_FUNCTION_ARGS);
extern Datum regtypeout(PG_FUNCTION_ARGS);
extern List *stringToQualifiedNameList(const char *string, const char *caller);
extern char *format_procedure(Oid procedure_oid);
extern char *format_operator(Oid operator_oid);
/* ruleutils.c */
extern Datum pg_get_ruledef(PG_FUNCTION_ARGS);