]> granicus.if.org Git - postgresql/commitdiff
Check that user-specified opclass in CREATE INDEX corresponds to operators
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 25 Apr 2000 02:45:54 +0000 (02:45 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 25 Apr 2000 02:45:54 +0000 (02:45 +0000)
that will actually work on the column datatype.

src/backend/commands/indexcmds.c

index c1c16a844d4737a93246241b98cac6a54509828f..19ff9597d5297129ce761b5161a77e8214fc4bdc 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.24 2000/04/23 01:44:55 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.25 2000/04/25 02:45:54 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -24,6 +24,7 @@
 #include "catalog/pg_database.h"
 #include "catalog/pg_index.h"
 #include "catalog/pg_opclass.h"
+#include "catalog/pg_operator.h"
 #include "catalog/pg_proc.h"
 #include "catalog/pg_shadow.h"
 #include "catalog/pg_type.h"
@@ -32,6 +33,7 @@
 #include "optimizer/planmain.h"
 #include "optimizer/prep.h"
 #include "parser/parsetree.h"
+#include "parser/parse_coerce.h"
 #include "parser/parse_func.h"
 #include "parser/parse_type.h"
 #include "utils/builtins.h"
@@ -556,7 +558,9 @@ GetAttrOpClass(IndexElem *attribute, Oid attrType,
        HeapScanDesc scan;
        ScanKeyData entry[2];
        HeapTuple       tuple;
-       Oid                     opClassId;
+       Oid                     opClassId,
+                               oprId;
+       bool            doTypeCheck = true;
 
        if (attribute->class == NULL)
        {
@@ -565,6 +569,8 @@ GetAttrOpClass(IndexElem *attribute, Oid attrType,
                if (attribute->class == NULL)
                        elog(ERROR, "DefineIndex: type %s has no default operator class",
                                 typeidTypeName(attrType));
+               /* assume we need not check type compatibility */
+               doTypeCheck = false;
        }
 
        tuple = SearchSysCacheTuple(CLANAME,
@@ -597,9 +603,42 @@ GetAttrOpClass(IndexElem *attribute, Oid attrType,
                         attribute->class, accessMethodName);
        }
 
+       oprId = ((Form_pg_amop) GETSTRUCT(tuple))->amopopr;
+
        heap_endscan(scan);
        heap_close(relation, AccessShareLock);
 
+       /*
+        * Make sure the operators associated with this opclass actually accept
+        * the column data type.  This prevents possible coredumps caused by
+        * user errors like applying text_ops to an int4 column.  We will accept
+        * an opclass as OK if the operator's input datatype is binary-compatible
+        * with the actual column datatype.  Note we assume that all the operators
+        * associated with an opclass accept the same datatypes, so checking the
+        * first one we happened to find in the table is sufficient.
+        *
+        * If the opclass was the default for the datatype, assume we can skip
+        * this check --- that saves a few cycles in the most common case.
+        * If pg_opclass is messed up then we're probably screwed anyway...
+        */
+       if (doTypeCheck)
+       {
+               tuple = SearchSysCacheTuple(OPEROID,
+                                                                       ObjectIdGetDatum(oprId),
+                                                                       0, 0, 0);
+               if (HeapTupleIsValid(tuple))
+               {
+                       Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tuple);
+                       Oid             opInputType = (optup->oprkind == 'l') ?
+                               optup->oprright : optup->oprleft;
+
+                       if (attrType != opInputType &&
+                               ! IS_BINARY_COMPATIBLE(attrType, opInputType))
+                               elog(ERROR, "DefineIndex: opclass \"%s\" does not accept datatype \"%s\"",
+                                        attribute->class, typeidTypeName(attrType));
+               }
+       }
+
        return opClassId;
 }