]> granicus.if.org Git - postgresql/blob - src/backend/parser/parse_query.c
Remove tqual.h includes not needed.
[postgresql] / src / backend / parser / parse_query.c
1 /*-------------------------------------------------------------------------
2  *
3  * parse_query.c--
4  *        take an "optimizable" stmt and make the query tree that
5  *         the planner requires.
6  *
7  * Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $Header: /cvsroot/pgsql/src/backend/parser/Attic/parse_query.c,v 1.25 1997/11/24 05:08:27 momjian Exp $
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include <ctype.h>
16 #include <string.h>
17 #include "postgres.h"
18
19 #include "fmgr.h"
20 #include "access/heapam.h"
21 #include "access/tupmacs.h"
22 #include "utils/builtins.h"
23 #include "utils/elog.h"
24 #include "utils/palloc.h"
25 #include "utils/acl.h"                  /* for ACL_NO_PRIV_WARNING */
26 #include "utils/rel.h"                  /* Relation stuff */
27
28 #include "utils/syscache.h"
29 #include "catalog/pg_type.h"
30 #include "catalog/pg_operator.h"
31 #include "parser/catalog_utils.h"
32 #include "parser/parse_query.h"
33 #include "utils/lsyscache.h"
34
35 #include "nodes/pg_list.h"
36 #include "nodes/primnodes.h"
37 #include "nodes/parsenodes.h"
38 #include "nodes/makefuncs.h"
39
40 static void
41 checkTargetTypes(ParseState *pstate, char *target_colname,
42                                  char *refname, char *colname);
43
44 Oid                *param_type_info;
45 int                     pfunc_num_args;
46
47 /* given refname, return a pointer to the range table entry */
48 RangeTblEntry *
49 refnameRangeTableEntry(List *rtable, char *refname)
50 {
51         List       *temp;
52
53         foreach(temp, rtable)
54         {
55                 RangeTblEntry *rte = lfirst(temp);
56
57                 if (!strcmp(rte->refname, refname))
58                         return rte;
59         }
60         return NULL;
61 }
62
63 /* given refname, return id of variable; position starts with 1 */
64 int
65 refnameRangeTablePosn(List *rtable, char *refname)
66 {
67         int                     index;
68         List       *temp;
69
70         index = 1;
71         foreach(temp, rtable)
72         {
73                 RangeTblEntry *rte = lfirst(temp);
74
75                 if (!strcmp(rte->refname, refname))
76                         return index;
77                 index++;
78         }
79         return (0);
80 }
81
82 /*
83  * returns range entry if found, else NULL
84  */
85 RangeTblEntry *
86 colnameRangeTableEntry(ParseState *pstate, char *colname)
87 {
88         List       *et;
89         List       *rtable;
90         RangeTblEntry *rte_result;
91
92         if (pstate->p_is_rule)
93                 rtable = lnext(lnext(pstate->p_rtable));
94         else
95                 rtable = pstate->p_rtable;
96
97         rte_result = NULL;
98         foreach(et, rtable)
99         {
100                 RangeTblEntry *rte = lfirst(et);
101
102                 /* only entries on outer(non-function?) scope */
103                 if (!rte->inFromCl && rte != pstate->p_target_rangetblentry)
104                         continue;
105
106                 if (get_attnum(rte->relid, colname) != InvalidAttrNumber)
107                 {
108                         if (rte_result != NULL)
109                         {
110                                 if (!pstate->p_is_insert ||
111                                         rte != pstate->p_target_rangetblentry)
112                                         elog(WARN, "Column %s is ambiguous", colname);
113                         }
114                         else
115                                 rte_result = rte;
116                 }
117         }
118         return rte_result;
119 }
120
121 /*
122  * put new entry in pstate p_rtable structure, or return pointer
123  * if pstate null
124 */
125 RangeTblEntry *
126 addRangeTableEntry(ParseState *pstate,
127                                    char *relname,
128                                    char *refname,
129                                    bool inh,
130                                    bool inFromCl)
131 {
132         Relation        relation;
133         RangeTblEntry *rte = makeNode(RangeTblEntry);
134
135         if (pstate != NULL &&
136                 refnameRangeTableEntry(pstate->p_rtable, refname) != NULL)
137                 elog(WARN, "Table name %s specified more than once", refname);
138
139         rte->relname = pstrdup(relname);
140         rte->refname = pstrdup(refname);
141
142         relation = heap_openr(relname);
143         if (relation == NULL)
144         {
145                 elog(WARN, "%s: %s",
146                          relname, aclcheck_error_strings[ACLCHECK_NO_CLASS]);
147         }
148
149         /*
150          * Flags - zero or more from inheritance,union,version or
151          * recursive (transitive closure) [we don't support them all -- ay
152          * 9/94 ]
153          */
154         rte->inh = inh;
155
156         /* RelOID */
157         rte->relid = RelationGetRelationId(relation);
158
159         rte->inFromCl = inFromCl;
160
161         /*
162          * close the relation we're done with it for now.
163          */
164         if (pstate != NULL)
165                 pstate->p_rtable = lappend(pstate->p_rtable, rte);
166
167         heap_close(relation);
168
169         return rte;
170 }
171
172 /*
173  * expandAll -
174  *        makes a list of attributes
175  *        assumes reldesc caching works
176  */
177 List       *
178 expandAll(ParseState *pstate, char *relname, char *refname, int *this_resno)
179 {
180         Relation        rdesc;
181         List       *te_tail = NIL,
182                            *te_head = NIL;
183         Var                *varnode;
184         int                     varattno,
185                                 maxattrs;
186         Oid                     type_id;
187         int                     type_len;
188         RangeTblEntry *rte;
189
190         rte = refnameRangeTableEntry(pstate->p_rtable, refname);
191         if (rte == NULL)
192                 rte = addRangeTableEntry(pstate, relname, refname, FALSE, FALSE);
193
194         rdesc = heap_open(rte->relid);
195
196         if (rdesc == NULL)
197         {
198                 elog(WARN, "Unable to expand all -- heap_open failed on %s",
199                          rte->refname);
200                 return NIL;
201         }
202         maxattrs = RelationGetNumberOfAttributes(rdesc);
203
204         for (varattno = 0; varattno <= maxattrs - 1; varattno++)
205         {
206                 char       *attrname;
207                 char       *resname = NULL;
208                 TargetEntry *te = makeNode(TargetEntry);
209
210                 attrname = pstrdup((rdesc->rd_att->attrs[varattno]->attname).data);
211                 varnode = (Var *) make_var(pstate, refname, attrname, &type_id);
212                 type_len = (int) tlen(get_id_type(type_id));
213
214                 handleTargetColname(pstate, &resname, refname, attrname);
215                 if (resname != NULL)
216                         attrname = resname;
217
218                 /*
219                  * Even if the elements making up a set are complex, the set
220                  * itself is not.
221                  */
222
223                 te->resdom = makeResdom((AttrNumber) (*this_resno)++,
224                                                                 type_id,
225                                                                 (Size) type_len,
226                                                                 attrname,
227                                                                 (Index) 0,
228                                                                 (Oid) 0,
229                                                                 0);
230                 te->expr = (Node *) varnode;
231                 if (te_head == NIL)
232                         te_head = te_tail = lcons(te, NIL);
233                 else
234                         te_tail = lappend(te_tail, te);
235         }
236
237         heap_close(rdesc);
238         return (te_head);
239 }
240
241 static void
242 disallow_setop(char *op, Type optype, Node *operand)
243 {
244         if (operand == NULL)
245                 return;
246
247         if (nodeTag(operand) == T_Iter)
248         {
249                 elog(NOTICE, "An operand to the '%s' operator returns a set of %s,",
250                          op, tname(optype));
251                 elog(WARN, "but '%s' takes single values, not sets.",
252                          op);
253         }
254 }
255
256 static Node *
257 make_operand(char *opname,
258                          Node *tree,
259                          Oid orig_typeId,
260                          Oid true_typeId)
261 {
262         Node       *result;
263         Type            true_type;
264         Datum           val;
265         Oid                     infunc;
266
267         if (tree != NULL)
268         {
269                 result = tree;
270                 true_type = get_id_type(true_typeId);
271                 disallow_setop(opname, true_type, result);
272                 if (true_typeId != orig_typeId)
273                 {                                               /* must coerce */
274                         Const      *con = (Const *) result;
275
276                         Assert(nodeTag(result) == T_Const);
277                         val = (Datum) textout((struct varlena *)
278                                                                   con->constvalue);
279                         infunc = typeid_get_retinfunc(true_typeId);
280                         con = makeNode(Const);
281                         con->consttype = true_typeId;
282                         con->constlen = tlen(true_type);
283                         con->constvalue = (Datum) fmgr(infunc,
284                                                                                    val,
285                                                                                    get_typelem(true_typeId),
286                                                                                    -1 /* for varchar() type */ );
287                         con->constisnull = false;
288                         con->constbyval = true;
289                         con->constisset = false;
290                         result = (Node *) con;
291                 }
292         }
293         else
294         {
295                 Const      *con = makeNode(Const);
296
297                 con->consttype = true_typeId;
298                 con->constlen = 0;
299                 con->constvalue = (Datum) (struct varlena *) NULL;
300                 con->constisnull = true;
301                 con->constbyval = true;
302                 con->constisset = false;
303                 result = (Node *) con;
304         }
305
306         return result;
307 }
308
309
310 Expr       *
311 make_op(char *opname, Node *ltree, Node *rtree)
312 {
313         Oid                     ltypeId,
314                                 rtypeId;
315         Operator        temp;
316         OperatorTupleForm opform;
317         Oper       *newop;
318         Node       *left,
319                            *right;
320         Expr       *result;
321
322         if (rtree == NULL)
323         {
324
325                 /* right operator */
326                 ltypeId = (ltree == NULL) ? UNKNOWNOID : exprType(ltree);
327                 temp = right_oper(opname, ltypeId);
328                 opform = (OperatorTupleForm) GETSTRUCT(temp);
329                 left = make_operand(opname, ltree, ltypeId, opform->oprleft);
330                 right = NULL;
331
332         }
333         else if (ltree == NULL)
334         {
335
336                 /* left operator */
337                 rtypeId = (rtree == NULL) ? UNKNOWNOID : exprType(rtree);
338                 temp = left_oper(opname, rtypeId);
339                 opform = (OperatorTupleForm) GETSTRUCT(temp);
340                 right = make_operand(opname, rtree, rtypeId, opform->oprright);
341                 left = NULL;
342
343         }
344         else
345         {
346                 char       *outstr;
347                 Oid                     infunc,
348                                         outfunc;
349                 Type            newtype;
350
351 #define CONVERTABLE_TYPE(t) (   (t) == INT2OID || \
352                                                                 (t) == INT4OID || \
353                                                                 (t) == OIDOID || \
354                                                                 (t) == FLOAT4OID || \
355                                                                 (t) == FLOAT8OID || \
356                                                                 (t) == CASHOID)
357
358                 /* binary operator */
359                 ltypeId = (ltree == NULL) ? UNKNOWNOID : exprType(ltree);
360                 rtypeId = (rtree == NULL) ? UNKNOWNOID : exprType(rtree);
361
362                 /*
363                  * convert constant when using a const of a numeric type and a
364                  * non-const of another numeric type
365                  */
366                 if (CONVERTABLE_TYPE(ltypeId) && nodeTag(ltree) != T_Const &&
367                         CONVERTABLE_TYPE(rtypeId) && nodeTag(rtree) == T_Const &&
368                         !((Const *) rtree)->constiscast)
369                 {
370                         outfunc = typeid_get_retoutfunc(rtypeId);
371                         infunc = typeid_get_retinfunc(ltypeId);
372                         outstr = (char *) fmgr(outfunc, ((Const *) rtree)->constvalue);
373                         ((Const *) rtree)->constvalue = (Datum) fmgr(infunc, outstr);
374                         pfree(outstr);
375                         ((Const *) rtree)->consttype = rtypeId = ltypeId;
376                         newtype = get_id_type(rtypeId);
377                         ((Const *) rtree)->constlen = tlen(newtype);
378                         ((Const *) rtree)->constbyval = tbyval(newtype);
379                 }
380
381                 if (CONVERTABLE_TYPE(rtypeId) && nodeTag(rtree) != T_Const &&
382                         CONVERTABLE_TYPE(ltypeId) && nodeTag(ltree) == T_Const &&
383                         !((Const *) ltree)->constiscast)
384                 {
385                         outfunc = typeid_get_retoutfunc(ltypeId);
386                         infunc = typeid_get_retinfunc(rtypeId);
387                         outstr = (char *) fmgr(outfunc, ((Const *) ltree)->constvalue);
388                         ((Const *) ltree)->constvalue = (Datum) fmgr(infunc, outstr);
389                         pfree(outstr);
390                         ((Const *) ltree)->consttype = ltypeId = rtypeId;
391                         newtype = get_id_type(ltypeId);
392                         ((Const *) ltree)->constlen = tlen(newtype);
393                         ((Const *) ltree)->constbyval = tbyval(newtype);
394                 }
395
396                 temp = oper(opname, ltypeId, rtypeId, false);
397                 opform = (OperatorTupleForm) GETSTRUCT(temp);
398                 left = make_operand(opname, ltree, ltypeId, opform->oprleft);
399                 right = make_operand(opname, rtree, rtypeId, opform->oprright);
400         }
401
402         newop = makeOper(oprid(temp),           /* opno */
403                                          InvalidOid,/* opid */
404                                          opform->oprresult, /* operator result type */
405                                          0,
406                                          NULL);
407
408         result = makeNode(Expr);
409         result->typeOid = opform->oprresult;
410         result->opType = OP_EXPR;
411         result->oper = (Node *) newop;
412
413         if (!left)
414         {
415                 result->args = lcons(right, NIL);
416         }
417         else if (!right)
418         {
419                 result->args = lcons(left, NIL);
420         }
421         else
422         {
423                 result->args = lcons(left, lcons(right, NIL));
424         }
425
426         return result;
427 }
428
429 Oid
430 find_atttype(Oid relid, char *attrname)
431 {
432         int                     attid;
433         Oid                     vartype;
434         Relation        rd;
435
436         rd = heap_open(relid);
437         if (!RelationIsValid(rd))
438         {
439                 rd = heap_openr(tname(get_id_type(relid)));
440                 if (!RelationIsValid(rd))
441                         elog(WARN, "cannot compute type of att %s for relid %d",
442                                  attrname, relid);
443         }
444
445         attid = nf_varattno(rd, attrname);
446
447         if (attid == InvalidAttrNumber)
448                 elog(WARN, "Invalid attribute %s\n", attrname);
449
450         vartype = att_typeid(rd, attid);
451
452         /*
453          * close relation we're done with it now
454          */
455         heap_close(rd);
456
457         return (vartype);
458 }
459
460
461 Var                *
462 make_var(ParseState *pstate, char *refname, char *attrname, Oid *type_id)
463 {
464         Var                *varnode;
465         int                     vnum,
466                                 attid;
467         Oid                     vartypeid;
468         Relation        rd;
469         RangeTblEntry *rte;
470
471         rte = refnameRangeTableEntry(pstate->p_rtable, refname);
472         if (rte == NULL)
473                 rte = addRangeTableEntry(pstate, refname, refname, FALSE, FALSE);
474
475         vnum = refnameRangeTablePosn(pstate->p_rtable, refname);
476
477         rd = heap_open(rte->relid);
478
479         attid = nf_varattno(rd, attrname);
480         if (attid == InvalidAttrNumber)
481                 elog(WARN, "Invalid attribute %s\n", attrname);
482         vartypeid = att_typeid(rd, attid);
483
484         varnode = makeVar(vnum, attid, vartypeid, vnum, attid);
485
486         heap_close(rd);
487
488         *type_id = vartypeid;
489         return varnode;
490 }
491
492 /*
493  *      make_array_ref() -- Make an array reference node.
494  *
495  *              Array references can hang off of arbitrary nested dot (or
496  *              function invocation) expressions.  This routine takes a
497  *              tree generated by ParseFunc() and an array index and
498  *              generates a new array reference tree.  We do some simple
499  *              typechecking to be sure the dereference is valid in the
500  *              type system, but we don't do any bounds checking here.
501  *
502  *      indirection is a list of A_Indices
503  */
504 ArrayRef   *
505 make_array_ref(Node *expr,
506                            List *indirection)
507 {
508         Oid                     typearray;
509         HeapTuple       type_tuple;
510         TypeTupleForm type_struct_array,
511                                 type_struct_element;
512         ArrayRef   *aref;
513         Oid                     reftype;
514         List       *upperIndexpr = NIL;
515         List       *lowerIndexpr = NIL;
516
517         typearray = exprType(expr);
518
519         type_tuple = SearchSysCacheTuple(TYPOID,
520                                                                          ObjectIdGetDatum(typearray),
521                                                                          0, 0, 0);
522
523         if (!HeapTupleIsValid(type_tuple))
524                 elog(WARN, "make_array_ref: Cache lookup failed for type %d\n",
525                          typearray);
526
527         /* get the array type struct from the type tuple */
528         type_struct_array = (TypeTupleForm) GETSTRUCT(type_tuple);
529
530         if (type_struct_array->typelem == InvalidOid)
531         {
532                 elog(WARN, "make_array_ref: type %s is not an array",
533                          (Name) &(type_struct_array->typname.data[0]));
534         }
535
536         /* get the type tuple for the element type */
537         type_tuple = SearchSysCacheTuple(TYPOID,
538                                                         ObjectIdGetDatum(type_struct_array->typelem),
539                                                                          0, 0, 0);
540         if (!HeapTupleIsValid(type_tuple))
541                 elog(WARN, "make_array_ref: Cache lookup failed for type %d\n",
542                          typearray);
543
544         type_struct_element = (TypeTupleForm) GETSTRUCT(type_tuple);
545
546         while (indirection != NIL)
547         {
548                 A_Indices  *ind = lfirst(indirection);
549
550                 if (ind->lidx)
551                 {
552
553                         /*
554                          * XXX assumes all lower indices non null in this case
555                          */
556                         lowerIndexpr = lappend(lowerIndexpr, ind->lidx);
557                 }
558                 upperIndexpr = lappend(upperIndexpr, ind->uidx);
559                 indirection = lnext(indirection);
560         }
561         aref = makeNode(ArrayRef);
562         aref->refattrlength = type_struct_array->typlen;
563         aref->refelemlength = type_struct_element->typlen;
564         aref->refelemtype = type_struct_array->typelem;
565         aref->refelembyval = type_struct_element->typbyval;
566         aref->refupperindexpr = upperIndexpr;
567         aref->reflowerindexpr = lowerIndexpr;
568         aref->refexpr = expr;
569         aref->refassgnexpr = NULL;
570
571         if (lowerIndexpr == NIL)        /* accessing a single array element */
572                 reftype = aref->refelemtype;
573         else
574 /* request to clip a part of the array, the result is another array */
575                 reftype = typearray;
576
577         /*
578          * we change it to reflect the true type; since the original
579          * refelemtype doesn't seem to get used anywhere. - ay 10/94
580          */
581         aref->refelemtype = reftype;
582
583         return aref;
584 }
585
586 ArrayRef   *
587 make_array_set(Expr *target_expr,
588                            List *upperIndexpr,
589                            List *lowerIndexpr,
590                            Expr *expr)
591 {
592         Oid                     typearray;
593         HeapTuple       type_tuple;
594         TypeTupleForm type_struct_array;
595         TypeTupleForm type_struct_element;
596         ArrayRef   *aref;
597         Oid                     reftype;
598
599         typearray = exprType((Node *) target_expr);
600
601         type_tuple = SearchSysCacheTuple(TYPOID,
602                                                                          ObjectIdGetDatum(typearray),
603                                                                          0, 0, 0);
604
605         if (!HeapTupleIsValid(type_tuple))
606                 elog(WARN, "make_array_ref: Cache lookup failed for type %d\n",
607                          typearray);
608
609         /* get the array type struct from the type tuple */
610         type_struct_array = (TypeTupleForm) GETSTRUCT(type_tuple);
611
612         if (type_struct_array->typelem == InvalidOid)
613         {
614                 elog(WARN, "make_array_ref: type %s is not an array",
615                          (Name) &(type_struct_array->typname.data[0]));
616         }
617         /* get the type tuple for the element type */
618         type_tuple = SearchSysCacheTuple(TYPOID,
619                                                         ObjectIdGetDatum(type_struct_array->typelem),
620                                                                          0, 0, 0);
621
622         if (!HeapTupleIsValid(type_tuple))
623                 elog(WARN, "make_array_ref: Cache lookup failed for type %d\n",
624                          typearray);
625
626         type_struct_element = (TypeTupleForm) GETSTRUCT(type_tuple);
627
628         aref = makeNode(ArrayRef);
629         aref->refattrlength = type_struct_array->typlen;
630         aref->refelemlength = type_struct_element->typlen;
631         aref->refelemtype = type_struct_array->typelem;
632         aref->refelembyval = type_struct_element->typbyval;
633         aref->refupperindexpr = upperIndexpr;
634         aref->reflowerindexpr = lowerIndexpr;
635         aref->refexpr = (Node *) target_expr;
636         aref->refassgnexpr = (Node *) expr;
637
638         if (lowerIndexpr == NIL)        /* accessing a single array element */
639                 reftype = aref->refelemtype;
640         else
641 /* request to set a part of the array, by another array */
642                 reftype = typearray;
643
644         aref->refelemtype = reftype;
645
646         return aref;
647 }
648
649 /*
650  *
651  * make_const -
652  *
653  * - takes a lispvalue, (as returned to the yacc routine by the lexer)
654  *       extracts the type, and makes the appropriate type constant
655  *       by invoking the (c-callable) lisp routine c-make-const
656  *       via the lisp_call() mechanism
657  *
658  * eventually, produces a "const" lisp-struct as per nodedefs.cl
659  */
660 Const      *
661 make_const(Value *value)
662 {
663         Type            tp;
664         Datum           val;
665         Const      *con;
666
667         switch (nodeTag(value))
668         {
669                 case T_Integer:
670                         tp = type("int4");
671                         val = Int32GetDatum(intVal(value));
672                         break;
673
674                 case T_Float:
675                         {
676                                 float64         dummy;
677
678                                 tp = type("float8");
679
680                                 dummy = (float64) palloc(sizeof(float64data));
681                                 *dummy = floatVal(value);
682
683                                 val = Float64GetDatum(dummy);
684                         }
685                         break;
686
687                 case T_String:
688                         tp = type("unknown");           /* unknown for now, will be type
689                                                                                  * coerced */
690                         val = PointerGetDatum(textin(strVal(value)));
691                         break;
692
693                 case T_Null:
694                 default:
695                         {
696                                 if (nodeTag(value) != T_Null)
697                                         elog(NOTICE, "unknown type : %d\n", nodeTag(value));
698
699                                 /* null const */
700                                 con = makeConst(0, 0, (Datum) NULL, true, false, false, false);
701                                 return con;
702                         }
703         }
704
705         con = makeConst(typeid(tp),
706                                         tlen(tp),
707                                         val,
708                                         false,
709                                         tbyval(tp),
710                                         false,          /* not a set */
711                                         false);
712
713         return (con);
714 }
715
716 /*
717  * param_type_init()
718  *
719  * keep enough information around fill out the type of param nodes
720  * used in postquel functions
721  */
722 void
723 param_type_init(Oid *typev, int nargs)
724 {
725         pfunc_num_args = nargs;
726         param_type_info = typev;
727 }
728
729 Oid
730 param_type(int t)
731 {
732         if ((t > pfunc_num_args) || (t == 0))
733                 return InvalidOid;
734         return param_type_info[t - 1];
735 }
736
737 /*
738  * handleTargetColname -
739  *        use column names from insert
740  */
741 void
742 handleTargetColname(ParseState *pstate, char **resname,
743                                         char *refname, char *colname)
744 {
745         if (pstate->p_is_insert)
746         {
747                 if (pstate->p_insert_columns != NIL)
748                 {
749                         Ident      *id = lfirst(pstate->p_insert_columns);
750
751                         *resname = id->name;
752                         pstate->p_insert_columns = lnext(pstate->p_insert_columns);
753                 }
754                 else
755                         elog(WARN, "insert: more expressions than target columns");
756         }
757         if (pstate->p_is_insert || pstate->p_is_update)
758                 checkTargetTypes(pstate, *resname, refname, colname);
759 }
760
761 /*
762  * checkTargetTypes -
763  *        checks value and target column types
764  */
765 static void
766 checkTargetTypes(ParseState *pstate, char *target_colname,
767                                  char *refname, char *colname)
768 {
769         Oid                     attrtype_id,
770                                 attrtype_target;
771         int                     resdomno_id,
772                                 resdomno_target;
773         Relation        rd;
774         RangeTblEntry *rte;
775
776         if (target_colname == NULL || colname == NULL)
777                 return;
778
779         if (refname != NULL)
780                 rte = refnameRangeTableEntry(pstate->p_rtable, refname);
781         else
782         {
783                 rte = colnameRangeTableEntry(pstate, colname);
784                 if (rte == (RangeTblEntry *) NULL)
785                         elog(WARN, "attribute %s not found", colname);
786                 refname = rte->refname;
787         }
788
789 /*
790         if (pstate->p_is_insert && rte == pstate->p_target_rangetblentry)
791                 elog(WARN, "%s not available in this context", colname);
792 */
793         rd = heap_open(rte->relid);
794
795         resdomno_id = varattno(rd, colname);
796         attrtype_id = att_typeid(rd, resdomno_id);
797
798         resdomno_target = varattno(pstate->p_target_relation, target_colname);
799         attrtype_target = att_typeid(pstate->p_target_relation, resdomno_target);
800
801         if (attrtype_id != attrtype_target)
802                 elog(WARN, "Type of %s does not match target column %s",
803                          colname, target_colname);
804
805         if ((attrtype_id == BPCHAROID || attrtype_id == VARCHAROID) &&
806                 rd->rd_att->attrs[resdomno_id - 1]->attlen !=
807         pstate->p_target_relation->rd_att->attrs[resdomno_target - 1]->attlen)
808                 elog(WARN, "Length of %s does not match length of target column %s",
809                          colname, target_colname);
810
811         heap_close(rd);
812 }