aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser/catalog_utils.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/parser/catalog_utils.c')
-rw-r--r--src/backend/parser/catalog_utils.c1686
1 files changed, 0 insertions, 1686 deletions
diff --git a/src/backend/parser/catalog_utils.c b/src/backend/parser/catalog_utils.c
deleted file mode 100644
index b119c7dbb5a..00000000000
--- a/src/backend/parser/catalog_utils.c
+++ /dev/null
@@ -1,1686 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * catalog_utils.c--
- *
- * Copyright (c) 1994, Regents of the University of California
- *
- *
- * IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/Attic/catalog_utils.c,v 1.30 1997/11/20 23:22:14 momjian Exp $
- *
- *-------------------------------------------------------------------------
- */
-#include <string.h>
-#include "postgres.h"
-
-#include "lib/dllist.h"
-#include "utils/datum.h"
-
-#include "utils/builtins.h"
-#include "utils/elog.h"
-#include "utils/palloc.h"
-#include "fmgr.h"
-
-#include "nodes/pg_list.h"
-#include "nodes/parsenodes.h"
-#include "utils/syscache.h"
-#include "catalog/catname.h"
-
-#include "parser/catalog_utils.h"
-#include "catalog/pg_inherits.h"
-#include "catalog/pg_operator.h"
-#include "catalog/pg_type.h"
-#include "catalog/pg_proc.h"
-#include "catalog/indexing.h"
-#include "catalog/catname.h"
-
-#include "access/skey.h"
-#include "access/relscan.h"
-#include "access/tupdesc.h"
-#include "access/htup.h"
-#include "access/heapam.h"
-#include "access/genam.h"
-#include "access/itup.h"
-#include "access/tupmacs.h"
-
-#include "storage/buf.h"
-#include "storage/bufmgr.h"
-#include "utils/lsyscache.h"
-#include "storage/lmgr.h"
-
-#include "port-protos.h" /* strdup() */
-
-struct
-{
- char *field;
- int code;
-} special_attr[] =
-
-{
- {
- "ctid", SelfItemPointerAttributeNumber
- },
- {
- "oid", ObjectIdAttributeNumber
- },
- {
- "xmin", MinTransactionIdAttributeNumber
- },
- {
- "cmin", MinCommandIdAttributeNumber
- },
- {
- "xmax", MaxTransactionIdAttributeNumber
- },
- {
- "cmax", MaxCommandIdAttributeNumber
- },
-};
-
-#define SPECIALS (sizeof(special_attr)/sizeof(*special_attr))
-
-static char *attnum_type[SPECIALS] = {
- "tid",
- "oid",
- "xid",
- "cid",
- "xid",
- "cid",
-};
-
-#define MAXFARGS 8 /* max # args to a c or postquel function */
-
-/*
- * This structure is used to explore the inheritance hierarchy above
- * nodes in the type tree in order to disambiguate among polymorphic
- * functions.
- */
-
-typedef struct _InhPaths
-{
- int nsupers; /* number of superclasses */
- Oid self; /* this class */
- Oid *supervec; /* vector of superclasses */
-} InhPaths;
-
-/*
- * This structure holds a list of possible functions or operators that
- * agree with the known name and argument types of the function/operator.
- */
-typedef struct _CandidateList
-{
- Oid *args;
- struct _CandidateList *next;
-} *CandidateList;
-
-static Oid **argtype_inherit(int nargs, Oid *oid_array);
-static Oid **genxprod(InhPaths *arginh, int nargs);
-static int findsupers(Oid relid, Oid **supervec);
-static bool check_typeid(Oid id);
-static char *instr1(TypeTupleForm tp, char *string, int typlen);
-static void op_error(char *op, Oid arg1, Oid arg2);
-
-/* check to see if a type id is valid,
- * returns true if it is. By using this call before calling
- * get_id_type or get_id_typname, more meaningful error messages
- * can be produced because the caller typically has more context of
- * what's going on - jolly
- */
-static bool
-check_typeid(Oid id)
-{
- return (SearchSysCacheTuple(TYPOID,
- ObjectIdGetDatum(id),
- 0, 0, 0) != NULL);
-}
-
-
-/* return a Type structure, given an typid */
-Type
-get_id_type(Oid id)
-{
- HeapTuple tup;
-
- if (!(tup = SearchSysCacheTuple(TYPOID, ObjectIdGetDatum(id),
- 0, 0, 0)))
- {
- elog(WARN, "type id lookup of %ud failed", id);
- return (NULL);
- }
- return ((Type) tup);
-}
-
-/* return a type name, given a typeid */
-char *
-get_id_typname(Oid id)
-{
- HeapTuple tup;
- TypeTupleForm typetuple;
-
- if (!(tup = SearchSysCacheTuple(TYPOID, ObjectIdGetDatum(id),
- 0, 0, 0)))
- {
- elog(WARN, "type id lookup of %ud failed", id);
- return (NULL);
- }
- typetuple = (TypeTupleForm) GETSTRUCT(tup);
- return (typetuple->typname).data;
-}
-
-/* return a Type structure, given type name */
-Type
-type(char *s)
-{
- HeapTuple tup;
-
- if (s == NULL)
- {
- elog(WARN, "type(): Null type");
- }
-
- if (!(tup = SearchSysCacheTuple(TYPNAME, PointerGetDatum(s), 0, 0, 0)))
- {
- elog(WARN, "type name lookup of %s failed", s);
- }
- return ((Type) tup);
-}
-
-/* given attribute id, return type of that attribute */
-/* XXX Special case for pseudo-attributes is a hack */
-Oid
-att_typeid(Relation rd, int attid)
-{
-
- if (attid < 0)
- {
- return (typeid(type(attnum_type[-attid - 1])));
- }
-
- /*
- * -1 because varattno (where attid comes from) returns one more than
- * index
- */
- return (rd->rd_att->attrs[attid - 1]->atttypid);
-}
-
-
-int
-att_attnelems(Relation rd, int attid)
-{
- return (rd->rd_att->attrs[attid - 1]->attnelems);
-}
-
-/* given type, return the type OID */
-Oid
-typeid(Type tp)
-{
- if (tp == NULL)
- {
- elog(WARN, "typeid() called with NULL type struct");
- }
- return (tp->t_oid);
-}
-
-/* given type (as type struct), return the length of type */
-int16
-tlen(Type t)
-{
- TypeTupleForm typ;
-
- typ = (TypeTupleForm) GETSTRUCT(t);
- return (typ->typlen);
-}
-
-/* given type (as type struct), return the value of its 'byval' attribute.*/
-bool
-tbyval(Type t)
-{
- TypeTupleForm typ;
-
- typ = (TypeTupleForm) GETSTRUCT(t);
- return (typ->typbyval);
-}
-
-/* given type (as type struct), return the name of type */
-char *
-tname(Type t)
-{
- TypeTupleForm typ;
-
- typ = (TypeTupleForm) GETSTRUCT(t);
- return (typ->typname).data;
-}
-
-/* given type (as type struct), return wether type is passed by value */
-int
-tbyvalue(Type t)
-{
- TypeTupleForm typ;
-
- typ = (TypeTupleForm) GETSTRUCT(t);
- return (typ->typbyval);
-}
-
-/* given a type, return its typetype ('c' for 'c'atalog types) */
-static char
-typetypetype(Type t)
-{
- TypeTupleForm typ;
-
- typ = (TypeTupleForm) GETSTRUCT(t);
- return (typ->typtype);
-}
-
-/* given operator, return the operator OID */
-Oid
-oprid(Operator op)
-{
- return (op->t_oid);
-}
-
-/*
- * given opname, leftTypeId and rightTypeId,
- * find all possible (arg1, arg2) pairs for which an operator named
- * opname exists, such that leftTypeId can be coerced to arg1 and
- * rightTypeId can be coerced to arg2
- */
-static int
-binary_oper_get_candidates(char *opname,
- Oid leftTypeId,
- Oid rightTypeId,
- CandidateList *candidates)
-{
- CandidateList current_candidate;
- Relation pg_operator_desc;
- HeapScanDesc pg_operator_scan;
- HeapTuple tup;
- OperatorTupleForm oper;
- Buffer buffer;
- int nkeys;
- int ncandidates = 0;
- ScanKeyData opKey[3];
-
- *candidates = NULL;
-
- ScanKeyEntryInitialize(&opKey[0], 0,
- Anum_pg_operator_oprname,
- NameEqualRegProcedure,
- NameGetDatum(opname));
-
- ScanKeyEntryInitialize(&opKey[1], 0,
- Anum_pg_operator_oprkind,
- CharacterEqualRegProcedure,
- CharGetDatum('b'));
-
-
- if (leftTypeId == UNKNOWNOID)
- {
- if (rightTypeId == UNKNOWNOID)
- {
- nkeys = 2;
- }
- else
- {
- nkeys = 3;
-
- ScanKeyEntryInitialize(&opKey[2], 0,
- Anum_pg_operator_oprright,
- ObjectIdEqualRegProcedure,
- ObjectIdGetDatum(rightTypeId));
- }
- }
- else if (rightTypeId == UNKNOWNOID)
- {
- nkeys = 3;
-
- ScanKeyEntryInitialize(&opKey[2], 0,
- Anum_pg_operator_oprleft,
- ObjectIdEqualRegProcedure,
- ObjectIdGetDatum(leftTypeId));
- }
- else
- {
- /* currently only "unknown" can be coerced */
- return 0;
- }
-
- pg_operator_desc = heap_openr(OperatorRelationName);
- pg_operator_scan = heap_beginscan(pg_operator_desc,
- 0,
- true,
- nkeys,
- opKey);
-
- do
- {
- tup = heap_getnext(pg_operator_scan, 0, &buffer);
- if (HeapTupleIsValid(tup))
- {
- current_candidate = (CandidateList) palloc(sizeof(struct _CandidateList));
- current_candidate->args = (Oid *) palloc(2 * sizeof(Oid));
-
- oper = (OperatorTupleForm) GETSTRUCT(tup);
- current_candidate->args[0] = oper->oprleft;
- current_candidate->args[1] = oper->oprright;
- current_candidate->next = *candidates;
- *candidates = current_candidate;
- ncandidates++;
- ReleaseBuffer(buffer);
- }
- } while (HeapTupleIsValid(tup));
-
- heap_endscan(pg_operator_scan);
- heap_close(pg_operator_desc);
-
- return ncandidates;
-}
-
-/*
- * equivalentOpersAfterPromotion -
- * checks if a list of candidate operators obtained from
- * binary_oper_get_candidates() contain equivalent operators. If
- * this routine is called, we have more than 1 candidate and need to
- * decided whether to pick one of them. This routine returns true if
- * the all the candidates operate on the same data types after
- * promotion (int2, int4, float4 -> float8).
- */
-static bool
-equivalentOpersAfterPromotion(CandidateList candidates)
-{
- CandidateList result;
- CandidateList promotedCandidates = NULL;
- Oid leftarg,
- rightarg;
-
- for (result = candidates; result != NULL; result = result->next)
- {
- CandidateList c;
-
- c = (CandidateList) palloc(sizeof(*c));
- c->args = (Oid *) palloc(2 * sizeof(Oid));
- switch (result->args[0])
- {
- case FLOAT4OID:
- case INT4OID:
- case INT2OID:
- case CASHOID:
- c->args[0] = FLOAT8OID;
- break;
- default:
- c->args[0] = result->args[0];
- break;
- }
- switch (result->args[1])
- {
- case FLOAT4OID:
- case INT4OID:
- case INT2OID:
- case CASHOID:
- c->args[1] = FLOAT8OID;
- break;
- default:
- c->args[1] = result->args[1];
- break;
- }
- c->next = promotedCandidates;
- promotedCandidates = c;
- }
-
- /*
- * if we get called, we have more than 1 candidates so we can do the
- * following safely
- */
- leftarg = promotedCandidates->args[0];
- rightarg = promotedCandidates->args[1];
-
- for (result = promotedCandidates->next; result != NULL; result = result->next)
- {
- if (result->args[0] != leftarg || result->args[1] != rightarg)
-
- /*
- * this list contains operators that operate on different data
- * types even after promotion. Hence we can't decide on which
- * one to pick. The user must do explicit type casting.
- */
- return FALSE;
- }
-
- /*
- * all the candidates are equivalent in the following sense: they
- * operate on equivalent data types and picking any one of them is as
- * good.
- */
- return TRUE;
-}
-
-
-/*
- * given a choice of argument type pairs for a binary operator,
- * try to choose a default pair
- */
-static CandidateList
-binary_oper_select_candidate(Oid arg1,
- Oid arg2,
- CandidateList candidates)
-{
- CandidateList result;
-
- /*
- * if both are "unknown", there is no way to select a candidate
- *
- * current wisdom holds that the default operator should be one in which
- * both operands have the same type (there will only be one such
- * operator)
- *
- * 7.27.93 - I have decided not to do this; it's too hard to justify, and
- * it's easy enough to typecast explicitly -avi [the rest of this
- * routine were commented out since then -ay]
- */
-
- if (arg1 == UNKNOWNOID && arg2 == UNKNOWNOID)
- return (NULL);
-
- /*
- * 6/23/95 - I don't complete agree with avi. In particular, casting
- * floats is a pain for users. Whatever the rationale behind not doing
- * this is, I need the following special case to work.
- *
- * In the WHERE clause of a query, if a float is specified without
- * quotes, we treat it as float8. I added the float48* operators so
- * that we can operate on float4 and float8. But now we have more than
- * one matching operator if the right arg is unknown (eg. float
- * specified with quotes). This break some stuff in the regression
- * test where there are floats in quotes not properly casted. Below is
- * the solution. In addition to requiring the operator operates on the
- * same type for both operands [as in the code Avi originally
- * commented out], we also require that the operators be equivalent in
- * some sense. (see equivalentOpersAfterPromotion for details.) - ay
- * 6/95
- */
- if (!equivalentOpersAfterPromotion(candidates))
- return NULL;
-
- /*
- * if we get here, any one will do but we're more picky and require
- * both operands be the same.
- */
- for (result = candidates; result != NULL; result = result->next)
- {
- if (result->args[0] == result->args[1])
- return result;
- }
-
- return (NULL);
-}
-
-/* Given operator, types of arg1, and arg2, return oper struct */
-/* arg1, arg2 --typeids */
-Operator
-oper(char *op, Oid arg1, Oid arg2, bool noWarnings)
-{
- HeapTuple tup;
- CandidateList candidates;
- int ncandidates;
-
- if (!arg2)
- arg2 = arg1;
- if (!arg1)
- arg1 = arg2;
-
- if (!(tup = SearchSysCacheTuple(OPRNAME,
- PointerGetDatum(op),
- ObjectIdGetDatum(arg1),
- ObjectIdGetDatum(arg2),
- Int8GetDatum('b'))))
- {
- ncandidates = binary_oper_get_candidates(op, arg1, arg2, &candidates);
- if (ncandidates == 0)
- {
-
- /*
- * no operators of the desired types found
- */
- if (!noWarnings)
- op_error(op, arg1, arg2);
- return (NULL);
- }
- else if (ncandidates == 1)
- {
-
- /*
- * exactly one operator of the desired types found
- */
- tup = SearchSysCacheTuple(OPRNAME,
- PointerGetDatum(op),
- ObjectIdGetDatum(candidates->args[0]),
- ObjectIdGetDatum(candidates->args[1]),
- Int8GetDatum('b'));
- Assert(HeapTupleIsValid(tup));
- }
- else
- {
-
- /*
- * multiple operators of the desired types found
- */
- candidates = binary_oper_select_candidate(arg1, arg2, candidates);
- if (candidates != NULL)
- {
- /* we chose one of them */
- tup = SearchSysCacheTuple(OPRNAME,
- PointerGetDatum(op),
- ObjectIdGetDatum(candidates->args[0]),
- ObjectIdGetDatum(candidates->args[1]),
- Int8GetDatum('b'));
- Assert(HeapTupleIsValid(tup));
- }
- else
- {
- Type tp1,
- tp2;
-
- /* we chose none of them */
- tp1 = get_id_type(arg1);
- tp2 = get_id_type(arg2);
- if (!noWarnings)
- {
- elog(NOTICE, "there is more than one operator %s for types", op);
- elog(NOTICE, "%s and %s. You will have to retype this query",
- tname(tp1), tname(tp2));
- elog(WARN, "using an explicit cast");
- }
- return (NULL);
- }
- }
- }
- return ((Operator) tup);
-}
-
-/*
- * given opname and typeId, find all possible types for which
- * a right/left unary operator named opname exists,
- * such that typeId can be coerced to it
- */
-static int
-unary_oper_get_candidates(char *op,
- Oid typeId,
- CandidateList *candidates,
- char rightleft)
-{
- CandidateList current_candidate;
- Relation pg_operator_desc;
- HeapScanDesc pg_operator_scan;
- HeapTuple tup;
- OperatorTupleForm oper;
- Buffer buffer;
- int ncandidates = 0;
-
- static ScanKeyData opKey[2] = {
- {0, Anum_pg_operator_oprname, NameEqualRegProcedure},
- {0, Anum_pg_operator_oprkind, CharacterEqualRegProcedure}};
-
- *candidates = NULL;
-
- fmgr_info(NameEqualRegProcedure, (func_ptr *) &opKey[0].sk_func,
- &opKey[0].sk_nargs);
- opKey[0].sk_argument = NameGetDatum(op);
- fmgr_info(CharacterEqualRegProcedure, (func_ptr *) &opKey[1].sk_func,
- &opKey[1].sk_nargs);
- opKey[1].sk_argument = CharGetDatum(rightleft);
-
- /* currently, only "unknown" can be coerced */
-
- /*
- * but we should allow types that are internally the same to be
- * "coerced"
- */
- if (typeId != UNKNOWNOID)
- {
- return 0;
- }
-
- pg_operator_desc = heap_openr(OperatorRelationName);
- pg_operator_scan = heap_beginscan(pg_operator_desc,
- 0,
- true,
- 2,
- opKey);
-
- do
- {
- tup = heap_getnext(pg_operator_scan, 0, &buffer);
- if (HeapTupleIsValid(tup))
- {
- current_candidate = (CandidateList) palloc(sizeof(struct _CandidateList));
- current_candidate->args = (Oid *) palloc(sizeof(Oid));
-
- oper = (OperatorTupleForm) GETSTRUCT(tup);
- if (rightleft == 'r')
- current_candidate->args[0] = oper->oprleft;
- else
- current_candidate->args[0] = oper->oprright;
- current_candidate->next = *candidates;
- *candidates = current_candidate;
- ncandidates++;
- ReleaseBuffer(buffer);
- }
- } while (HeapTupleIsValid(tup));
-
- heap_endscan(pg_operator_scan);
- heap_close(pg_operator_desc);
-
- return ncandidates;
-}
-
-/* Given unary right-side operator (operator on right), return oper struct */
-/* arg-- type id */
-Operator
-right_oper(char *op, Oid arg)
-{
- HeapTuple tup;
- CandidateList candidates;
- int ncandidates;
-
- /*
- * if (!OpCache) { init_op_cache(); }
- */
- if (!(tup = SearchSysCacheTuple(OPRNAME,
- PointerGetDatum(op),
- ObjectIdGetDatum(arg),
- ObjectIdGetDatum(InvalidOid),
- Int8GetDatum('r'))))
- {
- ncandidates = unary_oper_get_candidates(op, arg, &candidates, 'r');
- if (ncandidates == 0)
- {
- elog(WARN,
- "Can't find right op: %s for type %d", op, arg);
- return (NULL);
- }
- else if (ncandidates == 1)
- {
- tup = SearchSysCacheTuple(OPRNAME,
- PointerGetDatum(op),
- ObjectIdGetDatum(candidates->args[0]),
- ObjectIdGetDatum(InvalidOid),
- Int8GetDatum('r'));
- Assert(HeapTupleIsValid(tup));
- }
- else
- {
- elog(NOTICE, "there is more than one right operator %s", op);
- elog(NOTICE, "you will have to retype this query");
- elog(WARN, "using an explicit cast");
- return (NULL);
- }
- }
- return ((Operator) tup);
-}
-
-/* Given unary left-side operator (operator on left), return oper struct */
-/* arg--type id */
-Operator
-left_oper(char *op, Oid arg)
-{
- HeapTuple tup;
- CandidateList candidates;
- int ncandidates;
-
- /*
- * if (!OpCache) { init_op_cache(); }
- */
- if (!(tup = SearchSysCacheTuple(OPRNAME,
- PointerGetDatum(op),
- ObjectIdGetDatum(InvalidOid),
- ObjectIdGetDatum(arg),
- Int8GetDatum('l'))))
- {
- ncandidates = unary_oper_get_candidates(op, arg, &candidates, 'l');
- if (ncandidates == 0)
- {
- elog(WARN,
- "Can't find left op: %s for type %d", op, arg);
- return (NULL);
- }
- else if (ncandidates == 1)
- {
- tup = SearchSysCacheTuple(OPRNAME,
- PointerGetDatum(op),
- ObjectIdGetDatum(InvalidOid),
- ObjectIdGetDatum(candidates->args[0]),
- Int8GetDatum('l'));
- Assert(HeapTupleIsValid(tup));
- }
- else
- {
- elog(NOTICE, "there is more than one left operator %s", op);
- elog(NOTICE, "you will have to retype this query");
- elog(WARN, "using an explicit cast");
- return (NULL);
- }
- }
- return ((Operator) tup);
-}
-
-/* given range variable, return id of variable */
-
-int
-varattno(Relation rd, char *a)
-{
- int i;
-
- for (i = 0; i < rd->rd_rel->relnatts; i++)
- {
- if (!namestrcmp(&(rd->rd_att->attrs[i]->attname), a))
- {
- return (i + 1);
- }
- }
- for (i = 0; i < SPECIALS; i++)
- {
- if (!strcmp(special_attr[i].field, a))
- {
- return (special_attr[i].code);
- }
- }
-
- elog(WARN, "Relation %s does not have attribute %s",
- RelationGetRelationName(rd), a);
- return (-1);
-}
-
-/* Given range variable, return whether attribute of this name
- * is a set.
- * NOTE the ASSUMPTION here that no system attributes are, or ever
- * will be, sets.
- */
-bool
-varisset(Relation rd, char *name)
-{
- int i;
-
- /* First check if this is a system attribute */
- for (i = 0; i < SPECIALS; i++)
- {
- if (!strcmp(special_attr[i].field, name))
- {
- return (false); /* no sys attr is a set */
- }
- }
- return (get_attisset(rd->rd_id, name));
-}
-
-/* given range variable, return id of variable */
-int
-nf_varattno(Relation rd, char *a)
-{
- int i;
-
- for (i = 0; i < rd->rd_rel->relnatts; i++)
- {
- if (!namestrcmp(&(rd->rd_att->attrs[i]->attname), a))
- {
- return (i + 1);
- }
- }
- for (i = 0; i < SPECIALS; i++)
- {
- if (!strcmp(special_attr[i].field, a))
- {
- return (special_attr[i].code);
- }
- }
- return InvalidAttrNumber;
-}
-
-/*-------------
- * given an attribute number and a relation, return its relation name
- */
-char *
-getAttrName(Relation rd, int attrno)
-{
- char *name;
- int i;
-
- if (attrno < 0)
- {
- for (i = 0; i < SPECIALS; i++)
- {
- if (special_attr[i].code == attrno)
- {
- name = special_attr[i].field;
- return (name);
- }
- }
- elog(WARN, "Illegal attr no %d for relation %s",
- attrno, RelationGetRelationName(rd));
- }
- else if (attrno >= 1 && attrno <= RelationGetNumberOfAttributes(rd))
- {
- name = (rd->rd_att->attrs[attrno - 1]->attname).data;
- return (name);
- }
- else
- {
- elog(WARN, "Illegal attr no %d for relation %s",
- attrno, RelationGetRelationName(rd));
- }
-
- /*
- * Shouldn't get here, but we want lint to be happy...
- */
-
- return (NULL);
-}
-
-/* Given a typename and value, returns the ascii form of the value */
-
-#ifdef NOT_USED
-char *
-outstr(char *typename, /* Name of type of value */
- char *value) /* Could be of any type */
-{
- TypeTupleForm tp;
- Oid op;
-
- tp = (TypeTupleForm) GETSTRUCT(type(typename));
- op = tp->typoutput;
- return ((char *) fmgr(op, value));
-}
-
-#endif
-
-/* Given a Type and a string, return the internal form of that string */
-char *
-instr2(Type tp, char *string, int typlen)
-{
- return (instr1((TypeTupleForm) GETSTRUCT(tp), string, typlen));
-}
-
-/* Given a type structure and a string, returns the internal form of
- that string */
-static char *
-instr1(TypeTupleForm tp, char *string, int typlen)
-{
- Oid op;
- Oid typelem;
-
- op = tp->typinput;
- typelem = tp->typelem; /* XXX - used for array_in */
- /* typlen is for bpcharin() and varcharin() */
- return ((char *) fmgr(op, string, typelem, typlen));
-}
-
-/* Given the attribute type of an array return the arrtribute type of
- an element of the array */
-
-Oid
-GetArrayElementType(Oid typearray)
-{
- HeapTuple type_tuple;
- TypeTupleForm type_struct_array;
-
- type_tuple = SearchSysCacheTuple(TYPOID,
- ObjectIdGetDatum(typearray),
- 0, 0, 0);
-
- if (!HeapTupleIsValid(type_tuple))
- elog(WARN, "GetArrayElementType: Cache lookup failed for type %d",
- typearray);
-
- /* get the array type struct from the type tuple */
- type_struct_array = (TypeTupleForm) GETSTRUCT(type_tuple);
-
- if (type_struct_array->typelem == InvalidOid)
- {
- elog(WARN, "GetArrayElementType: type %s is not an array",
- (Name) &(type_struct_array->typname.data[0]));
- }
-
- return (type_struct_array->typelem);
-}
-
-Oid
-funcid_get_rettype(Oid funcid)
-{
- HeapTuple func_tuple = NULL;
- Oid funcrettype = (Oid) 0;
-
- func_tuple = SearchSysCacheTuple(PROOID, ObjectIdGetDatum(funcid),
- 0, 0, 0);
-
- if (!HeapTupleIsValid(func_tuple))
- elog(WARN, "function %d does not exist", funcid);
-
- funcrettype = (Oid)
- ((Form_pg_proc) GETSTRUCT(func_tuple))->prorettype;
-
- return (funcrettype);
-}
-
-/*
- * get a list of all argument type vectors for which a function named
- * funcname taking nargs arguments exists
- */
-static CandidateList
-func_get_candidates(char *funcname, int nargs)
-{
- Relation heapRelation;
- Relation idesc;
- ScanKeyData skey;
- HeapTuple tuple;
- IndexScanDesc sd;
- RetrieveIndexResult indexRes;
- Buffer buffer;
- Form_pg_proc pgProcP;
- bool bufferUsed = FALSE;
- CandidateList candidates = NULL;
- CandidateList current_candidate;
- int i;
-
- heapRelation = heap_openr(ProcedureRelationName);
- ScanKeyEntryInitialize(&skey,
- (bits16) 0x0,
- (AttrNumber) 1,
- (RegProcedure) NameEqualRegProcedure,
- (Datum) funcname);
-
- idesc = index_openr(ProcedureNameIndex);
-
- sd = index_beginscan(idesc, false, 1, &skey);
-
- do
- {
- tuple = (HeapTuple) NULL;
- if (bufferUsed)
- {
- ReleaseBuffer(buffer);
- bufferUsed = FALSE;
- }
-
- indexRes = index_getnext(sd, ForwardScanDirection);
- if (indexRes)
- {
- ItemPointer iptr;
-
- iptr = &indexRes->heap_iptr;
- tuple = heap_fetch(heapRelation, false, iptr, &buffer);
- pfree(indexRes);
- if (HeapTupleIsValid(tuple))
- {
- pgProcP = (Form_pg_proc) GETSTRUCT(tuple);
- bufferUsed = TRUE;
- if (pgProcP->pronargs == nargs)
- {
- current_candidate = (CandidateList)
- palloc(sizeof(struct _CandidateList));
- current_candidate->args = (Oid *)
- palloc(8 * sizeof(Oid));
- MemSet(current_candidate->args, 0, 8 * sizeof(Oid));
- for (i = 0; i < nargs; i++)
- {
- current_candidate->args[i] =
- pgProcP->proargtypes[i];
- }
-
- current_candidate->next = candidates;
- candidates = current_candidate;
- }
- }
- }
- } while (indexRes);
-
- index_endscan(sd);
- index_close(idesc);
- heap_close(heapRelation);
-
- return candidates;
-}
-
-/*
- * can input_typeids be coerced to func_typeids?
- */
-static bool
-can_coerce(int nargs, Oid *input_typeids, Oid *func_typeids)
-{
- int i;
- Type tp;
-
- /*
- * right now, we only coerce "unknown", and we cannot coerce it to a
- * relation type
- */
- for (i = 0; i < nargs; i++)
- {
- if (input_typeids[i] != func_typeids[i])
- {
- if ((input_typeids[i] == BPCHAROID && func_typeids[i] == TEXTOID) ||
- (input_typeids[i] == BPCHAROID && func_typeids[i] == VARCHAROID) ||
- (input_typeids[i] == VARCHAROID && func_typeids[i] == TEXTOID) ||
- (input_typeids[i] == VARCHAROID && func_typeids[i] == BPCHAROID) ||
- (input_typeids[i] == CASHOID && func_typeids[i] == INT4OID) ||
- (input_typeids[i] == INT4OID && func_typeids[i] == CASHOID))
- ; /* these are OK */
- else if (input_typeids[i] != UNKNOWNOID || func_typeids[i] == 0)
- return false;
-
- tp = get_id_type(input_typeids[i]);
- if (typetypetype(tp) == 'c')
- return false;
- }
- }
-
- return true;
-}
-
-/*
- * given a list of possible typeid arrays to a function and an array of
- * input typeids, produce a shortlist of those function typeid arrays
- * that match the input typeids (either exactly or by coercion), and
- * return the number of such arrays
- */
-static int
-match_argtypes(int nargs,
- Oid *input_typeids,
- CandidateList function_typeids,
- CandidateList *candidates) /* return value */
-{
- CandidateList current_candidate;
- CandidateList matching_candidate;
- Oid *current_typeids;
- int ncandidates = 0;
-
- *candidates = NULL;
-
- for (current_candidate = function_typeids;
- current_candidate != NULL;
- current_candidate = current_candidate->next)
- {
- current_typeids = current_candidate->args;
- if (can_coerce(nargs, input_typeids, current_typeids))
- {
- matching_candidate = (CandidateList)
- palloc(sizeof(struct _CandidateList));
- matching_candidate->args = current_typeids;
- matching_candidate->next = *candidates;
- *candidates = matching_candidate;
- ncandidates++;
- }
- }
-
- return ncandidates;
-}
-
-/*
- * given the input argtype array and more than one candidate
- * for the function argtype array, attempt to resolve the conflict.
- * returns the selected argtype array if the conflict can be resolved,
- * otherwise returns NULL
- */
-static Oid *
-func_select_candidate(int nargs,
- Oid *input_typeids,
- CandidateList candidates)
-{
- /* XXX no conflict resolution implemeneted yet */
- return (NULL);
-}
-
-bool
-func_get_detail(char *funcname,
- int nargs,
- Oid *oid_array,
- Oid *funcid, /* return value */
- Oid *rettype, /* return value */
- bool *retset, /* return value */
- Oid **true_typeids) /* return value */
-{
- Oid **input_typeid_vector;
- Oid *current_input_typeids;
- CandidateList function_typeids;
- CandidateList current_function_typeids;
- HeapTuple ftup;
- Form_pg_proc pform;
-
- /*
- * attempt to find named function in the system catalogs with
- * arguments exactly as specified - so that the normal case is just as
- * quick as before
- */
- ftup = SearchSysCacheTuple(PRONAME,
- PointerGetDatum(funcname),
- Int32GetDatum(nargs),
- PointerGetDatum(oid_array),
- 0);
- *true_typeids = oid_array;
-
- /*
- * If an exact match isn't found : 1) get a vector of all possible
- * input arg type arrays constructed from the superclasses of the
- * original input arg types 2) get a list of all possible argument
- * type arrays to the function with given name and number of arguments
- * 3) for each input arg type array from vector #1 : a) find how many
- * of the function arg type arrays from list #2 it can be coerced to
- * b) - if the answer is one, we have our function - if the answer is
- * more than one, attempt to resolve the conflict - if the answer is
- * zero, try the next array from vector #1
- */
- if (!HeapTupleIsValid(ftup))
- {
- function_typeids = func_get_candidates(funcname, nargs);
-
- if (function_typeids != NULL)
- {
- int ncandidates = 0;
-
- input_typeid_vector = argtype_inherit(nargs, oid_array);
- current_input_typeids = oid_array;
-
- do
- {
- ncandidates = match_argtypes(nargs, current_input_typeids,
- function_typeids,
- &current_function_typeids);
- if (ncandidates == 1)
- {
- *true_typeids = current_function_typeids->args;
- ftup = SearchSysCacheTuple(PRONAME,
- PointerGetDatum(funcname),
- Int32GetDatum(nargs),
- PointerGetDatum(*true_typeids),
- 0);
- Assert(HeapTupleIsValid(ftup));
- }
- else if (ncandidates > 1)
- {
- *true_typeids =
- func_select_candidate(nargs,
- current_input_typeids,
- current_function_typeids);
- if (*true_typeids == NULL)
- {
- elog(NOTICE, "there is more than one function named \"%s\"",
- funcname);
- elog(NOTICE, "that satisfies the given argument types. you will have to");
- elog(NOTICE, "retype your query using explicit typecasts.");
- func_error("func_get_detail", funcname, nargs, oid_array);
- }
- else
- {
- ftup = SearchSysCacheTuple(PRONAME,
- PointerGetDatum(funcname),
- Int32GetDatum(nargs),
- PointerGetDatum(*true_typeids),
- 0);
- Assert(HeapTupleIsValid(ftup));
- }
- }
- current_input_typeids = *input_typeid_vector++;
- }
- while (current_input_typeids !=
- InvalidOid && ncandidates == 0);
- }
- }
-
- if (!HeapTupleIsValid(ftup))
- {
- Type tp;
-
- if (nargs == 1)
- {
- tp = get_id_type(oid_array[0]);
- if (typetypetype(tp) == 'c')
- elog(WARN, "no such attribute or function \"%s\"",
- funcname);
- }
- func_error("func_get_detail", funcname, nargs, oid_array);
- }
- else
- {
- pform = (Form_pg_proc) GETSTRUCT(ftup);
- *funcid = ftup->t_oid;
- *rettype = pform->prorettype;
- *retset = pform->proretset;
-
- return (true);
- }
-/* shouldn't reach here */
- return (false);
-
-}
-
-/*
- * argtype_inherit() -- Construct an argtype vector reflecting the
- * inheritance properties of the supplied argv.
- *
- * This function is used to disambiguate among functions with the
- * same name but different signatures. It takes an array of eight
- * type ids. For each type id in the array that's a complex type
- * (a class), it walks up the inheritance tree, finding all
- * superclasses of that type. A vector of new Oid type arrays
- * is returned to the caller, reflecting the structure of the
- * inheritance tree above the supplied arguments.
- *
- * The order of this vector is as follows: all superclasses of the
- * rightmost complex class are explored first. The exploration
- * continues from right to left. This policy means that we favor
- * keeping the leftmost argument type as low in the inheritance tree
- * as possible. This is intentional; it is exactly what we need to
- * do for method dispatch. The last type array we return is all
- * zeroes. This will match any functions for which return types are
- * not defined. There are lots of these (mostly builtins) in the
- * catalogs.
- */
-static Oid **
-argtype_inherit(int nargs, Oid *oid_array)
-{
- Oid relid;
- int i;
- InhPaths arginh[MAXFARGS];
-
- for (i = 0; i < MAXFARGS; i++)
- {
- if (i < nargs)
- {
- arginh[i].self = oid_array[i];
- if ((relid = typeid_get_relid(oid_array[i])) != InvalidOid)
- {
- arginh[i].nsupers = findsupers(relid, &(arginh[i].supervec));
- }
- else
- {
- arginh[i].nsupers = 0;
- arginh[i].supervec = (Oid *) NULL;
- }
- }
- else
- {
- arginh[i].self = InvalidOid;
- arginh[i].nsupers = 0;
- arginh[i].supervec = (Oid *) NULL;
- }
- }
-
- /* return an ordered cross-product of the classes involved */
- return (genxprod(arginh, nargs));
-}
-
-typedef struct _SuperQE
-{
- Oid sqe_relid;
-} SuperQE;
-
-static int
-findsupers(Oid relid, Oid **supervec)
-{
- Oid *relidvec;
- Relation inhrel;
- HeapScanDesc inhscan;
- ScanKeyData skey;
- HeapTuple inhtup;
- TupleDesc inhtupdesc;
- int nvisited;
- SuperQE *qentry,
- *vnode;
- Dllist *visited,
- *queue;
- Dlelem *qe,
- *elt;
-
- Relation rd;
- Buffer buf;
- Datum d;
- bool newrelid;
- char isNull;
-
- nvisited = 0;
- queue = DLNewList();
- visited = DLNewList();
-
-
- inhrel = heap_openr(InheritsRelationName);
- RelationSetLockForRead(inhrel);
- inhtupdesc = RelationGetTupleDescriptor(inhrel);
-
- /*
- * Use queue to do a breadth-first traversal of the inheritance graph
- * from the relid supplied up to the root.
- */
- do
- {
- ScanKeyEntryInitialize(&skey, 0x0, Anum_pg_inherits_inhrel,
- ObjectIdEqualRegProcedure,
- ObjectIdGetDatum(relid));
-
- inhscan = heap_beginscan(inhrel, 0, false, 1, &skey);
-
- while (HeapTupleIsValid(inhtup = heap_getnext(inhscan, 0, &buf)))
- {
- qentry = (SuperQE *) palloc(sizeof(SuperQE));
-
- d = fastgetattr(inhtup, Anum_pg_inherits_inhparent,
- inhtupdesc, &isNull);
- qentry->sqe_relid = DatumGetObjectId(d);
-
- /* put this one on the queue */
- DLAddTail(queue, DLNewElem(qentry));
-
- ReleaseBuffer(buf);
- }
-
- heap_endscan(inhscan);
-
- /* pull next unvisited relid off the queue */
- do
- {
- qe = DLRemHead(queue);
- qentry = qe ? (SuperQE *) DLE_VAL(qe) : NULL;
-
- if (qentry == (SuperQE *) NULL)
- break;
-
- relid = qentry->sqe_relid;
- newrelid = true;
-
- for (elt = DLGetHead(visited); elt; elt = DLGetSucc(elt))
- {
- vnode = (SuperQE *) DLE_VAL(elt);
- if (vnode && (qentry->sqe_relid == vnode->sqe_relid))
- {
- newrelid = false;
- break;
- }
- }
- } while (!newrelid);
-
- if (qentry != (SuperQE *) NULL)
- {
-
- /* save the type id, rather than the relation id */
- if ((rd = heap_open(qentry->sqe_relid)) == (Relation) NULL)
- elog(WARN, "relid %d does not exist", qentry->sqe_relid);
- qentry->sqe_relid = typeid(type(RelationGetRelationName(rd)->data));
- heap_close(rd);
-
- DLAddTail(visited, qe);
-
- nvisited++;
- }
- } while (qentry != (SuperQE *) NULL);
-
- RelationUnsetLockForRead(inhrel);
- heap_close(inhrel);
-
- if (nvisited > 0)
- {
- relidvec = (Oid *) palloc(nvisited * sizeof(Oid));
- *supervec = relidvec;
-
- for (elt = DLGetHead(visited); elt; elt = DLGetSucc(elt))
- {
- vnode = (SuperQE *) DLE_VAL(elt);
- *relidvec++ = vnode->sqe_relid;
- }
-
- }
- else
- {
- *supervec = (Oid *) NULL;
- }
-
- return (nvisited);
-}
-
-static Oid **
-genxprod(InhPaths *arginh, int nargs)
-{
- int nanswers;
- Oid **result,
- **iter;
- Oid *oneres;
- int i,
- j;
- int cur[MAXFARGS];
-
- nanswers = 1;
- for (i = 0; i < nargs; i++)
- {
- nanswers *= (arginh[i].nsupers + 2);
- cur[i] = 0;
- }
-
- iter = result = (Oid **) palloc(sizeof(Oid *) * nanswers);
-
- /* compute the cross product from right to left */
- for (;;)
- {
- oneres = (Oid *) palloc(MAXFARGS * sizeof(Oid));
- MemSet(oneres, 0, MAXFARGS * sizeof(Oid));
-
- for (i = nargs - 1; i >= 0 && cur[i] > arginh[i].nsupers; i--)
- continue;
-
- /* if we're done, terminate with NULL pointer */
- if (i < 0)
- {
- *iter = NULL;
- return (result);
- }
-
- /* no, increment this column and zero the ones after it */
- cur[i] = cur[i] + 1;
- for (j = nargs - 1; j > i; j--)
- cur[j] = 0;
-
- for (i = 0; i < nargs; i++)
- {
- if (cur[i] == 0)
- oneres[i] = arginh[i].self;
- else if (cur[i] > arginh[i].nsupers)
- oneres[i] = 0; /* wild card */
- else
- oneres[i] = arginh[i].supervec[cur[i] - 1];
- }
-
- *iter++ = oneres;
- }
-}
-
-/* Given a type id, returns the in-conversion function of the type */
-Oid
-typeid_get_retinfunc(Oid type_id)
-{
- HeapTuple typeTuple;
- TypeTupleForm type;
- Oid infunc;
-
- typeTuple = SearchSysCacheTuple(TYPOID,
- ObjectIdGetDatum(type_id),
- 0, 0, 0);
- if (!HeapTupleIsValid(typeTuple))
- elog(WARN, "typeid_get_retinfunc: Invalid type - oid = %u", type_id);
-
- type = (TypeTupleForm) GETSTRUCT(typeTuple);
- infunc = type->typinput;
- return (infunc);
-}
-
-/* Given a type id, returns the out-conversion function of the type */
-Oid
-typeid_get_retoutfunc(Oid type_id)
-{
- HeapTuple typeTuple;
- TypeTupleForm type;
- Oid outfunc;
-
- typeTuple = SearchSysCacheTuple(TYPOID,
- ObjectIdGetDatum(type_id),
- 0, 0, 0);
- if (!HeapTupleIsValid(typeTuple))
- elog(WARN, "typeid_get_retoutfunc: Invalid type - oid = %u", type_id);
-
- type = (TypeTupleForm) GETSTRUCT(typeTuple);
- outfunc = type->typoutput;
- return (outfunc);
-}
-
-Oid
-typeid_get_relid(Oid type_id)
-{
- HeapTuple typeTuple;
- TypeTupleForm type;
- Oid infunc;
-
- typeTuple = SearchSysCacheTuple(TYPOID,
- ObjectIdGetDatum(type_id),
- 0, 0, 0);
- if (!HeapTupleIsValid(typeTuple))
- elog(WARN, "typeid_get_relid: Invalid type - oid = %u", type_id);
-
- type = (TypeTupleForm) GETSTRUCT(typeTuple);
- infunc = type->typrelid;
- return (infunc);
-}
-
-Oid
-get_typrelid(Type typ)
-{
- TypeTupleForm typtup;
-
- typtup = (TypeTupleForm) GETSTRUCT(typ);
-
- return (typtup->typrelid);
-}
-
-Oid
-get_typelem(Oid type_id)
-{
- HeapTuple typeTuple;
- TypeTupleForm type;
-
- if (!(typeTuple = SearchSysCacheTuple(TYPOID,
- ObjectIdGetDatum(type_id),
- 0, 0, 0)))
- {
- elog(WARN, "type id lookup of %u failed", type_id);
- }
- type = (TypeTupleForm) GETSTRUCT(typeTuple);
-
- return (type->typelem);
-}
-
-#ifdef NOT_USED
-char
-FindDelimiter(char *typename)
-{
- char delim;
- HeapTuple typeTuple;
- TypeTupleForm type;
-
-
- if (!(typeTuple = SearchSysCacheTuple(TYPNAME,
- PointerGetDatum(typename),
- 0, 0, 0)))
- {
- elog(WARN, "type name lookup of %s failed", typename);
- }
- type = (TypeTupleForm) GETSTRUCT(typeTuple);
-
- delim = type->typdelim;
- return (delim);
-}
-
-#endif
-
-/*
- * Give a somewhat useful error message when the operator for two types
- * is not found.
- */
-static void
-op_error(char *op, Oid arg1, Oid arg2)
-{
- Type tp1 = NULL,
- tp2 = NULL;
-
- if (check_typeid(arg1))
- {
- tp1 = get_id_type(arg1);
- }
- else
- {
- elog(WARN, "left hand side of operator %s has an unknown type, probably a bad attribute name", op);
- }
-
- if (check_typeid(arg2))
- {
- tp2 = get_id_type(arg2);
- }
- else
- {
- elog(WARN, "right hand side of operator %s has an unknown type, probably a bad attribute name", op);
- }
-
- elog(NOTICE, "there is no operator %s for types %s and %s",
- op, tname(tp1), tname(tp2));
- elog(NOTICE, "You will either have to retype this query using an");
- elog(NOTICE, "explicit cast, or you will have to define the operator");
- elog(WARN, "%s for %s and %s using CREATE OPERATOR",
- op, tname(tp1), tname(tp2));
-}
-
-/*
- * Error message when function lookup fails that gives details of the
- * argument types
- */
-void
-func_error(char *caller, char *funcname, int nargs, Oid *argtypes)
-{
- char p[(NAMEDATALEN + 2) * MAXFMGRARGS],
- *ptr;
- int i;
-
- ptr = p;
- *ptr = '\0';
- for (i = 0; i < nargs; i++)
- {
- if (i)
- {
- *ptr++ = ',';
- *ptr++ = ' ';
- }
- if (argtypes[i] != 0)
- {
- strcpy(ptr, tname(get_id_type(argtypes[i])));
- *(ptr + NAMEDATALEN) = '\0';
- }
- else
- strcpy(ptr, "opaque");
- ptr += strlen(ptr);
- }
-
- elog(WARN, "%s: function %s(%s) does not exist", caller, funcname, p);
-}
-
-/*
- * Error message when aggregate lookup fails that gives details of the
- * basetype
- */
-void
-agg_error(char *caller, char *aggname, Oid basetypeID)
-{
-
- /*
- * basetypeID that is Invalid (zero) means aggregate over all types.
- * (count)
- */
-
- if (basetypeID == InvalidOid)
- {
- elog(WARN, "%s: aggregate '%s' for all types does not exist", caller, aggname);
- }
- else
- {
- elog(WARN, "%s: aggregate '%s' for '%s' does not exist", caller, aggname,
- tname(get_id_type(basetypeID)));
- }
-}