From f46c1f1e336100de405b7e1312462e11aa36255e Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Tue, 25 Apr 2000 02:45:54 +0000 Subject: [PATCH] Check that user-specified opclass in CREATE INDEX corresponds to operators that will actually work on the column datatype. --- src/backend/commands/indexcmds.c | 43 ++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index c1c16a844d..19ff9597d5 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -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; }