]> granicus.if.org Git - postgresql/blob - src/backend/parser/catalog_utils.c
This patch changes quite a few instances of references of Oid's
[postgresql] / src / backend / parser / catalog_utils.c
1 /*-------------------------------------------------------------------------
2  *
3  * catalog_utils.c--
4  *
5  * Copyright (c) 1994, Regents of the University of California
6  *
7  *
8  * IDENTIFICATION
9  *    $Header: /cvsroot/pgsql/src/backend/parser/Attic/catalog_utils.c,v 1.12 1996/11/30 18:06:31 momjian Exp $
10  *
11  *-------------------------------------------------------------------------
12  */
13 #include <string.h>
14 #include "postgres.h"
15
16 #include "lib/dllist.h"
17 #include "utils/datum.h"
18
19 #include "utils/builtins.h"
20 #include "utils/elog.h"
21 #include "utils/palloc.h"
22 #include "fmgr.h"
23
24 #include "nodes/pg_list.h"
25 #include "nodes/parsenodes.h"
26 #include "utils/syscache.h"
27 #include "catalog/catname.h"
28
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"
36
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"
45
46 #include "storage/buf.h"
47 #include "storage/bufmgr.h"
48 #include "utils/lsyscache.h"
49 #include "storage/lmgr.h"
50
51 #include "port-protos.h"              /* strdup() */
52
53 struct {
54     char *field;
55     int code;
56 } special_attr[] = {
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 }
68 };
69
70 #define SPECIALS (sizeof(special_attr)/sizeof(*special_attr))
71   
72 static char *attnum_type[SPECIALS] = {
73     "tid",
74     "oid",
75     "xid",
76     "cid",
77     "xid",
78     "cid",
79     "tid",
80     "tid",
81     "abstime",
82     "abstime",
83     "char"
84   };
85
86 #define MAXFARGS 8              /* max # args to a c or postquel function */
87
88 /*
89  *  This structure is used to explore the inheritance hierarchy above
90  *  nodes in the type tree in order to disambiguate among polymorphic
91  *  functions.
92  */
93
94 typedef struct _InhPaths {
95     int         nsupers;        /* number of superclasses */
96     Oid self;           /* this class */
97     Oid *supervec;      /* vector of superclasses */
98 } InhPaths;
99
100 /*
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.
103  */
104 typedef struct _CandidateList {
105     Oid *args;
106     struct _CandidateList *next;
107 } *CandidateList;
108
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);
112
113 static bool is_lowercase(char *string);
114 static void make_lowercase(char *string);
115
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
121  */
122 bool
123 check_typeid(long id)
124 {
125     return (SearchSysCacheTuple(TYPOID, 
126                                 ObjectIdGetDatum(id),
127                                 0,0,0) != NULL);
128 }
129
130
131 /* return a Type structure, given an typid */
132 Type
133 get_id_type(long id)
134 {
135     HeapTuple tup;
136     
137     if (!(tup = SearchSysCacheTuple(TYPOID, ObjectIdGetDatum(id),
138                                     0,0,0))) { 
139         elog ( WARN, "type id lookup of %d failed", id);
140         return(NULL);
141     }
142     return((Type) tup);
143 }
144
145 /* return a type name, given a typeid */
146 char*
147 get_id_typname(long id)
148 {
149     HeapTuple tup;
150     TypeTupleForm typetuple;
151     
152     if (!(tup = SearchSysCacheTuple(TYPOID, ObjectIdGetDatum(id),
153                                     0,0,0))) {
154         elog ( WARN, "type id lookup of %d failed", id);
155         return(NULL);
156     }
157     typetuple = (TypeTupleForm)GETSTRUCT(tup);
158     return (typetuple->typname).data;
159 }
160
161 /* return a Type structure, given type name */
162 Type
163 type(char *s)
164 {
165     HeapTuple tup;
166     
167     if (s == NULL) {
168         elog ( WARN , "type(): Null type" );
169     }
170     
171     if (!(tup = SearchSysCacheTuple(TYPNAME, PointerGetDatum(s), 0,0,0))) {
172         elog (WARN , "type name lookup of %s failed", s);
173     }
174     return((Type) tup);
175 }
176
177 /* given attribute id, return type of that attribute */
178 /* XXX Special case for pseudo-attributes is a hack */
179 Oid
180 att_typeid(Relation rd, int attid)
181 {
182     
183     if (attid < 0) {
184         return(typeid(type(attnum_type[-attid-1])));
185     }
186     /* -1 because varattno (where attid comes from) returns one
187        more than index */
188     return(rd->rd_att->attrs[attid-1]->atttypid);
189 }
190
191
192 int
193 att_attnelems(Relation rd, int attid)
194 {
195     return(rd->rd_att->attrs[attid-1]->attnelems);
196 }
197
198 /* given type, return the type OID */
199 Oid
200 typeid(Type tp)
201 {
202     if (tp == NULL) {
203         elog ( WARN , "typeid() called with NULL type struct");
204     }
205     return(tp->t_oid);
206 }
207
208 /* given type (as type struct), return the length of type */
209 int16
210 tlen(Type t)
211 {
212     TypeTupleForm    typ;
213     
214     typ = (TypeTupleForm)GETSTRUCT(t);
215     return(typ->typlen);
216 }
217
218 /* given type (as type struct), return the value of its 'byval' attribute.*/
219 bool
220 tbyval(Type t)
221 {
222     TypeTupleForm    typ;
223     
224     typ = (TypeTupleForm)GETSTRUCT(t);
225     return(typ->typbyval);
226 }
227
228 /* given type (as type struct), return the name of type */
229 char*
230 tname(Type t)
231 {
232     TypeTupleForm    typ;
233     
234     typ = (TypeTupleForm)GETSTRUCT(t);
235     return (typ->typname).data;
236 }
237
238 /* given type (as type struct), return wether type is passed by value */
239 int
240 tbyvalue(Type t)
241 {
242     TypeTupleForm typ;
243     
244     typ = (TypeTupleForm) GETSTRUCT(t);
245     return(typ->typbyval);
246 }
247
248 /* given a type, return its typetype ('c' for 'c'atalog types) */
249 static char
250 typetypetype(Type t)
251 {
252     TypeTupleForm typ;
253     
254     typ = (TypeTupleForm) GETSTRUCT(t);
255     return(typ->typtype);
256 }
257
258 /* given operator, return the operator OID */
259 Oid
260 oprid(Operator op)
261 {
262     return(op->t_oid);
263 }
264
265 /*
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
270  */
271 static int
272 binary_oper_get_candidates(char *opname,
273                            Oid leftTypeId,
274                            Oid rightTypeId,
275                            CandidateList *candidates)
276 {
277     CandidateList       current_candidate;
278     Relation            pg_operator_desc;
279     HeapScanDesc        pg_operator_scan;
280     HeapTuple           tup;
281     OperatorTupleForm   oper;
282     Buffer              buffer;
283     int                 nkeys;
284     int                 ncandidates = 0;
285     ScanKeyData         opKey[3];
286     
287     *candidates = NULL;
288
289     ScanKeyEntryInitialize(&opKey[0], 0,
290                            Anum_pg_operator_oprname,
291                            NameEqualRegProcedure,
292                            NameGetDatum(opname));
293
294     ScanKeyEntryInitialize(&opKey[1], 0,
295                            Anum_pg_operator_oprkind,
296                            CharacterEqualRegProcedure,
297                            CharGetDatum('b'));
298
299     
300     if (leftTypeId == UNKNOWNOID) {
301         if (rightTypeId == UNKNOWNOID) {
302             nkeys = 2;
303         } else {
304             nkeys = 3;
305
306             ScanKeyEntryInitialize(&opKey[2], 0,
307                                    Anum_pg_operator_oprright,
308                                    ObjectIdEqualRegProcedure,
309                                    ObjectIdGetDatum(rightTypeId));
310         }
311     } else if (rightTypeId == UNKNOWNOID) {
312         nkeys = 3;
313         
314         ScanKeyEntryInitialize(&opKey[2], 0,
315                                Anum_pg_operator_oprleft,
316                                ObjectIdEqualRegProcedure,
317                                ObjectIdGetDatum(leftTypeId));
318     } else {
319         /* currently only "unknown" can be coerced */
320         return 0;
321     }
322     
323     pg_operator_desc = heap_openr(OperatorRelationName);
324     pg_operator_scan = heap_beginscan(pg_operator_desc,
325                                       0,
326                                       SelfTimeQual,
327                                       nkeys,
328                                       opKey);
329     
330     do {
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));
335             
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;
341             ncandidates++;
342             ReleaseBuffer(buffer);
343         }
344     } while(HeapTupleIsValid(tup));
345     
346     heap_endscan(pg_operator_scan);
347     heap_close(pg_operator_desc);
348     
349     return ncandidates;
350 }
351
352 /*
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).
360  */
361 static bool
362 equivalentOpersAfterPromotion(CandidateList candidates)
363 {
364     CandidateList result;
365     CandidateList promotedCandidates = NULL;
366     Oid leftarg, rightarg;
367
368     for (result = candidates; result != NULL; result = result->next) {
369         CandidateList c;
370         c = (CandidateList)palloc(sizeof(*c));
371         c->args = (Oid *)palloc(2 * sizeof(Oid));
372         switch (result->args[0]) {
373         case FLOAT4OID:
374         case INT4OID:
375         case INT2OID:
376             c->args[0] = FLOAT8OID;
377             break;
378         default:
379             c->args[0] = result->args[0];
380             break;
381         }
382         switch (result->args[1]) {
383         case FLOAT4OID:
384         case INT4OID:
385         case INT2OID:
386             c->args[1] = FLOAT8OID;
387             break;
388         default:
389             c->args[1] = result->args[1];
390             break;
391         }
392         c->next = promotedCandidates;
393         promotedCandidates = c;
394     }
395
396     /* if we get called, we have more than 1 candidates so we can do the
397        following safely */
398     leftarg = promotedCandidates->args[0];
399     rightarg = promotedCandidates->args[1];
400
401     for (result=promotedCandidates->next; result!=NULL; result=result->next) {
402         if (result->args[0]!=leftarg || result->args[1]!=rightarg)
403             /*
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.
407              */
408             return FALSE;
409     }
410
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. */
413     return TRUE;
414 }
415         
416
417 /*
418  *  given a choice of argument type pairs for a binary operator,
419  *  try to choose a default pair
420  */
421 static CandidateList
422 binary_oper_select_candidate(Oid arg1,
423                              Oid arg2,
424                              CandidateList candidates)
425 {
426     CandidateList result;
427
428     /*
429      * if both are "unknown", there is no way to select a candidate
430      *
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)
434      *
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]
438      */
439     
440     if (arg1 == UNKNOWNOID && arg2 == UNKNOWNOID)
441         return (NULL);
442
443     /*
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.
447      *
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.)
458      *                                                  - ay 6/95
459      */
460     if (!equivalentOpersAfterPromotion(candidates))
461         return NULL;
462
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])
467             return result;
468     }
469
470     return (NULL);
471 }
472
473 /* Given operator, types of arg1, and arg2, return oper struct */
474 /* arg1, arg2 --typeids */
475 Operator
476 oper(char *op, Oid arg1, Oid arg2)
477 {
478     HeapTuple tup;
479     CandidateList candidates;
480     int ncandidates;
481
482     if (!arg2) arg2=arg1;
483     if (!arg1) arg1=arg2;
484
485     if (!(tup = SearchSysCacheTuple(OPRNAME,
486                                     PointerGetDatum(op),
487                                     ObjectIdGetDatum(arg1),
488                                     ObjectIdGetDatum(arg2),
489                                     Int8GetDatum('b')))) {
490         ncandidates = binary_oper_get_candidates(op, arg1, arg2, &candidates);
491         if (ncandidates == 0) {
492             /*
493              * no operators of the desired types found
494              */
495             op_error(op, arg1, arg2);
496             return(NULL);
497         } else if (ncandidates == 1) {
498             /*
499              * exactly one operator of the desired types found
500              */
501             tup = SearchSysCacheTuple(OPRNAME,
502                                       PointerGetDatum(op),
503                                       ObjectIdGetDatum(candidates->args[0]),
504                                       ObjectIdGetDatum(candidates->args[1]),
505                                       Int8GetDatum('b'));
506             Assert(HeapTupleIsValid(tup));
507         } else {
508             /*
509              * multiple operators of the desired types found
510              */
511             candidates = binary_oper_select_candidate(arg1, arg2, candidates);
512             if (candidates != NULL) {
513                 /* we chose one of them */
514                 tup = SearchSysCacheTuple(OPRNAME,
515                                           PointerGetDatum(op),
516                                           ObjectIdGetDatum(candidates->args[0]),
517                                           ObjectIdGetDatum(candidates->args[1]),
518                                           Int8GetDatum('b'));
519                 Assert(HeapTupleIsValid(tup));
520             } else {
521                 Type tp1, tp2;
522                 
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");
530                 
531                 return(NULL);
532             }
533         }
534     }
535     return((Operator) tup);
536 }
537
538 /*
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
542  */
543 static int
544 unary_oper_get_candidates(char *op,
545                           Oid typeId,
546                           CandidateList *candidates,
547                           char rightleft)
548 {
549     CandidateList       current_candidate;
550     Relation            pg_operator_desc;
551     HeapScanDesc        pg_operator_scan;
552     HeapTuple           tup;
553     OperatorTupleForm   oper;
554     Buffer              buffer;
555     int                 ncandidates = 0;
556     
557     static ScanKeyData opKey[2] = {
558         { 0, Anum_pg_operator_oprname, NameEqualRegProcedure },
559         { 0, Anum_pg_operator_oprkind, CharacterEqualRegProcedure } };
560     
561     *candidates = NULL;
562     
563     fmgr_info(NameEqualRegProcedure, (func_ptr *) &opKey[0].sk_func,
564               &opKey[0].sk_nargs);
565     opKey[0].sk_argument = NameGetDatum(op);
566     fmgr_info(CharacterEqualRegProcedure, (func_ptr *) &opKey[1].sk_func,
567               &opKey[1].sk_nargs);
568     opKey[1].sk_argument = CharGetDatum(rightleft);
569     
570     /* currently, only "unknown" can be coerced */
571     if (typeId != UNKNOWNOID) {
572         return 0;
573     }
574     
575     pg_operator_desc = heap_openr(OperatorRelationName);
576     pg_operator_scan = heap_beginscan(pg_operator_desc,
577                                       0,
578                                       SelfTimeQual,
579                                       2,
580                                       opKey);
581     
582     do {
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));
587             
588             oper = (OperatorTupleForm)GETSTRUCT(tup);
589             if (rightleft == 'r')
590                 current_candidate->args[0] = oper->oprleft;
591             else
592                 current_candidate->args[0] = oper->oprright;
593             current_candidate->next = *candidates;
594             *candidates = current_candidate;
595             ncandidates++;
596             ReleaseBuffer(buffer);
597         }
598     } while(HeapTupleIsValid(tup));
599     
600     heap_endscan(pg_operator_scan);
601     heap_close(pg_operator_desc);
602     
603     return ncandidates;
604 }
605
606 /* Given unary right-side operator (operator on right), return oper struct */
607 /* arg-- type id */
608 Operator
609 right_oper(char *op, Oid arg)
610 {
611     HeapTuple tup;
612     CandidateList candidates;
613     int ncandidates;
614     
615     /*
616       if (!OpCache) {
617       init_op_cache();
618       }
619       */
620     if (!(tup = SearchSysCacheTuple(OPRNAME,
621                                     PointerGetDatum(op),
622                                     ObjectIdGetDatum(arg),
623                                     ObjectIdGetDatum(InvalidOid),
624                                     Int8GetDatum('r')))) {
625         ncandidates = unary_oper_get_candidates(op, arg, &candidates, 'r');
626         if (ncandidates == 0) {
627             elog ( WARN ,
628                   "Can't find right op: %s for type %d", op, arg );
629             return(NULL);
630         }
631         else if (ncandidates == 1) {
632             tup = SearchSysCacheTuple(OPRNAME,
633                                       PointerGetDatum(op),
634                                       ObjectIdGetDatum(candidates->args[0]),
635                                       ObjectIdGetDatum(InvalidOid),
636                                       Int8GetDatum('r'));
637             Assert(HeapTupleIsValid(tup));
638         }
639         else {
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");
643             return(NULL);
644         }
645     }
646     return((Operator) tup);
647 }
648
649 /* Given unary left-side operator (operator on left), return oper struct */
650 /* arg--type id */
651 Operator
652 left_oper(char *op, Oid arg)
653 {
654     HeapTuple tup;
655     CandidateList candidates;
656     int ncandidates;
657     
658     /*
659       if (!OpCache) {
660       init_op_cache();
661       }
662       */
663     if (!(tup = SearchSysCacheTuple(OPRNAME,
664                                     PointerGetDatum(op),
665                                     ObjectIdGetDatum(InvalidOid),
666                                     ObjectIdGetDatum(arg),
667                                     Int8GetDatum('l')))) {
668         ncandidates = unary_oper_get_candidates(op, arg, &candidates, 'l');
669         if (ncandidates == 0) {
670             elog ( WARN ,
671                   "Can't find left op: %s for type %d", op, arg );
672             return(NULL);
673         }
674         else if (ncandidates == 1) {
675             tup = SearchSysCacheTuple(OPRNAME,
676                                       PointerGetDatum(op),
677                                       ObjectIdGetDatum(InvalidOid),
678                                       ObjectIdGetDatum(candidates->args[0]),
679                                       Int8GetDatum('l'));
680             Assert(HeapTupleIsValid(tup));
681         }
682         else {
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");
686             return(NULL);
687         }
688     }
689     return((Operator) tup);
690 }
691
692 /* given range variable, return id of variable */
693
694 int
695 varattno(Relation rd, char *a)
696 {
697     int i;
698     
699     for (i = 0; i < rd->rd_rel->relnatts; i++) {
700         if (!namestrcmp(&(rd->rd_att->attrs[i]->attname), a)) {
701             return(i+1);
702         }
703     }
704     for (i = 0; i < SPECIALS; i++) {
705         if (!strcmp(special_attr[i].field, a)) {
706             return(special_attr[i].code);
707         }
708     }
709     
710     elog(WARN,"Relation %s does not have attribute %s\n", 
711          RelationGetRelationName(rd), a );
712     return(-1);
713 }
714
715 /* Given range variable, return whether attribute of this name
716  * is a set.
717  * NOTE the ASSUMPTION here that no system attributes are, or ever
718  * will be, sets.
719  */
720 bool
721 varisset(Relation rd, char *name)
722 {
723     int i;
724     
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 */
729         }
730     }
731     return (get_attisset(rd->rd_id, name));
732 }
733
734 /* given range variable, return id of variable */
735 int
736 nf_varattno(Relation rd, char *a)
737 {
738     int i;
739     
740     for (i = 0; i < rd->rd_rel->relnatts; i++) {
741         if (!namestrcmp(&(rd->rd_att->attrs[i]->attname), a)) {
742             return(i+1);
743         }
744     }
745     for (i = 0; i < SPECIALS; i++) {
746         if (!strcmp(special_attr[i].field, a)) {
747             return(special_attr[i].code);
748         }
749     }
750     return InvalidAttrNumber;
751 }
752
753 /*-------------
754  * given an attribute number and a relation, return its relation name
755  */
756 char*
757 getAttrName(Relation rd, int attrno)
758 {
759     char *name;
760     int i;
761     
762     if (attrno<0) {
763         for (i = 0; i < SPECIALS; i++) {
764             if (special_attr[i].code == attrno) {
765                 name = special_attr[i].field;
766                 return(name);
767             }
768         }
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;
773         return(name);
774     } else {
775         elog(WARN, "Illegal attr no %d for relation %s\n",
776              attrno, RelationGetRelationName(rd));
777     }
778     
779     /*
780      * Shouldn't get here, but we want lint to be happy...
781      */
782     
783     return(NULL);
784 }
785
786 /* Given a typename and value, returns the ascii form of the value */
787
788 char *
789 outstr(char *typename,  /* Name of type of value */
790        char *value)     /* Could be of any type */
791 {
792     TypeTupleForm tp;
793     Oid op;
794     
795     tp = (TypeTupleForm ) GETSTRUCT(type(typename));
796     op = tp->typoutput;
797     return((char *) fmgr(op, value));
798 }
799
800 /* Given a Type and a string, return the internal form of that string */
801 char *
802 instr2(Type tp, char *string, int typlen)
803 {
804     return(instr1((TypeTupleForm ) GETSTRUCT(tp), string, typlen));
805 }
806
807 /* Given a type structure and a string, returns the internal form of
808    that string */
809 char *
810 instr1(TypeTupleForm tp, char *string, int typlen)
811 {
812     Oid op;
813     Oid typelem;
814     
815     op = tp->typinput;
816     typelem = tp->typelem; /* XXX - used for array_in */
817     /* typlen is for bpcharin() and varcharin() */
818     return((char *) fmgr(op, string, typelem, typlen));
819 }
820
821 /* Given the attribute type of an array return the arrtribute type of
822    an element of the array */
823
824 Oid
825 GetArrayElementType(Oid typearray)
826 {
827     HeapTuple type_tuple;
828     TypeTupleForm type_struct_array;
829     
830     type_tuple = SearchSysCacheTuple(TYPOID,
831                                      ObjectIdGetDatum(typearray),
832                                      0,0,0);
833     
834     if (!HeapTupleIsValid(type_tuple))
835         elog(WARN, "GetArrayElementType: Cache lookup failed for type %d\n",
836              typearray);
837     
838     /* get the array type struct from the type tuple */
839     type_struct_array = (TypeTupleForm) GETSTRUCT(type_tuple);
840     
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]));
844     }
845     
846     return(type_struct_array->typelem);
847 }
848
849 Oid
850 funcid_get_rettype(Oid funcid)
851 {
852     HeapTuple func_tuple = NULL;
853     Oid funcrettype = (Oid)0;
854     
855     func_tuple = SearchSysCacheTuple(PROOID, ObjectIdGetDatum(funcid),
856                                      0,0,0);
857     
858     if ( !HeapTupleIsValid ( func_tuple )) 
859         elog (WARN, "function  %d does not exist", funcid);
860     
861     funcrettype = (Oid)
862         ((Form_pg_proc)GETSTRUCT(func_tuple))->prorettype ;
863     
864     return (funcrettype);
865 }
866
867 /*
868  * get a list of all argument type vectors for which a function named
869  * funcname taking nargs arguments exists
870  */
871 static CandidateList
872 func_get_candidates(char *funcname, int nargs)
873 {
874     Relation heapRelation;
875     Relation idesc;
876     ScanKeyData skey;
877     HeapTuple tuple;
878     IndexScanDesc sd;
879     RetrieveIndexResult indexRes;
880     Buffer buffer;
881     Form_pg_proc pgProcP;
882     bool bufferUsed = FALSE;
883     CandidateList candidates = NULL;
884     CandidateList current_candidate;
885     int i;
886     
887     heapRelation = heap_openr(ProcedureRelationName);
888     ScanKeyEntryInitialize(&skey,
889                            (bits16)0x0,
890                            (AttrNumber)1,
891                            (RegProcedure)NameEqualRegProcedure,
892                            (Datum)funcname);
893     
894     idesc = index_openr(ProcedureNameIndex);
895     
896     sd = index_beginscan(idesc, false, 1, &skey);
897     
898     do {  
899         tuple = (HeapTuple)NULL;
900         if (bufferUsed) {
901             ReleaseBuffer(buffer);
902             bufferUsed = FALSE;
903         }
904         
905         indexRes = index_getnext(sd, ForwardScanDirection);
906         if (indexRes) {
907             ItemPointer iptr;
908             
909             iptr = &indexRes->heap_iptr;
910             tuple = heap_fetch(heapRelation, NowTimeQual, iptr, &buffer);
911             pfree(indexRes);
912             if (HeapTupleIsValid(tuple)) {
913                 pgProcP = (Form_pg_proc)GETSTRUCT(tuple);
914                 bufferUsed = TRUE;
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];
924                     }
925                     
926                     current_candidate->next = candidates;
927                     candidates = current_candidate;
928                 }
929             }
930         }
931     } while (indexRes);
932     
933     index_endscan(sd);
934     index_close(idesc);
935     heap_close(heapRelation);            
936     
937     return candidates;
938 }
939
940 /*
941  * can input_typeids be coerced to func_typeids?
942  */
943 static bool
944 can_coerce(int nargs, Oid *input_typeids, Oid *func_typeids)
945 {
946     int i;
947     Type tp;
948     
949     /*
950      * right now, we only coerce "unknown", and we cannot coerce it to a
951      * relation type
952      */
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)
956                 return false;
957             
958             tp = get_id_type(input_typeids[i]);
959             if (typetypetype(tp) == 'c' )
960                 return false;
961         }
962     }
963     
964     return true;
965 }
966
967 /*
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
972  */
973 static int
974 match_argtypes(int nargs,
975                Oid *input_typeids,
976                CandidateList function_typeids,
977                CandidateList *candidates) /* return value */
978 {
979     CandidateList current_candidate;
980     CandidateList matching_candidate;
981     Oid *current_typeids;
982     int ncandidates = 0;
983     
984     *candidates = NULL;
985     
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;
996             ncandidates++;
997         }
998     }
999     
1000     return ncandidates;
1001 }
1002
1003 /*
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
1008  */
1009 static Oid *
1010 func_select_candidate(int nargs,
1011                       Oid *input_typeids,
1012                       CandidateList candidates)
1013 {
1014     /* XXX no conflict resolution implemeneted yet */
1015     return (NULL);
1016 }
1017
1018 static
1019 bool is_lowercase(char *string)
1020 {
1021     int i;
1022
1023     for(i = 0; i < strlen(string); i++) {
1024         if(string[i] >= 'A' && string[i] <= 'Z') {
1025             return false;
1026         }
1027     }
1028
1029     return true;
1030 }
1031
1032 static
1033 void make_lowercase(char *string)
1034 {
1035     int i;
1036
1037     for(i = 0; i < strlen(string); i++) {
1038         if(string[i] >= 'A' && string[i] <= 'Z') {
1039             string[i] = (string[i] - 'A') + 'a';
1040         }
1041     }
1042 }
1043
1044 bool
1045 func_get_detail(char *funcname,
1046                 int nargs,
1047                 Oid *oid_array,
1048                 Oid *funcid,    /* return value */
1049                 Oid *rettype,   /* return value */
1050                 bool *retset,   /* return value */
1051                 Oid **true_typeids) /* return value */
1052 {
1053     Oid **input_typeid_vector;
1054     Oid *current_input_typeids;
1055     CandidateList function_typeids;
1056     CandidateList current_function_typeids;
1057     HeapTuple ftup;
1058     Form_pg_proc pform;
1059     
1060     /*
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
1064      */
1065     ftup = SearchSysCacheTuple(PRONAME, 
1066                                PointerGetDatum(funcname),
1067                                Int32GetDatum(nargs),
1068                                PointerGetDatum(oid_array),
1069                                0);
1070     *true_typeids = oid_array;
1071     
1072     /*
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
1083      *         conflict
1084      *       - if the answer is zero, try the next array from vector #1
1085      */
1086     if (!HeapTupleIsValid(ftup)) {
1087         function_typeids = func_get_candidates(funcname, nargs);
1088         
1089         if (function_typeids != NULL) {
1090             int ncandidates = 0;
1091             
1092             input_typeid_vector = argtype_inherit(nargs, oid_array);
1093             current_input_typeids = oid_array;
1094             
1095             do {
1096                 ncandidates = match_argtypes(nargs, current_input_typeids,
1097                                              function_typeids,
1098                                              &current_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),
1105                                                0);
1106                     Assert(HeapTupleIsValid(ftup));
1107                 }
1108                 else if (ncandidates > 1) {
1109                     *true_typeids =
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\"",
1115                              funcname);
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);
1119                     }
1120                     else {
1121                         ftup = SearchSysCacheTuple(PRONAME, 
1122                                                    PointerGetDatum(funcname),
1123                                                    Int32GetDatum(nargs),
1124                                                    PointerGetDatum(*true_typeids),
1125                                                    0);
1126                         Assert(HeapTupleIsValid(ftup));
1127                     }
1128                 }
1129                 current_input_typeids = *input_typeid_vector++;
1130             } 
1131             while (current_input_typeids !=
1132                    InvalidOid && ncandidates == 0);
1133         }
1134     }
1135     
1136     if (!HeapTupleIsValid(ftup)) {
1137         Type tp;
1138
1139         /*
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
1144          */
1145         if(!is_lowercase(funcname)) {
1146             char *lowercase_funcname = strdup(funcname);
1147             bool result;
1148
1149             make_lowercase(lowercase_funcname);
1150             result = func_get_detail(lowercase_funcname, nargs, oid_array,
1151                                      funcid, rettype, retset,   
1152                                      true_typeids);
1153             
1154             free(lowercase_funcname);
1155             return result;
1156         } else {
1157         if (nargs == 1) {
1158             tp = get_id_type(oid_array[0]);
1159             if (typetypetype(tp) == 'c')
1160                 elog(WARN, "no such attribute or function \"%s\"",
1161                      funcname);
1162         }
1163         func_error("func_get_detail", funcname, nargs, oid_array);
1164         }
1165     } else {
1166         pform = (Form_pg_proc) GETSTRUCT(ftup);
1167         *funcid = ftup->t_oid;
1168         *rettype = (Oid) pform->prorettype;
1169         *retset = (Oid) pform->proretset;
1170         
1171         return (true);
1172     }
1173 /* shouldn't reach here */
1174  return (false);
1175
1176 }
1177
1178 /*
1179  *  argtype_inherit() -- Construct an argtype vector reflecting the
1180  *                       inheritance properties of the supplied argv.
1181  *
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.
1189  *
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
1198  *      catalogs.
1199  */
1200 static Oid **
1201 argtype_inherit(int nargs, Oid *oid_array)
1202 {
1203     Oid relid;
1204     int i;
1205     InhPaths arginh[MAXFARGS];
1206     
1207     for (i = 0; i < MAXFARGS; i++) {
1208         if (i < nargs) {
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));
1212             } else {
1213                 arginh[i].nsupers = 0;
1214                 arginh[i].supervec = (Oid *) NULL;
1215             }
1216         } else {
1217             arginh[i].self = InvalidOid;
1218             arginh[i].nsupers = 0;
1219             arginh[i].supervec = (Oid *) NULL;
1220         }
1221     }
1222     
1223     /* return an ordered cross-product of the classes involved */
1224     return (genxprod(arginh, nargs));
1225 }
1226
1227 typedef struct _SuperQE {
1228     Oid sqe_relid;
1229 } SuperQE;
1230
1231 static int
1232 findsupers(Oid relid, Oid **supervec)
1233 {
1234     Oid *relidvec;
1235     Relation inhrel;
1236     HeapScanDesc inhscan;
1237     ScanKeyData skey;
1238     HeapTuple inhtup;
1239     TupleDesc inhtupdesc;
1240     int nvisited;
1241     SuperQE *qentry, *vnode;
1242     Dllist *visited, *queue;
1243     Dlelem *qe, *elt;
1244
1245     Relation rd;
1246     Buffer buf;
1247     Datum d;
1248     bool newrelid;
1249     char isNull;
1250     
1251     nvisited = 0;
1252     queue = DLNewList();
1253     visited = DLNewList();
1254
1255
1256     inhrel = heap_openr(InheritsRelationName);
1257     RelationSetLockForRead(inhrel);
1258     inhtupdesc = RelationGetTupleDescriptor(inhrel);
1259     
1260     /*
1261      *  Use queue to do a breadth-first traversal of the inheritance
1262      *  graph from the relid supplied up to the root.
1263      */
1264     do {
1265         ScanKeyEntryInitialize(&skey, 0x0, Anum_pg_inherits_inhrel,
1266                                ObjectIdEqualRegProcedure,
1267                                ObjectIdGetDatum(relid));
1268         
1269         inhscan = heap_beginscan(inhrel, 0, NowTimeQual, 1, &skey);
1270         
1271         while (HeapTupleIsValid(inhtup = heap_getnext(inhscan, 0, &buf))) {
1272             qentry = (SuperQE *) palloc(sizeof(SuperQE));
1273             
1274             d = (Datum) fastgetattr(inhtup, Anum_pg_inherits_inhparent,
1275                                     inhtupdesc, &isNull);
1276             qentry->sqe_relid = DatumGetObjectId(d);
1277             
1278             /* put this one on the queue */
1279             DLAddTail(queue, DLNewElem(qentry));
1280             
1281             ReleaseBuffer(buf);
1282         }
1283         
1284         heap_endscan(inhscan);
1285         
1286         /* pull next unvisited relid off the queue */
1287         do {
1288           qe = DLRemHead(queue);
1289           qentry = qe ? (SuperQE*)DLE_VAL(qe) : NULL;
1290
1291             if (qentry == (SuperQE *) NULL)
1292                 break;
1293             
1294             relid = qentry->sqe_relid;
1295             newrelid = true;
1296             
1297            for (elt = DLGetHead(visited); elt; elt = DLGetSucc(elt)) {
1298              vnode = (SuperQE*)DLE_VAL(elt);
1299              if (vnode && (qentry->sqe_relid == vnode->sqe_relid)) {
1300                newrelid = false;
1301                break;
1302              }
1303            }
1304         } while (!newrelid);
1305         
1306         if (qentry != (SuperQE *) NULL) {
1307             
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));
1312             heap_close(rd);
1313             
1314             DLAddTail(visited, qe);
1315
1316             nvisited++;
1317         }
1318     } while (qentry != (SuperQE *) NULL);
1319     
1320     RelationUnsetLockForRead(inhrel);
1321     heap_close(inhrel);
1322     
1323     if (nvisited > 0) {
1324         relidvec = (Oid *) palloc(nvisited * sizeof(Oid));
1325         *supervec = relidvec;
1326
1327         for (elt = DLGetHead(visited); elt; elt = DLGetSucc(elt)) {
1328              vnode = (SuperQE*)DLE_VAL(elt);
1329              *relidvec++ = vnode->sqe_relid;
1330            }
1331           
1332     } else {
1333         *supervec = (Oid *) NULL;
1334       }
1335
1336     return (nvisited);
1337 }
1338
1339 static Oid **
1340 genxprod(InhPaths *arginh, int nargs)
1341 {
1342     int nanswers;
1343     Oid **result, **iter;
1344     Oid *oneres;
1345     int i, j;
1346     int cur[MAXFARGS];
1347     
1348     nanswers = 1;
1349     for (i = 0; i < nargs; i++) {
1350         nanswers *= (arginh[i].nsupers + 2);
1351         cur[i] = 0;
1352     }
1353     
1354     iter = result = (Oid **) palloc(sizeof(Oid *) * nanswers);
1355     
1356     /* compute the cross product from right to left */
1357     for (;;) {
1358         oneres = (Oid *) palloc(MAXFARGS * sizeof(Oid));
1359         memset(oneres, 0, MAXFARGS * sizeof(Oid));
1360         
1361         for (i = nargs - 1; i >= 0 && cur[i] > arginh[i].nsupers; i--)
1362             continue;
1363         
1364         /* if we're done, terminate with NULL pointer */
1365         if (i < 0) {
1366             *iter = NULL;
1367             return (result);
1368         }
1369         
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--)
1373             cur[j] = 0;
1374         
1375         for (i = 0; i < nargs; i++) {
1376             if (cur[i] == 0)
1377                 oneres[i] = arginh[i].self;
1378             else if (cur[i] > arginh[i].nsupers)
1379                 oneres[i] = 0;  /* wild card */
1380             else
1381                 oneres[i] = arginh[i].supervec[cur[i] - 1];
1382         }
1383         
1384         *iter++ = oneres;
1385     }
1386 }
1387
1388 /* Given a type id, returns the in-conversion function of the type */
1389 Oid
1390 typeid_get_retinfunc(Oid type_id)
1391 {
1392     HeapTuple       typeTuple;
1393     TypeTupleForm   type;
1394     Oid             infunc;
1395     typeTuple = SearchSysCacheTuple(TYPOID,
1396                                     ObjectIdGetDatum(type_id),
1397                                     0,0,0);
1398     if ( !HeapTupleIsValid ( typeTuple ))
1399         elog(WARN,
1400              "typeid_get_retinfunc: Invalid type - oid = %ud",
1401              type_id);
1402     
1403     type = (TypeTupleForm) GETSTRUCT(typeTuple);
1404     infunc = type->typinput;
1405     return(infunc);
1406 }
1407
1408 Oid
1409 typeid_get_relid(Oid type_id)
1410 {
1411     HeapTuple       typeTuple;
1412     TypeTupleForm   type;
1413     Oid             infunc;
1414     typeTuple = SearchSysCacheTuple(TYPOID,
1415                                     ObjectIdGetDatum(type_id),
1416                                     0,0,0);
1417     if ( !HeapTupleIsValid ( typeTuple ))
1418         elog(WARN, "typeid_get_relid: Invalid type - oid = %ud ", type_id);
1419     
1420     type = (TypeTupleForm) GETSTRUCT(typeTuple);
1421     infunc = type->typrelid;
1422     return(infunc);
1423 }
1424
1425 Oid
1426 get_typrelid(Type typ)
1427 {
1428     TypeTupleForm typtup;
1429     
1430     typtup = (TypeTupleForm) GETSTRUCT(typ);
1431     
1432     return (typtup->typrelid);
1433 }
1434
1435 Oid
1436 get_typelem(Oid type_id)
1437 {
1438     HeapTuple       typeTuple;
1439     TypeTupleForm   type;
1440     
1441     if (!(typeTuple = SearchSysCacheTuple(TYPOID,
1442                                           ObjectIdGetDatum(type_id),
1443                                           0,0,0))) {
1444         elog (WARN , "type id lookup of %ud failed", type_id);
1445     }
1446     type = (TypeTupleForm) GETSTRUCT(typeTuple);
1447     
1448     return (type->typelem);
1449 }
1450
1451 char
1452 FindDelimiter(char *typename)
1453 {
1454     char            delim;
1455     HeapTuple       typeTuple;
1456     TypeTupleForm   type;
1457     
1458     
1459     if (!(typeTuple = SearchSysCacheTuple(TYPNAME, 
1460                                           PointerGetDatum(typename),
1461                                           0,0,0))) {
1462         elog (WARN , "type name lookup of %s failed", typename);
1463     }
1464     type = (TypeTupleForm) GETSTRUCT(typeTuple);
1465     
1466     delim = type->typdelim;
1467     return (delim);
1468 }
1469
1470 /*
1471  * Give a somewhat useful error message when the operator for two types
1472  * is not found.
1473  */
1474 void
1475 op_error(char *op, Oid arg1, Oid arg2)
1476 {
1477     Type tp1 = NULL, tp2 = NULL;
1478
1479     if (check_typeid(arg1)) {
1480         tp1 = get_id_type(arg1);
1481     } else {
1482         elog(WARN, "left hand side of operator %s has an unknown type, probably a bad attribute name", op);
1483     }
1484
1485     if (check_typeid(arg2)) {
1486         tp2 = get_id_type(arg2);
1487     } else {
1488         elog(WARN, "right hand side of operator %s has an unknown type, probably a bad attribute name", op);
1489     }
1490     
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));
1497 }
1498
1499 /*
1500  * Error message when function lookup fails that gives details of the
1501  * argument types
1502  */
1503 void
1504 func_error(char *caller, char *funcname, int nargs, Oid *argtypes)
1505 {
1506     Type get_id_type();
1507     char p[(NAMEDATALEN+2)*MAXFMGRARGS], *ptr;
1508     int i;
1509         
1510     ptr = p;
1511     *ptr = '\0';
1512     for (i=0; i<nargs; i++) {
1513         if (i) {
1514             *ptr++ = ',';
1515             *ptr++ = ' ';
1516         }
1517         if (argtypes[i] != 0) {
1518             (void) strcpy(ptr, tname(get_id_type(argtypes[i])));
1519             *(ptr + NAMEDATALEN) = '\0';
1520         } else
1521             strcpy(ptr, "opaque");
1522         ptr += strlen(ptr);
1523     }
1524         
1525     elog(WARN, "%s: function %s(%s) does not exist", caller, funcname, p);
1526 }
1527