Fix longstanding bug that kept functional indexes from working when you
defaulted the opclass. This addresses TODO item * Allow creation of functional indexes to use default types (Does that make it a feature? Oh dear...)
This commit is contained in:
parent
73348316e7
commit
4926709563
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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
|
* INTERFACE ROUTINES
|
||||||
@ -1032,28 +1032,6 @@ index_create(char *heapRelationName,
|
|||||||
* We create the disk file for this relation here
|
* We create the disk file for this relation here
|
||||||
*/
|
*/
|
||||||
heap_storage_create(indexRelation);
|
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
|
* now update the object id's of all the attribute
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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 $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -31,24 +31,26 @@
|
|||||||
#include "optimizer/planmain.h"
|
#include "optimizer/planmain.h"
|
||||||
#include "optimizer/prep.h"
|
#include "optimizer/prep.h"
|
||||||
#include "parser/parsetree.h"
|
#include "parser/parsetree.h"
|
||||||
|
#include "parser/parse_func.h"
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
#include "utils/syscache.h"
|
#include "utils/syscache.h"
|
||||||
#include "miscadmin.h" /* ReindexDatabase() */
|
#include "miscadmin.h" /* ReindexDatabase() */
|
||||||
#include "utils/portal.h" /* ReindexDatabase() */
|
#include "utils/portal.h" /* ReindexDatabase() */
|
||||||
#include "catalog/catalog.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 */
|
/* non-export function prototypes */
|
||||||
static void CheckPredicate(List *predList, List *rangeTable, Oid baseRelOid);
|
static void CheckPredicate(List *predList, List *rangeTable, Oid baseRelOid);
|
||||||
static void CheckPredExpr(Node *predicate, List *rangeTable,
|
static void CheckPredExpr(Node *predicate, List *rangeTable, Oid baseRelOid);
|
||||||
Oid baseRelOid);
|
static void CheckPredClause(Expr *predicate, List *rangeTable, Oid baseRelOid);
|
||||||
static void
|
static void FuncIndexArgs(IndexElem *funcIndex, FuncIndexInfo *funcInfo,
|
||||||
CheckPredClause(Expr *predicate, List *rangeTable, Oid baseRelOid);
|
AttrNumber *attNumP, Oid *opOidP, Oid relId);
|
||||||
static void FuncIndexArgs(IndexElem *funcIndex, AttrNumber *attNumP,
|
|
||||||
Oid *argTypes, Oid *opOidP, Oid relId);
|
|
||||||
static void NormIndexAttrs(List *attList, AttrNumber *attNumP,
|
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);
|
static char *GetDefaultOpClass(Oid atttypid);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -169,22 +171,22 @@ DefineIndex(char *heapRelationName,
|
|||||||
|
|
||||||
FIsetnArgs(&fInfo, nargs);
|
FIsetnArgs(&fInfo, nargs);
|
||||||
|
|
||||||
strcpy(FIgetname(&fInfo), funcIndex->name);
|
namestrcpy(&fInfo.funcName, funcIndex->name);
|
||||||
|
|
||||||
attributeNumberA = (AttrNumber *) palloc(nargs * sizeof attributeNumberA[0]);
|
attributeNumberA = (AttrNumber *) palloc(nargs *
|
||||||
|
sizeof attributeNumberA[0]);
|
||||||
|
|
||||||
classObjectId = (Oid *) palloc(sizeof classObjectId[0]);
|
classObjectId = (Oid *) palloc(sizeof(Oid));
|
||||||
|
|
||||||
|
FuncIndexArgs(funcIndex, &fInfo, attributeNumberA,
|
||||||
FuncIndexArgs(funcIndex, attributeNumberA,
|
|
||||||
&(FIgetArg(&fInfo, 0)),
|
|
||||||
classObjectId, relationId);
|
classObjectId, relationId);
|
||||||
|
|
||||||
index_create(heapRelationName,
|
index_create(heapRelationName,
|
||||||
indexRelationName,
|
indexRelationName,
|
||||||
&fInfo, NULL, accessMethodId,
|
&fInfo, NULL, accessMethodId,
|
||||||
numberOfAttributes, attributeNumberA,
|
numberOfAttributes, attributeNumberA,
|
||||||
classObjectId, parameterCount, parameterA, (Node *) cnfPred,
|
classObjectId, parameterCount, parameterA,
|
||||||
|
(Node *) cnfPred,
|
||||||
lossy, unique, primary);
|
lossy, unique, primary);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -192,7 +194,7 @@ DefineIndex(char *heapRelationName,
|
|||||||
attributeNumberA = (AttrNumber *) palloc(numberOfAttributes *
|
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,
|
NormIndexAttrs(attributeList, attributeNumberA,
|
||||||
classObjectId, relationId);
|
classObjectId, relationId);
|
||||||
@ -200,9 +202,11 @@ DefineIndex(char *heapRelationName,
|
|||||||
index_create(heapRelationName, indexRelationName, NULL,
|
index_create(heapRelationName, indexRelationName, NULL,
|
||||||
attributeList,
|
attributeList,
|
||||||
accessMethodId, numberOfAttributes, attributeNumberA,
|
accessMethodId, numberOfAttributes, attributeNumberA,
|
||||||
classObjectId, parameterCount, parameterA, (Node *) cnfPred,
|
classObjectId, parameterCount, parameterA,
|
||||||
|
(Node *) cnfPred,
|
||||||
lossy, unique, primary);
|
lossy, unique, primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
setRelhasindexInplace(relationId, true, false);
|
setRelhasindexInplace(relationId, true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -320,7 +324,6 @@ ExtendIndex(char *indexRelationName, Expr *predicate, List *rangetable)
|
|||||||
if (indproc != InvalidOid)
|
if (indproc != InvalidOid)
|
||||||
{
|
{
|
||||||
funcInfo = &fInfo;
|
funcInfo = &fInfo;
|
||||||
/* FIgetnArgs(funcInfo) = numberOfAttributes; */
|
|
||||||
FIsetnArgs(funcInfo, numberOfAttributes);
|
FIsetnArgs(funcInfo, numberOfAttributes);
|
||||||
|
|
||||||
tuple = SearchSysCacheTuple(PROCOID,
|
tuple = SearchSysCacheTuple(PROCOID,
|
||||||
@ -407,51 +410,62 @@ CheckPredClause(Expr *predicate, List *rangeTable, Oid baseRelOid)
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
FuncIndexArgs(IndexElem *funcIndex,
|
FuncIndexArgs(IndexElem *funcIndex,
|
||||||
|
FuncIndexInfo *funcInfo,
|
||||||
AttrNumber *attNumP,
|
AttrNumber *attNumP,
|
||||||
Oid *argTypes,
|
|
||||||
Oid *opOidP,
|
Oid *opOidP,
|
||||||
Oid relId)
|
Oid relId)
|
||||||
{
|
{
|
||||||
List *rest;
|
List *rest;
|
||||||
HeapTuple tuple;
|
HeapTuple tuple;
|
||||||
Form_pg_attribute att;
|
Oid retType;
|
||||||
|
int argn = 0;
|
||||||
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));
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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))
|
MemSet(funcInfo->arglist, 0, FUNC_MAX_ARGS * sizeof(Oid));
|
||||||
{
|
|
||||||
char *arg;
|
|
||||||
|
|
||||||
arg = strVal(lfirst(rest));
|
foreach(rest, funcIndex->args)
|
||||||
|
{
|
||||||
|
char *arg = strVal(lfirst(rest));
|
||||||
|
Form_pg_attribute att;
|
||||||
|
|
||||||
tuple = SearchSysCacheTuple(ATTNAME,
|
tuple = SearchSysCacheTuple(ATTNAME,
|
||||||
ObjectIdGetDatum(relId),
|
ObjectIdGetDatum(relId),
|
||||||
PointerGetDatum(arg), 0, 0);
|
PointerGetDatum(arg), 0, 0);
|
||||||
|
|
||||||
if (!HeapTupleIsValid(tuple))
|
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);
|
att = (Form_pg_attribute) GETSTRUCT(tuple);
|
||||||
*attNumP++ = att->attnum;
|
*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
|
static void
|
||||||
@ -461,20 +475,16 @@ NormIndexAttrs(List *attList, /* list of IndexElem's */
|
|||||||
Oid relId)
|
Oid relId)
|
||||||
{
|
{
|
||||||
List *rest;
|
List *rest;
|
||||||
HeapTuple atttuple,
|
|
||||||
tuple;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* process attributeList
|
* process attributeList
|
||||||
*/
|
*/
|
||||||
|
foreach(rest, attList)
|
||||||
for (rest = attList; rest != NIL; rest = lnext(rest))
|
|
||||||
{
|
{
|
||||||
IndexElem *attribute;
|
IndexElem *attribute = lfirst(rest);
|
||||||
|
HeapTuple atttuple;
|
||||||
Form_pg_attribute attform;
|
Form_pg_attribute attform;
|
||||||
|
|
||||||
attribute = lfirst(rest);
|
|
||||||
|
|
||||||
if (attribute->name == NULL)
|
if (attribute->name == NULL)
|
||||||
elog(ERROR, "missing attribute for define index");
|
elog(ERROR, "missing attribute for define index");
|
||||||
|
|
||||||
@ -483,42 +493,54 @@ NormIndexAttrs(List *attList, /* list of IndexElem's */
|
|||||||
PointerGetDatum(attribute->name),
|
PointerGetDatum(attribute->name),
|
||||||
0, 0);
|
0, 0);
|
||||||
if (!HeapTupleIsValid(atttuple))
|
if (!HeapTupleIsValid(atttuple))
|
||||||
{
|
elog(ERROR, "DefineIndex: attribute \"%s\" not found",
|
||||||
elog(ERROR,
|
|
||||||
"DefineIndex: attribute \"%s\" not found",
|
|
||||||
attribute->name);
|
attribute->name);
|
||||||
}
|
|
||||||
|
|
||||||
attform = (Form_pg_attribute) GETSTRUCT(atttuple);
|
attform = (Form_pg_attribute) GETSTRUCT(atttuple);
|
||||||
|
|
||||||
*attNumP++ = attform->attnum;
|
*attNumP++ = attform->attnum;
|
||||||
|
|
||||||
/* we want the type so we can set the proper alignment, etc. */
|
ProcessAttrTypename(attribute, attform->atttypid, attform->atttypmod);
|
||||||
|
|
||||||
|
*classOidP++ = GetAttrOpClass(attribute, attform->atttypid);
|
||||||
|
|
||||||
|
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)
|
if (attribute->typename == NULL)
|
||||||
{
|
{
|
||||||
tuple = SearchSysCacheTuple(TYPEOID,
|
tuple = SearchSysCacheTuple(TYPEOID,
|
||||||
ObjectIdGetDatum(attform->atttypid),
|
ObjectIdGetDatum(defType),
|
||||||
0, 0, 0);
|
0, 0, 0);
|
||||||
if (!HeapTupleIsValid(tuple))
|
if (!HeapTupleIsValid(tuple))
|
||||||
elog(ERROR, "create index: type for attribute '%s' undefined",
|
elog(ERROR, "DefineIndex: type for attribute '%s' undefined",
|
||||||
attribute->name);
|
attribute->name);
|
||||||
/* we just set the type name because that is all we need */
|
|
||||||
attribute->typename = makeNode(TypeName);
|
attribute->typename = makeNode(TypeName);
|
||||||
attribute->typename->name = nameout(&((Form_pg_type) GETSTRUCT(tuple))->typname);
|
attribute->typename->name = nameout(&((Form_pg_type) GETSTRUCT(tuple))->typname);
|
||||||
|
attribute->typename->typmod = defTypmod;
|
||||||
/* we all need the typmod for the char and varchar types. */
|
|
||||||
attribute->typename->typmod = attform->atttypmod;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Oid
|
||||||
|
GetAttrOpClass(IndexElem *attribute, Oid attrType)
|
||||||
|
{
|
||||||
|
HeapTuple tuple;
|
||||||
|
|
||||||
if (attribute->class == NULL)
|
if (attribute->class == NULL)
|
||||||
{
|
{
|
||||||
/* no operator class specified, so find the default */
|
/* no operator class specified, so find the default */
|
||||||
attribute->class = GetDefaultOpClass(attform->atttypid);
|
attribute->class = GetDefaultOpClass(attrType);
|
||||||
if (attribute->class == NULL)
|
if (attribute->class == NULL)
|
||||||
{
|
elog(ERROR, "Can't find a default operator class for type %u",
|
||||||
elog(ERROR,
|
attrType);
|
||||||
"Can't find a default operator class for type %u.",
|
|
||||||
attform->atttypid);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tuple = SearchSysCacheTuple(CLANAME,
|
tuple = SearchSysCacheTuple(CLANAME,
|
||||||
@ -526,13 +548,10 @@ NormIndexAttrs(List *attList, /* list of IndexElem's */
|
|||||||
0, 0, 0);
|
0, 0, 0);
|
||||||
|
|
||||||
if (!HeapTupleIsValid(tuple))
|
if (!HeapTupleIsValid(tuple))
|
||||||
{
|
elog(ERROR, "DefineIndex: %s opclass not found",
|
||||||
elog(ERROR, "DefineIndex: %s class not found",
|
|
||||||
attribute->class);
|
attribute->class);
|
||||||
}
|
|
||||||
*classOidP++ = tuple->t_data->t_oid;
|
return tuple->t_data->t_oid;
|
||||||
heap_freetuple(atttuple);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
|
Loading…
x
Reference in New Issue
Block a user