Fix longstanding bug that kept functional indexes from working when you
authorTom Lane
Fri, 25 Feb 2000 02:58:48 +0000 (02:58 +0000)
committerTom Lane
Fri, 25 Feb 2000 02:58:48 +0000 (02:58 +0000)
defaulted the opclass.  This addresses TODO item
* Allow creation of functional indexes to use default types
(Does that make it a feature?  Oh dear...)

src/backend/catalog/index.c
src/backend/commands/indexcmds.c

index b7d49ed3bc8c6f927cd989bbc17a9b01a5c52514..5bfc332f0dbebd5659d151eda3884df2f3a0db6e 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.105 2000/02/18 09:28:41 inoue Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.106 2000/02/25 02:58:47 tgl Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -1032,28 +1032,6 @@ index_create(char *heapRelationName,
     * We create the disk file for this relation here
     */
    heap_storage_create(indexRelation);
-   /* ----------------
-    * Now get the index procedure (only relevant for functional indices).
-    * ----------------
-    */
-
-   if (PointerIsValid(funcInfo))
-   {
-       HeapTuple   proc_tup;
-
-       proc_tup = SearchSysCacheTuple(PROCNAME,
-                                   PointerGetDatum(FIgetname(funcInfo)),
-                                    Int32GetDatum(FIgetnArgs(funcInfo)),
-                                PointerGetDatum(FIgetArglist(funcInfo)),
-                                      0);
-
-       if (!HeapTupleIsValid(proc_tup))
-       {
-           func_error("index_create", FIgetname(funcInfo),
-                    FIgetnArgs(funcInfo), FIgetArglist(funcInfo), NULL);
-       }
-       FIgetProcOid(funcInfo) = proc_tup->t_data->t_oid;
-   }
 
    /* ----------------
     *  now update the object id's of all the attribute
index cbd7b26ae8ad2370693b03d1fd624bb7d8972bb2..93ad0eb63b47fdd601112ab075a1617ec64c9ba5 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.21 2000/02/18 09:29:37 inoue Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.22 2000/02/25 02:58:48 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "optimizer/planmain.h"
 #include "optimizer/prep.h"
 #include "parser/parsetree.h"
+#include "parser/parse_func.h"
 #include "utils/builtins.h"
 #include "utils/syscache.h"
 #include "miscadmin.h" /* ReindexDatabase() */
 #include "utils/portal.h" /* ReindexDatabase() */
 #include "catalog/catalog.h" /* ReindexDatabase() */
 
-#define IsFuncIndex(ATTR_LIST) (((IndexElem*)lfirst(ATTR_LIST))->args!=NULL)
+#define IsFuncIndex(ATTR_LIST) (((IndexElem*)lfirst(ATTR_LIST))->args != NIL)
 
 /* non-export function prototypes */
 static void CheckPredicate(List *predList, List *rangeTable, Oid baseRelOid);
-static void CheckPredExpr(Node *predicate, List *rangeTable,
-             Oid baseRelOid);
-static void
-           CheckPredClause(Expr *predicate, List *rangeTable, Oid baseRelOid);
-static void FuncIndexArgs(IndexElem *funcIndex, AttrNumber *attNumP,
-             Oid *argTypes, Oid *opOidP, Oid relId);
+static void CheckPredExpr(Node *predicate, List *rangeTable, Oid baseRelOid);
+static void CheckPredClause(Expr *predicate, List *rangeTable, Oid baseRelOid);
+static void FuncIndexArgs(IndexElem *funcIndex, FuncIndexInfo *funcInfo,
+                         AttrNumber *attNumP, Oid *opOidP, Oid relId);
 static void NormIndexAttrs(List *attList, AttrNumber *attNumP,
-              Oid *opOidP, Oid relId);
+                          Oid *opOidP, Oid relId);
+static void ProcessAttrTypename(IndexElem *attribute,
+                               Oid defType, int32 defTypmod);
+static Oid GetAttrOpClass(IndexElem *attribute, Oid attrType);
 static char *GetDefaultOpClass(Oid atttypid);
 
 /*
@@ -169,30 +171,30 @@ DefineIndex(char *heapRelationName,
 
        FIsetnArgs(&fInfo, nargs);
 
-       strcpy(FIgetname(&fInfo), funcIndex->name);
-
-       attributeNumberA = (AttrNumber *) palloc(nargs * sizeof attributeNumberA[0]);
+       namestrcpy(&fInfo.funcName, funcIndex->name);
 
-       classObjectId = (Oid *) palloc(sizeof classObjectId[0]);
+       attributeNumberA = (AttrNumber *) palloc(nargs *
+                                                sizeof attributeNumberA[0]);
 
+       classObjectId = (Oid *) palloc(sizeof(Oid));
 
-       FuncIndexArgs(funcIndex, attributeNumberA,
-                     &(FIgetArg(&fInfo, 0)),
+       FuncIndexArgs(funcIndex, &fInfo, attributeNumberA,
                      classObjectId, relationId);
 
        index_create(heapRelationName,
                     indexRelationName,
                     &fInfo, NULL, accessMethodId,
                     numberOfAttributes, attributeNumberA,
-            classObjectId, parameterCount, parameterA, (Node *) cnfPred,
+                    classObjectId, parameterCount, parameterA,
+                    (Node *) cnfPred,
                     lossy, unique, primary);
    }
    else
    {
        attributeNumberA = (AttrNumber *) palloc(numberOfAttributes *
-                                            sizeof attributeNumberA[0]);
+                                                sizeof attributeNumberA[0]);
 
-       classObjectId = (Oid *) palloc(numberOfAttributes * sizeof classObjectId[0]);
+       classObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
 
        NormIndexAttrs(attributeList, attributeNumberA,
                       classObjectId, relationId);
@@ -200,9 +202,11 @@ DefineIndex(char *heapRelationName,
        index_create(heapRelationName, indexRelationName, NULL,
                     attributeList,
                     accessMethodId, numberOfAttributes, attributeNumberA,
-            classObjectId, parameterCount, parameterA, (Node *) cnfPred,
+                    classObjectId, parameterCount, parameterA,
+                    (Node *) cnfPred,
                     lossy, unique, primary);
    }
+
    setRelhasindexInplace(relationId, true, false);
 }
 
@@ -320,7 +324,6 @@ ExtendIndex(char *indexRelationName, Expr *predicate, List *rangetable)
    if (indproc != InvalidOid)
    {
        funcInfo = &fInfo;
-/*     FIgetnArgs(funcInfo) = numberOfAttributes; */
        FIsetnArgs(funcInfo, numberOfAttributes);
 
        tuple = SearchSysCacheTuple(PROCOID,
@@ -407,51 +410,62 @@ CheckPredClause(Expr *predicate, List *rangeTable, Oid baseRelOid)
 
 static void
 FuncIndexArgs(IndexElem *funcIndex,
+             FuncIndexInfo *funcInfo,
              AttrNumber *attNumP,
-             Oid *argTypes,
              Oid *opOidP,
              Oid relId)
 {
    List       *rest;
    HeapTuple   tuple;
-   Form_pg_attribute att;
-
-   tuple = SearchSysCacheTuple(CLANAME,
-                               PointerGetDatum(funcIndex->class),
-                               0, 0, 0);
-
-   if (!HeapTupleIsValid(tuple))
-   {
-       elog(ERROR, "DefineIndex: %s class not found",
-            funcIndex->class);
-   }
-   *opOidP = tuple->t_data->t_oid;
-
-   MemSet(argTypes, 0, FUNC_MAX_ARGS * sizeof(Oid));
+   Oid         retType;
+   int         argn = 0;
 
    /*
-    * process the function arguments
+    * process the function arguments, which are a list of T_String
+    * (someday ought to allow more general expressions?)
     */
-   for (rest = funcIndex->args; rest != NIL; rest = lnext(rest))
-   {
-       char       *arg;
+   MemSet(funcInfo->arglist, 0, FUNC_MAX_ARGS * sizeof(Oid));
 
-       arg = strVal(lfirst(rest));
+   foreach(rest, funcIndex->args)
+   {
+       char       *arg = strVal(lfirst(rest));
+       Form_pg_attribute att;
 
        tuple = SearchSysCacheTuple(ATTNAME,
                                    ObjectIdGetDatum(relId),
                                    PointerGetDatum(arg), 0, 0);
 
        if (!HeapTupleIsValid(tuple))
-       {
-           elog(ERROR,
-                "DefineIndex: attribute \"%s\" not found",
-                arg);
-       }
+           elog(ERROR, "DefineIndex: attribute \"%s\" not found", arg);
        att = (Form_pg_attribute) GETSTRUCT(tuple);
        *attNumP++ = att->attnum;
-       *argTypes++ = att->atttypid;
+       funcInfo->arglist[argn++] = att->atttypid;
+   }
+
+   /* ----------------
+    * Lookup the function procedure to get its OID and result type.
+    * ----------------
+    */
+   tuple = SearchSysCacheTuple(PROCNAME,
+                               PointerGetDatum(FIgetname(funcInfo)),
+                               Int32GetDatum(FIgetnArgs(funcInfo)),
+                               PointerGetDatum(FIgetArglist(funcInfo)),
+                               0);
+
+   if (!HeapTupleIsValid(tuple))
+   {
+       func_error("DefineIndex", FIgetname(funcInfo),
+                  FIgetnArgs(funcInfo), FIgetArglist(funcInfo), NULL);
    }
+
+   FIsetProcOid(funcInfo, tuple->t_data->t_oid);
+   retType = ((Form_pg_proc) GETSTRUCT(tuple))->prorettype;
+
+   /* Process type and opclass, using func return type as default */
+
+   ProcessAttrTypename(funcIndex, retType, -1);
+
+   *opOidP = GetAttrOpClass(funcIndex, retType);
 }
 
 static void
@@ -461,80 +475,85 @@ NormIndexAttrs(List *attList, /* list of IndexElem's */
               Oid relId)
 {
    List       *rest;
-   HeapTuple   atttuple,
-               tuple;
 
    /*
     * process attributeList
     */
-
-   for (rest = attList; rest != NIL; rest = lnext(rest))
+   foreach(rest, attList)
    {
-       IndexElem  *attribute;
+       IndexElem  *attribute = lfirst(rest);
+       HeapTuple   atttuple;
        Form_pg_attribute attform;
 
-       attribute = lfirst(rest);
-
        if (attribute->name == NULL)
            elog(ERROR, "missing attribute for define index");
 
        atttuple = SearchSysCacheTupleCopy(ATTNAME,
                                           ObjectIdGetDatum(relId),
-                                       PointerGetDatum(attribute->name),
+                                          PointerGetDatum(attribute->name),
                                           0, 0);
        if (!HeapTupleIsValid(atttuple))
-       {
-           elog(ERROR,
-                "DefineIndex: attribute \"%s\" not found",
+           elog(ERROR, "DefineIndex: attribute \"%s\" not found",
                 attribute->name);
-       }
-
        attform = (Form_pg_attribute) GETSTRUCT(atttuple);
+
        *attNumP++ = attform->attnum;
 
-       /* we want the type so we can set the proper alignment, etc. */
-       if (attribute->typename == NULL)
-       {
-           tuple = SearchSysCacheTuple(TYPEOID,
-                                    ObjectIdGetDatum(attform->atttypid),
-                                       0, 0, 0);
-           if (!HeapTupleIsValid(tuple))
-               elog(ERROR, "create index: type for attribute '%s' undefined",
-                    attribute->name);
-           /* we just set the type name because that is all we need */
-           attribute->typename = makeNode(TypeName);
-           attribute->typename->name = nameout(&((Form_pg_type) GETSTRUCT(tuple))->typname);
-
-           /* we all need the typmod for the char and varchar types. */
-           attribute->typename->typmod = attform->atttypmod;
-       }
+       ProcessAttrTypename(attribute, attform->atttypid, attform->atttypmod);
 
-       if (attribute->class == NULL)
-       {
-           /* no operator class specified, so find the default */
-           attribute->class = GetDefaultOpClass(attform->atttypid);
-           if (attribute->class == NULL)
-           {
-               elog(ERROR,
-                    "Can't find a default operator class for type %u.",
-                    attform->atttypid);
-           }
-       }
+       *classOidP++ = GetAttrOpClass(attribute, attform->atttypid);
 
-       tuple = SearchSysCacheTuple(CLANAME,
-                                   PointerGetDatum(attribute->class),
-                                   0, 0, 0);
+       heap_freetuple(atttuple);
+   }
+}
 
+static void
+ProcessAttrTypename(IndexElem *attribute,
+                   Oid defType, int32 defTypmod)
+{
+   HeapTuple   tuple;
+
+   /* build a type node so we can set the proper alignment, etc. */
+   if (attribute->typename == NULL)
+   {
+       tuple = SearchSysCacheTuple(TYPEOID,
+                                   ObjectIdGetDatum(defType),
+                                   0, 0, 0);
        if (!HeapTupleIsValid(tuple))
-       {
-           elog(ERROR, "DefineIndex: %s class not found",
-                attribute->class);
-       }
-       *classOidP++ = tuple->t_data->t_oid;
-       heap_freetuple(atttuple);
+           elog(ERROR, "DefineIndex: type for attribute '%s' undefined",
+                attribute->name);
+
+       attribute->typename = makeNode(TypeName);
+       attribute->typename->name = nameout(&((Form_pg_type) GETSTRUCT(tuple))->typname);
+       attribute->typename->typmod = defTypmod;
    }
 }
 
+static Oid
+GetAttrOpClass(IndexElem *attribute, Oid attrType)
+{
+   HeapTuple   tuple;
+
+   if (attribute->class == NULL)
+   {
+       /* no operator class specified, so find the default */
+       attribute->class = GetDefaultOpClass(attrType);
+       if (attribute->class == NULL)
+           elog(ERROR, "Can't find a default operator class for type %u",
+                attrType);
+   }
+
+   tuple = SearchSysCacheTuple(CLANAME,
+                               PointerGetDatum(attribute->class),
+                               0, 0, 0);
+
+   if (!HeapTupleIsValid(tuple))
+       elog(ERROR, "DefineIndex: %s opclass not found",
+            attribute->class);
+
+   return tuple->t_data->t_oid;
+}
+
 static char *
 GetDefaultOpClass(Oid atttypid)
 {