1 /*-------------------------------------------------------------------------
5 * Copyright (c) 1994, Regents of the University of California
9 * $Header: /cvsroot/pgsql/src/backend/parser/Attic/catalog_utils.c,v 1.12 1996/11/30 18:06:31 momjian Exp $
11 *-------------------------------------------------------------------------
16 #include "lib/dllist.h"
17 #include "utils/datum.h"
19 #include "utils/builtins.h"
20 #include "utils/elog.h"
21 #include "utils/palloc.h"
24 #include "nodes/pg_list.h"
25 #include "nodes/parsenodes.h"
26 #include "utils/syscache.h"
27 #include "catalog/catname.h"
29 #include "parser/catalog_utils.h"
30 #include "catalog/pg_inherits.h"
31 #include "catalog/pg_operator.h"
32 #include "catalog/pg_type.h"
33 #include "catalog/pg_proc.h"
34 #include "catalog/indexing.h"
35 #include "catalog/catname.h"
37 #include "access/skey.h"
38 #include "access/relscan.h"
39 #include "access/tupdesc.h"
40 #include "access/htup.h"
41 #include "access/heapam.h"
42 #include "access/genam.h"
43 #include "access/itup.h"
44 #include "access/tupmacs.h"
46 #include "storage/buf.h"
47 #include "storage/bufmgr.h"
48 #include "utils/lsyscache.h"
49 #include "storage/lmgr.h"
51 #include "port-protos.h" /* strdup() */
57 { "ctid", SelfItemPointerAttributeNumber },
58 { "oid", ObjectIdAttributeNumber },
59 { "xmin", MinTransactionIdAttributeNumber },
60 { "cmin", MinCommandIdAttributeNumber },
61 { "xmax", MaxTransactionIdAttributeNumber },
62 { "cmax", MaxCommandIdAttributeNumber },
63 { "chain", ChainItemPointerAttributeNumber },
64 { "anchor", AnchorItemPointerAttributeNumber },
65 { "tmin", MinAbsoluteTimeAttributeNumber },
66 { "tmax", MaxAbsoluteTimeAttributeNumber },
67 { "vtype", VersionTypeAttributeNumber }
70 #define SPECIALS (sizeof(special_attr)/sizeof(*special_attr))
72 static char *attnum_type[SPECIALS] = {
86 #define MAXFARGS 8 /* max # args to a c or postquel function */
89 * This structure is used to explore the inheritance hierarchy above
90 * nodes in the type tree in order to disambiguate among polymorphic
94 typedef struct _InhPaths {
95 int nsupers; /* number of superclasses */
96 Oid self; /* this class */
97 Oid *supervec; /* vector of superclasses */
101 * This structure holds a list of possible functions or operators that
102 * agree with the known name and argument types of the function/operator.
104 typedef struct _CandidateList {
106 struct _CandidateList *next;
109 static Oid **argtype_inherit(int nargs, Oid *oid_array);
110 static Oid **genxprod(InhPaths *arginh, int nargs);
111 static int findsupers(Oid relid, Oid **supervec);
113 static bool is_lowercase(char *string);
114 static void make_lowercase(char *string);
116 /* check to see if a type id is valid,
117 * returns true if it is. By using this call before calling
118 * get_id_type or get_id_typname, more meaningful error messages
119 * can be produced because the caller typically has more context of
120 * what's going on - jolly
123 check_typeid(long id)
125 return (SearchSysCacheTuple(TYPOID,
126 ObjectIdGetDatum(id),
131 /* return a Type structure, given an typid */
137 if (!(tup = SearchSysCacheTuple(TYPOID, ObjectIdGetDatum(id),
139 elog ( WARN, "type id lookup of %d failed", id);
145 /* return a type name, given a typeid */
147 get_id_typname(long id)
150 TypeTupleForm typetuple;
152 if (!(tup = SearchSysCacheTuple(TYPOID, ObjectIdGetDatum(id),
154 elog ( WARN, "type id lookup of %d failed", id);
157 typetuple = (TypeTupleForm)GETSTRUCT(tup);
158 return (typetuple->typname).data;
161 /* return a Type structure, given type name */
168 elog ( WARN , "type(): Null type" );
171 if (!(tup = SearchSysCacheTuple(TYPNAME, PointerGetDatum(s), 0,0,0))) {
172 elog (WARN , "type name lookup of %s failed", s);
177 /* given attribute id, return type of that attribute */
178 /* XXX Special case for pseudo-attributes is a hack */
180 att_typeid(Relation rd, int attid)
184 return(typeid(type(attnum_type[-attid-1])));
186 /* -1 because varattno (where attid comes from) returns one
188 return(rd->rd_att->attrs[attid-1]->atttypid);
193 att_attnelems(Relation rd, int attid)
195 return(rd->rd_att->attrs[attid-1]->attnelems);
198 /* given type, return the type OID */
203 elog ( WARN , "typeid() called with NULL type struct");
208 /* given type (as type struct), return the length of type */
214 typ = (TypeTupleForm)GETSTRUCT(t);
218 /* given type (as type struct), return the value of its 'byval' attribute.*/
224 typ = (TypeTupleForm)GETSTRUCT(t);
225 return(typ->typbyval);
228 /* given type (as type struct), return the name of type */
234 typ = (TypeTupleForm)GETSTRUCT(t);
235 return (typ->typname).data;
238 /* given type (as type struct), return wether type is passed by value */
244 typ = (TypeTupleForm) GETSTRUCT(t);
245 return(typ->typbyval);
248 /* given a type, return its typetype ('c' for 'c'atalog types) */
254 typ = (TypeTupleForm) GETSTRUCT(t);
255 return(typ->typtype);
258 /* given operator, return the operator OID */
266 * given opname, leftTypeId and rightTypeId,
267 * find all possible (arg1, arg2) pairs for which an operator named
268 * opname exists, such that leftTypeId can be coerced to arg1 and
269 * rightTypeId can be coerced to arg2
272 binary_oper_get_candidates(char *opname,
275 CandidateList *candidates)
277 CandidateList current_candidate;
278 Relation pg_operator_desc;
279 HeapScanDesc pg_operator_scan;
281 OperatorTupleForm oper;
285 ScanKeyData opKey[3];
289 ScanKeyEntryInitialize(&opKey[0], 0,
290 Anum_pg_operator_oprname,
291 NameEqualRegProcedure,
292 NameGetDatum(opname));
294 ScanKeyEntryInitialize(&opKey[1], 0,
295 Anum_pg_operator_oprkind,
296 CharacterEqualRegProcedure,
300 if (leftTypeId == UNKNOWNOID) {
301 if (rightTypeId == UNKNOWNOID) {
306 ScanKeyEntryInitialize(&opKey[2], 0,
307 Anum_pg_operator_oprright,
308 ObjectIdEqualRegProcedure,
309 ObjectIdGetDatum(rightTypeId));
311 } else if (rightTypeId == UNKNOWNOID) {
314 ScanKeyEntryInitialize(&opKey[2], 0,
315 Anum_pg_operator_oprleft,
316 ObjectIdEqualRegProcedure,
317 ObjectIdGetDatum(leftTypeId));
319 /* currently only "unknown" can be coerced */
323 pg_operator_desc = heap_openr(OperatorRelationName);
324 pg_operator_scan = heap_beginscan(pg_operator_desc,
331 tup = heap_getnext(pg_operator_scan, 0, &buffer);
332 if (HeapTupleIsValid(tup)) {
333 current_candidate = (CandidateList)palloc(sizeof(struct _CandidateList));
334 current_candidate->args = (Oid *)palloc(2 * sizeof(Oid));
336 oper = (OperatorTupleForm)GETSTRUCT(tup);
337 current_candidate->args[0] = oper->oprleft;
338 current_candidate->args[1] = oper->oprright;
339 current_candidate->next = *candidates;
340 *candidates = current_candidate;
342 ReleaseBuffer(buffer);
344 } while(HeapTupleIsValid(tup));
346 heap_endscan(pg_operator_scan);
347 heap_close(pg_operator_desc);
353 * equivalentOpersAfterPromotion -
354 * checks if a list of candidate operators obtained from
355 * binary_oper_get_candidates() contain equivalent operators. If
356 * this routine is called, we have more than 1 candidate and need to
357 * decided whether to pick one of them. This routine returns true if
358 * the all the candidates operate on the same data types after
359 * promotion (int2, int4, float4 -> float8).
362 equivalentOpersAfterPromotion(CandidateList candidates)
364 CandidateList result;
365 CandidateList promotedCandidates = NULL;
366 Oid leftarg, rightarg;
368 for (result = candidates; result != NULL; result = result->next) {
370 c = (CandidateList)palloc(sizeof(*c));
371 c->args = (Oid *)palloc(2 * sizeof(Oid));
372 switch (result->args[0]) {
376 c->args[0] = FLOAT8OID;
379 c->args[0] = result->args[0];
382 switch (result->args[1]) {
386 c->args[1] = FLOAT8OID;
389 c->args[1] = result->args[1];
392 c->next = promotedCandidates;
393 promotedCandidates = c;
396 /* if we get called, we have more than 1 candidates so we can do the
398 leftarg = promotedCandidates->args[0];
399 rightarg = promotedCandidates->args[1];
401 for (result=promotedCandidates->next; result!=NULL; result=result->next) {
402 if (result->args[0]!=leftarg || result->args[1]!=rightarg)
404 * this list contains operators that operate on different
405 * data types even after promotion. Hence we can't decide on
406 * which one to pick. The user must do explicit type casting.
411 /* all the candidates are equivalent in the following sense: they operate
412 on equivalent data types and picking any one of them is as good. */
418 * given a choice of argument type pairs for a binary operator,
419 * try to choose a default pair
422 binary_oper_select_candidate(Oid arg1,
424 CandidateList candidates)
426 CandidateList result;
429 * if both are "unknown", there is no way to select a candidate
431 * current wisdom holds that the default operator should be one
432 * in which both operands have the same type (there will only
433 * be one such operator)
435 * 7.27.93 - I have decided not to do this; it's too hard to
436 * justify, and it's easy enough to typecast explicitly -avi
437 * [the rest of this routine were commented out since then -ay]
440 if (arg1 == UNKNOWNOID && arg2 == UNKNOWNOID)
444 * 6/23/95 - I don't complete agree with avi. In particular, casting
445 * floats is a pain for users. Whatever the rationale behind not doing
446 * this is, I need the following special case to work.
448 * In the WHERE clause of a query, if a float is specified without
449 * quotes, we treat it as float8. I added the float48* operators so
450 * that we can operate on float4 and float8. But now we have more
451 * than one matching operator if the right arg is unknown (eg. float
452 * specified with quotes). This break some stuff in the regression
453 * test where there are floats in quotes not properly casted. Below
454 * is the solution. In addition to requiring the operator operates
455 * on the same type for both operands [as in the code Avi originally
456 * commented out], we also require that the operators be equivalent
457 * in some sense. (see equivalentOpersAfterPromotion for details.)
460 if (!equivalentOpersAfterPromotion(candidates))
463 /* if we get here, any one will do but we're more picky and require
464 both operands be the same. */
465 for (result = candidates; result != NULL; result = result->next) {
466 if (result->args[0] == result->args[1])
473 /* Given operator, types of arg1, and arg2, return oper struct */
474 /* arg1, arg2 --typeids */
476 oper(char *op, Oid arg1, Oid arg2)
479 CandidateList candidates;
482 if (!arg2) arg2=arg1;
483 if (!arg1) arg1=arg2;
485 if (!(tup = SearchSysCacheTuple(OPRNAME,
487 ObjectIdGetDatum(arg1),
488 ObjectIdGetDatum(arg2),
489 Int8GetDatum('b')))) {
490 ncandidates = binary_oper_get_candidates(op, arg1, arg2, &candidates);
491 if (ncandidates == 0) {
493 * no operators of the desired types found
495 op_error(op, arg1, arg2);
497 } else if (ncandidates == 1) {
499 * exactly one operator of the desired types found
501 tup = SearchSysCacheTuple(OPRNAME,
503 ObjectIdGetDatum(candidates->args[0]),
504 ObjectIdGetDatum(candidates->args[1]),
506 Assert(HeapTupleIsValid(tup));
509 * multiple operators of the desired types found
511 candidates = binary_oper_select_candidate(arg1, arg2, candidates);
512 if (candidates != NULL) {
513 /* we chose one of them */
514 tup = SearchSysCacheTuple(OPRNAME,
516 ObjectIdGetDatum(candidates->args[0]),
517 ObjectIdGetDatum(candidates->args[1]),
519 Assert(HeapTupleIsValid(tup));
523 /* we chose none of them */
524 tp1 = get_id_type(arg1);
525 tp2 = get_id_type(arg2);
526 elog(NOTICE, "there is more than one operator %s for types", op);
527 elog(NOTICE, "%s and %s. You will have to retype this query",
528 tname(tp1), tname(tp2));
529 elog(WARN, "using an explicit cast");
535 return((Operator) tup);
539 * given opname and typeId, find all possible types for which
540 * a right/left unary operator named opname exists,
541 * such that typeId can be coerced to it
544 unary_oper_get_candidates(char *op,
546 CandidateList *candidates,
549 CandidateList current_candidate;
550 Relation pg_operator_desc;
551 HeapScanDesc pg_operator_scan;
553 OperatorTupleForm oper;
557 static ScanKeyData opKey[2] = {
558 { 0, Anum_pg_operator_oprname, NameEqualRegProcedure },
559 { 0, Anum_pg_operator_oprkind, CharacterEqualRegProcedure } };
563 fmgr_info(NameEqualRegProcedure, (func_ptr *) &opKey[0].sk_func,
565 opKey[0].sk_argument = NameGetDatum(op);
566 fmgr_info(CharacterEqualRegProcedure, (func_ptr *) &opKey[1].sk_func,
568 opKey[1].sk_argument = CharGetDatum(rightleft);
570 /* currently, only "unknown" can be coerced */
571 if (typeId != UNKNOWNOID) {
575 pg_operator_desc = heap_openr(OperatorRelationName);
576 pg_operator_scan = heap_beginscan(pg_operator_desc,
583 tup = heap_getnext(pg_operator_scan, 0, &buffer);
584 if (HeapTupleIsValid(tup)) {
585 current_candidate = (CandidateList)palloc(sizeof(struct _CandidateList));
586 current_candidate->args = (Oid *)palloc(sizeof(Oid));
588 oper = (OperatorTupleForm)GETSTRUCT(tup);
589 if (rightleft == 'r')
590 current_candidate->args[0] = oper->oprleft;
592 current_candidate->args[0] = oper->oprright;
593 current_candidate->next = *candidates;
594 *candidates = current_candidate;
596 ReleaseBuffer(buffer);
598 } while(HeapTupleIsValid(tup));
600 heap_endscan(pg_operator_scan);
601 heap_close(pg_operator_desc);
606 /* Given unary right-side operator (operator on right), return oper struct */
609 right_oper(char *op, Oid arg)
612 CandidateList candidates;
620 if (!(tup = SearchSysCacheTuple(OPRNAME,
622 ObjectIdGetDatum(arg),
623 ObjectIdGetDatum(InvalidOid),
624 Int8GetDatum('r')))) {
625 ncandidates = unary_oper_get_candidates(op, arg, &candidates, 'r');
626 if (ncandidates == 0) {
628 "Can't find right op: %s for type %d", op, arg );
631 else if (ncandidates == 1) {
632 tup = SearchSysCacheTuple(OPRNAME,
634 ObjectIdGetDatum(candidates->args[0]),
635 ObjectIdGetDatum(InvalidOid),
637 Assert(HeapTupleIsValid(tup));
640 elog(NOTICE, "there is more than one right operator %s", op);
641 elog(NOTICE, "you will have to retype this query");
642 elog(WARN, "using an explicit cast");
646 return((Operator) tup);
649 /* Given unary left-side operator (operator on left), return oper struct */
652 left_oper(char *op, Oid arg)
655 CandidateList candidates;
663 if (!(tup = SearchSysCacheTuple(OPRNAME,
665 ObjectIdGetDatum(InvalidOid),
666 ObjectIdGetDatum(arg),
667 Int8GetDatum('l')))) {
668 ncandidates = unary_oper_get_candidates(op, arg, &candidates, 'l');
669 if (ncandidates == 0) {
671 "Can't find left op: %s for type %d", op, arg );
674 else if (ncandidates == 1) {
675 tup = SearchSysCacheTuple(OPRNAME,
677 ObjectIdGetDatum(InvalidOid),
678 ObjectIdGetDatum(candidates->args[0]),
680 Assert(HeapTupleIsValid(tup));
683 elog(NOTICE, "there is more than one left operator %s", op);
684 elog(NOTICE, "you will have to retype this query");
685 elog(WARN, "using an explicit cast");
689 return((Operator) tup);
692 /* given range variable, return id of variable */
695 varattno(Relation rd, char *a)
699 for (i = 0; i < rd->rd_rel->relnatts; i++) {
700 if (!namestrcmp(&(rd->rd_att->attrs[i]->attname), a)) {
704 for (i = 0; i < SPECIALS; i++) {
705 if (!strcmp(special_attr[i].field, a)) {
706 return(special_attr[i].code);
710 elog(WARN,"Relation %s does not have attribute %s\n",
711 RelationGetRelationName(rd), a );
715 /* Given range variable, return whether attribute of this name
717 * NOTE the ASSUMPTION here that no system attributes are, or ever
721 varisset(Relation rd, char *name)
725 /* First check if this is a system attribute */
726 for (i = 0; i < SPECIALS; i++) {
727 if (! strcmp(special_attr[i].field, name)) {
728 return(false); /* no sys attr is a set */
731 return (get_attisset(rd->rd_id, name));
734 /* given range variable, return id of variable */
736 nf_varattno(Relation rd, char *a)
740 for (i = 0; i < rd->rd_rel->relnatts; i++) {
741 if (!namestrcmp(&(rd->rd_att->attrs[i]->attname), a)) {
745 for (i = 0; i < SPECIALS; i++) {
746 if (!strcmp(special_attr[i].field, a)) {
747 return(special_attr[i].code);
750 return InvalidAttrNumber;
754 * given an attribute number and a relation, return its relation name
757 getAttrName(Relation rd, int attrno)
763 for (i = 0; i < SPECIALS; i++) {
764 if (special_attr[i].code == attrno) {
765 name = special_attr[i].field;
769 elog(WARN, "Illegal attr no %d for relation %s\n",
770 attrno, RelationGetRelationName(rd));
771 } else if (attrno >=1 && attrno<= RelationGetNumberOfAttributes(rd)) {
772 name = (rd->rd_att->attrs[attrno-1]->attname).data;
775 elog(WARN, "Illegal attr no %d for relation %s\n",
776 attrno, RelationGetRelationName(rd));
780 * Shouldn't get here, but we want lint to be happy...
786 /* Given a typename and value, returns the ascii form of the value */
789 outstr(char *typename, /* Name of type of value */
790 char *value) /* Could be of any type */
795 tp = (TypeTupleForm ) GETSTRUCT(type(typename));
797 return((char *) fmgr(op, value));
800 /* Given a Type and a string, return the internal form of that string */
802 instr2(Type tp, char *string, int typlen)
804 return(instr1((TypeTupleForm ) GETSTRUCT(tp), string, typlen));
807 /* Given a type structure and a string, returns the internal form of
810 instr1(TypeTupleForm tp, char *string, int typlen)
816 typelem = tp->typelem; /* XXX - used for array_in */
817 /* typlen is for bpcharin() and varcharin() */
818 return((char *) fmgr(op, string, typelem, typlen));
821 /* Given the attribute type of an array return the arrtribute type of
822 an element of the array */
825 GetArrayElementType(Oid typearray)
827 HeapTuple type_tuple;
828 TypeTupleForm type_struct_array;
830 type_tuple = SearchSysCacheTuple(TYPOID,
831 ObjectIdGetDatum(typearray),
834 if (!HeapTupleIsValid(type_tuple))
835 elog(WARN, "GetArrayElementType: Cache lookup failed for type %d\n",
838 /* get the array type struct from the type tuple */
839 type_struct_array = (TypeTupleForm) GETSTRUCT(type_tuple);
841 if (type_struct_array->typelem == InvalidOid) {
842 elog(WARN, "GetArrayElementType: type %s is not an array",
843 (Name)&(type_struct_array->typname.data[0]));
846 return(type_struct_array->typelem);
850 funcid_get_rettype(Oid funcid)
852 HeapTuple func_tuple = NULL;
853 Oid funcrettype = (Oid)0;
855 func_tuple = SearchSysCacheTuple(PROOID, ObjectIdGetDatum(funcid),
858 if ( !HeapTupleIsValid ( func_tuple ))
859 elog (WARN, "function %d does not exist", funcid);
862 ((Form_pg_proc)GETSTRUCT(func_tuple))->prorettype ;
864 return (funcrettype);
868 * get a list of all argument type vectors for which a function named
869 * funcname taking nargs arguments exists
872 func_get_candidates(char *funcname, int nargs)
874 Relation heapRelation;
879 RetrieveIndexResult indexRes;
881 Form_pg_proc pgProcP;
882 bool bufferUsed = FALSE;
883 CandidateList candidates = NULL;
884 CandidateList current_candidate;
887 heapRelation = heap_openr(ProcedureRelationName);
888 ScanKeyEntryInitialize(&skey,
891 (RegProcedure)NameEqualRegProcedure,
894 idesc = index_openr(ProcedureNameIndex);
896 sd = index_beginscan(idesc, false, 1, &skey);
899 tuple = (HeapTuple)NULL;
901 ReleaseBuffer(buffer);
905 indexRes = index_getnext(sd, ForwardScanDirection);
909 iptr = &indexRes->heap_iptr;
910 tuple = heap_fetch(heapRelation, NowTimeQual, iptr, &buffer);
912 if (HeapTupleIsValid(tuple)) {
913 pgProcP = (Form_pg_proc)GETSTRUCT(tuple);
915 if (pgProcP->pronargs == nargs) {
916 current_candidate = (CandidateList)
917 palloc(sizeof(struct _CandidateList));
918 current_candidate->args = (Oid *)
919 palloc(8 * sizeof(Oid));
920 memset(current_candidate->args, 0, 8 * sizeof(Oid));
921 for (i=0; i<nargs; i++) {
922 current_candidate->args[i] =
923 pgProcP->proargtypes[i];
926 current_candidate->next = candidates;
927 candidates = current_candidate;
935 heap_close(heapRelation);
941 * can input_typeids be coerced to func_typeids?
944 can_coerce(int nargs, Oid *input_typeids, Oid *func_typeids)
950 * right now, we only coerce "unknown", and we cannot coerce it to a
953 for (i=0; i<nargs; i++) {
954 if (input_typeids[i] != func_typeids[i]) {
955 if (input_typeids[i] != UNKNOWNOID || func_typeids[i] == 0)
958 tp = get_id_type(input_typeids[i]);
959 if (typetypetype(tp) == 'c' )
968 * given a list of possible typeid arrays to a function and an array of
969 * input typeids, produce a shortlist of those function typeid arrays
970 * that match the input typeids (either exactly or by coercion), and
971 * return the number of such arrays
974 match_argtypes(int nargs,
976 CandidateList function_typeids,
977 CandidateList *candidates) /* return value */
979 CandidateList current_candidate;
980 CandidateList matching_candidate;
981 Oid *current_typeids;
986 for (current_candidate = function_typeids;
987 current_candidate != NULL;
988 current_candidate = current_candidate->next) {
989 current_typeids = current_candidate->args;
990 if (can_coerce(nargs, input_typeids, current_typeids)) {
991 matching_candidate = (CandidateList)
992 palloc(sizeof(struct _CandidateList));
993 matching_candidate->args = current_typeids;
994 matching_candidate->next = *candidates;
995 *candidates = matching_candidate;
1004 * given the input argtype array and more than one candidate
1005 * for the function argtype array, attempt to resolve the conflict.
1006 * returns the selected argtype array if the conflict can be resolved,
1007 * otherwise returns NULL
1010 func_select_candidate(int nargs,
1012 CandidateList candidates)
1014 /* XXX no conflict resolution implemeneted yet */
1019 bool is_lowercase(char *string)
1023 for(i = 0; i < strlen(string); i++) {
1024 if(string[i] >= 'A' && string[i] <= 'Z') {
1033 void make_lowercase(char *string)
1037 for(i = 0; i < strlen(string); i++) {
1038 if(string[i] >= 'A' && string[i] <= 'Z') {
1039 string[i] = (string[i] - 'A') + 'a';
1045 func_get_detail(char *funcname,
1048 Oid *funcid, /* return value */
1049 Oid *rettype, /* return value */
1050 bool *retset, /* return value */
1051 Oid **true_typeids) /* return value */
1053 Oid **input_typeid_vector;
1054 Oid *current_input_typeids;
1055 CandidateList function_typeids;
1056 CandidateList current_function_typeids;
1061 * attempt to find named function in the system catalogs
1062 * with arguments exactly as specified - so that the normal
1063 * case is just as quick as before
1065 ftup = SearchSysCacheTuple(PRONAME,
1066 PointerGetDatum(funcname),
1067 Int32GetDatum(nargs),
1068 PointerGetDatum(oid_array),
1070 *true_typeids = oid_array;
1073 * If an exact match isn't found :
1074 * 1) get a vector of all possible input arg type arrays constructed
1075 * from the superclasses of the original input arg types
1076 * 2) get a list of all possible argument type arrays to the
1077 * function with given name and number of arguments
1078 * 3) for each input arg type array from vector #1 :
1079 * a) find how many of the function arg type arrays from list #2
1080 * it can be coerced to
1081 * b) - if the answer is one, we have our function
1082 * - if the answer is more than one, attempt to resolve the
1084 * - if the answer is zero, try the next array from vector #1
1086 if (!HeapTupleIsValid(ftup)) {
1087 function_typeids = func_get_candidates(funcname, nargs);
1089 if (function_typeids != NULL) {
1090 int ncandidates = 0;
1092 input_typeid_vector = argtype_inherit(nargs, oid_array);
1093 current_input_typeids = oid_array;
1096 ncandidates = match_argtypes(nargs, current_input_typeids,
1098 ¤t_function_typeids);
1099 if (ncandidates == 1) {
1100 *true_typeids = current_function_typeids->args;
1101 ftup = SearchSysCacheTuple(PRONAME,
1102 PointerGetDatum(funcname),
1103 Int32GetDatum(nargs),
1104 PointerGetDatum(*true_typeids),
1106 Assert(HeapTupleIsValid(ftup));
1108 else if (ncandidates > 1) {
1110 func_select_candidate(nargs,
1111 current_input_typeids,
1112 current_function_typeids);
1113 if (*true_typeids == NULL) {
1114 elog(NOTICE, "there is more than one function named \"%s\"",
1116 elog(NOTICE, "that satisfies the given argument types. you will have to");
1117 elog(NOTICE, "retype your query using explicit typecasts.");
1118 func_error("func_get_detail", funcname, nargs, oid_array);
1121 ftup = SearchSysCacheTuple(PRONAME,
1122 PointerGetDatum(funcname),
1123 Int32GetDatum(nargs),
1124 PointerGetDatum(*true_typeids),
1126 Assert(HeapTupleIsValid(ftup));
1129 current_input_typeids = *input_typeid_vector++;
1131 while (current_input_typeids !=
1132 InvalidOid && ncandidates == 0);
1136 if (!HeapTupleIsValid(ftup)) {
1140 * everything else has failed--try converting the function
1141 * name to lowercase, and do everything one more time
1142 * (if it's not already lowercase). so ODBC applications
1143 * that expect uppercase names to work can work. --djm 8/17/96
1145 if(!is_lowercase(funcname)) {
1146 char *lowercase_funcname = strdup(funcname);
1149 make_lowercase(lowercase_funcname);
1150 result = func_get_detail(lowercase_funcname, nargs, oid_array,
1151 funcid, rettype, retset,
1154 free(lowercase_funcname);
1158 tp = get_id_type(oid_array[0]);
1159 if (typetypetype(tp) == 'c')
1160 elog(WARN, "no such attribute or function \"%s\"",
1163 func_error("func_get_detail", funcname, nargs, oid_array);
1166 pform = (Form_pg_proc) GETSTRUCT(ftup);
1167 *funcid = ftup->t_oid;
1168 *rettype = (Oid) pform->prorettype;
1169 *retset = (Oid) pform->proretset;
1173 /* shouldn't reach here */
1179 * argtype_inherit() -- Construct an argtype vector reflecting the
1180 * inheritance properties of the supplied argv.
1182 * This function is used to disambiguate among functions with the
1183 * same name but different signatures. It takes an array of eight
1184 * type ids. For each type id in the array that's a complex type
1185 * (a class), it walks up the inheritance tree, finding all
1186 * superclasses of that type. A vector of new Oid type arrays
1187 * is returned to the caller, reflecting the structure of the
1188 * inheritance tree above the supplied arguments.
1190 * The order of this vector is as follows: all superclasses of the
1191 * rightmost complex class are explored first. The exploration
1192 * continues from right to left. This policy means that we favor
1193 * keeping the leftmost argument type as low in the inheritance tree
1194 * as possible. This is intentional; it is exactly what we need to
1195 * do for method dispatch. The last type array we return is all
1196 * zeroes. This will match any functions for which return types are
1197 * not defined. There are lots of these (mostly builtins) in the
1201 argtype_inherit(int nargs, Oid *oid_array)
1205 InhPaths arginh[MAXFARGS];
1207 for (i = 0; i < MAXFARGS; i++) {
1209 arginh[i].self = oid_array[i];
1210 if ((relid = typeid_get_relid(oid_array[i])) != InvalidOid) {
1211 arginh[i].nsupers = findsupers(relid, &(arginh[i].supervec));
1213 arginh[i].nsupers = 0;
1214 arginh[i].supervec = (Oid *) NULL;
1217 arginh[i].self = InvalidOid;
1218 arginh[i].nsupers = 0;
1219 arginh[i].supervec = (Oid *) NULL;
1223 /* return an ordered cross-product of the classes involved */
1224 return (genxprod(arginh, nargs));
1227 typedef struct _SuperQE {
1232 findsupers(Oid relid, Oid **supervec)
1236 HeapScanDesc inhscan;
1239 TupleDesc inhtupdesc;
1241 SuperQE *qentry, *vnode;
1242 Dllist *visited, *queue;
1252 queue = DLNewList();
1253 visited = DLNewList();
1256 inhrel = heap_openr(InheritsRelationName);
1257 RelationSetLockForRead(inhrel);
1258 inhtupdesc = RelationGetTupleDescriptor(inhrel);
1261 * Use queue to do a breadth-first traversal of the inheritance
1262 * graph from the relid supplied up to the root.
1265 ScanKeyEntryInitialize(&skey, 0x0, Anum_pg_inherits_inhrel,
1266 ObjectIdEqualRegProcedure,
1267 ObjectIdGetDatum(relid));
1269 inhscan = heap_beginscan(inhrel, 0, NowTimeQual, 1, &skey);
1271 while (HeapTupleIsValid(inhtup = heap_getnext(inhscan, 0, &buf))) {
1272 qentry = (SuperQE *) palloc(sizeof(SuperQE));
1274 d = (Datum) fastgetattr(inhtup, Anum_pg_inherits_inhparent,
1275 inhtupdesc, &isNull);
1276 qentry->sqe_relid = DatumGetObjectId(d);
1278 /* put this one on the queue */
1279 DLAddTail(queue, DLNewElem(qentry));
1284 heap_endscan(inhscan);
1286 /* pull next unvisited relid off the queue */
1288 qe = DLRemHead(queue);
1289 qentry = qe ? (SuperQE*)DLE_VAL(qe) : NULL;
1291 if (qentry == (SuperQE *) NULL)
1294 relid = qentry->sqe_relid;
1297 for (elt = DLGetHead(visited); elt; elt = DLGetSucc(elt)) {
1298 vnode = (SuperQE*)DLE_VAL(elt);
1299 if (vnode && (qentry->sqe_relid == vnode->sqe_relid)) {
1304 } while (!newrelid);
1306 if (qentry != (SuperQE *) NULL) {
1308 /* save the type id, rather than the relation id */
1309 if ((rd = heap_open(qentry->sqe_relid)) == (Relation) NULL)
1310 elog(WARN, "relid %d does not exist", qentry->sqe_relid);
1311 qentry->sqe_relid = typeid(type(RelationGetRelationName(rd)->data));
1314 DLAddTail(visited, qe);
1318 } while (qentry != (SuperQE *) NULL);
1320 RelationUnsetLockForRead(inhrel);
1324 relidvec = (Oid *) palloc(nvisited * sizeof(Oid));
1325 *supervec = relidvec;
1327 for (elt = DLGetHead(visited); elt; elt = DLGetSucc(elt)) {
1328 vnode = (SuperQE*)DLE_VAL(elt);
1329 *relidvec++ = vnode->sqe_relid;
1333 *supervec = (Oid *) NULL;
1340 genxprod(InhPaths *arginh, int nargs)
1343 Oid **result, **iter;
1349 for (i = 0; i < nargs; i++) {
1350 nanswers *= (arginh[i].nsupers + 2);
1354 iter = result = (Oid **) palloc(sizeof(Oid *) * nanswers);
1356 /* compute the cross product from right to left */
1358 oneres = (Oid *) palloc(MAXFARGS * sizeof(Oid));
1359 memset(oneres, 0, MAXFARGS * sizeof(Oid));
1361 for (i = nargs - 1; i >= 0 && cur[i] > arginh[i].nsupers; i--)
1364 /* if we're done, terminate with NULL pointer */
1370 /* no, increment this column and zero the ones after it */
1371 cur[i] = cur[i] + 1;
1372 for (j = nargs - 1; j > i; j--)
1375 for (i = 0; i < nargs; i++) {
1377 oneres[i] = arginh[i].self;
1378 else if (cur[i] > arginh[i].nsupers)
1379 oneres[i] = 0; /* wild card */
1381 oneres[i] = arginh[i].supervec[cur[i] - 1];
1388 /* Given a type id, returns the in-conversion function of the type */
1390 typeid_get_retinfunc(Oid type_id)
1392 HeapTuple typeTuple;
1395 typeTuple = SearchSysCacheTuple(TYPOID,
1396 ObjectIdGetDatum(type_id),
1398 if ( !HeapTupleIsValid ( typeTuple ))
1400 "typeid_get_retinfunc: Invalid type - oid = %ud",
1403 type = (TypeTupleForm) GETSTRUCT(typeTuple);
1404 infunc = type->typinput;
1409 typeid_get_relid(Oid type_id)
1411 HeapTuple typeTuple;
1414 typeTuple = SearchSysCacheTuple(TYPOID,
1415 ObjectIdGetDatum(type_id),
1417 if ( !HeapTupleIsValid ( typeTuple ))
1418 elog(WARN, "typeid_get_relid: Invalid type - oid = %ud ", type_id);
1420 type = (TypeTupleForm) GETSTRUCT(typeTuple);
1421 infunc = type->typrelid;
1426 get_typrelid(Type typ)
1428 TypeTupleForm typtup;
1430 typtup = (TypeTupleForm) GETSTRUCT(typ);
1432 return (typtup->typrelid);
1436 get_typelem(Oid type_id)
1438 HeapTuple typeTuple;
1441 if (!(typeTuple = SearchSysCacheTuple(TYPOID,
1442 ObjectIdGetDatum(type_id),
1444 elog (WARN , "type id lookup of %ud failed", type_id);
1446 type = (TypeTupleForm) GETSTRUCT(typeTuple);
1448 return (type->typelem);
1452 FindDelimiter(char *typename)
1455 HeapTuple typeTuple;
1459 if (!(typeTuple = SearchSysCacheTuple(TYPNAME,
1460 PointerGetDatum(typename),
1462 elog (WARN , "type name lookup of %s failed", typename);
1464 type = (TypeTupleForm) GETSTRUCT(typeTuple);
1466 delim = type->typdelim;
1471 * Give a somewhat useful error message when the operator for two types
1475 op_error(char *op, Oid arg1, Oid arg2)
1477 Type tp1 = NULL, tp2 = NULL;
1479 if (check_typeid(arg1)) {
1480 tp1 = get_id_type(arg1);
1482 elog(WARN, "left hand side of operator %s has an unknown type, probably a bad attribute name", op);
1485 if (check_typeid(arg2)) {
1486 tp2 = get_id_type(arg2);
1488 elog(WARN, "right hand side of operator %s has an unknown type, probably a bad attribute name", op);
1491 elog(NOTICE, "there is no operator %s for types %s and %s",
1492 op, tname(tp1),tname(tp2));
1493 elog(NOTICE, "You will either have to retype this query using an");
1494 elog(NOTICE, "explicit cast, or you will have to define the operator");
1495 elog(WARN, "%s for %s and %s using CREATE OPERATOR",
1496 op, tname(tp1),tname(tp2));
1500 * Error message when function lookup fails that gives details of the
1504 func_error(char *caller, char *funcname, int nargs, Oid *argtypes)
1507 char p[(NAMEDATALEN+2)*MAXFMGRARGS], *ptr;
1512 for (i=0; i<nargs; i++) {
1517 if (argtypes[i] != 0) {
1518 (void) strcpy(ptr, tname(get_id_type(argtypes[i])));
1519 *(ptr + NAMEDATALEN) = '\0';
1521 strcpy(ptr, "opaque");
1525 elog(WARN, "%s: function %s(%s) does not exist", caller, funcname, p);