]> granicus.if.org Git - postgresql/blob - src/backend/parser/parse_coerce.c
c7cbcd37d4375d54f51d6a24fcab5ec4c7fcf6c4
[postgresql] / src / backend / parser / parse_coerce.c
1 /*-------------------------------------------------------------------------
2  *
3  * parse_coerce.c
4  *              handle type coercions/conversions for parser
5  *
6  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.39 2000/03/20 15:42:45 momjian Exp $
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16
17 #include "catalog/pg_proc.h"
18 #include "optimizer/clauses.h"
19 #include "parser/parse_coerce.h"
20 #include "parser/parse_expr.h"
21 #include "parser/parse_func.h"
22 #include "parser/parse_target.h"
23 #include "utils/builtins.h"
24 #include "utils/syscache.h"
25
26 Oid                     DemoteType(Oid inType);
27 Oid                     PromoteTypeToNext(Oid inType);
28
29 static Oid      PreferredType(CATEGORY category, Oid type);
30
31
32 /* coerce_type()
33  * Convert a function argument to a different type.
34  */
35 Node *
36 coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
37                         Oid targetTypeId, int32 atttypmod)
38 {
39         Node       *result;
40
41         if (targetTypeId == InvalidOid ||
42                 targetTypeId == inputTypeId)
43         {
44                 /* no conversion needed */
45                 result = node;
46         }
47         else if (inputTypeId == UNKNOWNOID && IsA(node, Const))
48         {
49                 /*
50                  * Input is a string constant with previously undetermined type.
51                  * Apply the target type's typinput function to it to produce
52                  * a constant of the target type.
53                  *
54                  * NOTE: this case cannot be folded together with the other
55                  * constant-input case, since the typinput function does not
56                  * necessarily behave the same as a type conversion function.
57                  * For example, int4's typinput function will reject "1.2",
58                  * whereas float-to-int type conversion will round to integer.
59                  *
60                  * XXX if the typinput function is not cachable, we really ought
61                  * to postpone evaluation of the function call until runtime.
62                  * But there is no way to represent a typinput function call as
63                  * an expression tree, because C-string values are not Datums.
64                  */
65                 Const      *con = (Const *) node;
66                 Const      *newcon = makeNode(Const);
67                 Type            targetType = typeidType(targetTypeId);
68
69                 newcon->consttype = targetTypeId;
70                 newcon->constlen = typeLen(targetType);
71                 newcon->constbyval = typeByVal(targetType);
72                 newcon->constisnull = con->constisnull;
73                 newcon->constisset = false;
74
75                 if (! con->constisnull)
76                 {
77                         /* We know the source constant is really of type 'text' */
78                         char       *val = textout((text *) con->constvalue);
79                         newcon->constvalue = stringTypeDatum(targetType, val, atttypmod);
80                         pfree(val);
81                 }
82
83                 result = (Node *) newcon;
84         }
85         else if (IS_BINARY_COMPATIBLE(inputTypeId, targetTypeId))
86         {
87                 /*
88                  * We don't really need to do a conversion, but we do need to attach
89                  * a RelabelType node so that the expression will be seen to have
90                  * the intended type when inspected by higher-level code.
91                  */
92                 RelabelType *relabel = makeNode(RelabelType);
93
94                 relabel->arg = node;
95                 relabel->resulttype = targetTypeId;
96                 /*
97                  * XXX could we label result with exprTypmod(node) instead of
98                  * default -1 typmod, to save a possible length-coercion later?
99                  * Would work if both types have same interpretation of typmod,
100                  * which is likely but not certain.
101                  */
102                 relabel->resulttypmod = -1;
103
104                 result = (Node *) relabel;
105         }
106         else if (typeInheritsFrom(inputTypeId, targetTypeId))
107         {
108                 /* Input class type is a subclass of target, so nothing to do */
109                 result = node;
110         }
111         else
112         {
113                 /*
114                  * Otherwise, find the appropriate type conversion function
115                  * (caller should have determined that there is one), and
116                  * generate an expression tree representing run-time
117                  * application of the conversion function.
118                  */
119                 FuncCall   *n = makeNode(FuncCall);
120                 Type            targetType = typeidType(targetTypeId);
121
122                 n->funcname = typeTypeName(targetType);
123                 n->args = lcons(node, NIL);
124                 n->agg_star = false;
125                 n->agg_distinct = false;
126
127                 result = transformExpr(pstate, (Node *) n, EXPR_COLUMN_FIRST);
128
129                 /* safety check that we got the right thing */
130                 if (exprType(result) != targetTypeId)
131                         elog(ERROR, "coerce_type: conversion function %s produced %s",
132                                  typeTypeName(targetType),
133                                  typeidTypeName(exprType(result)));
134
135                 /*
136                  * If the input is a constant, apply the type conversion function
137                  * now instead of delaying to runtime.  (We could, of course,
138                  * just leave this to be done during planning/optimization;
139                  * but it's a very frequent special case, and we save cycles
140                  * in the rewriter if we fold the expression now.)
141                  *
142                  * Note that no folding will occur if the conversion function is
143                  * not marked 'iscachable'.
144                  */
145                 if (IsA(node, Const))
146                         result = eval_const_expressions(result);
147         }
148
149         return result;
150 }
151
152
153 /* can_coerce_type()
154  * Can input_typeids be coerced to func_typeids?
155  *
156  * There are a few types which are known apriori to be convertible.
157  * We will check for those cases first, and then look for possible
158  *      conversion functions.
159  *
160  * Notes:
161  * This uses the same mechanism as the CAST() SQL construct in gram.y.
162  * We should also check the function return type on candidate conversion
163  *      routines just to be safe but we do not do that yet...
164  * We need to have a zero-filled OID array here, otherwise the cache lookup fails.
165  * - thomas 1998-03-31
166  */
167 bool
168 can_coerce_type(int nargs, Oid *input_typeids, Oid *func_typeids)
169 {
170         int                     i;
171         HeapTuple       ftup;
172         Form_pg_proc pform;
173         Oid                     oid_array[FUNC_MAX_ARGS];
174
175         /* run through argument list... */
176         for (i = 0; i < nargs; i++)
177         {
178                 Oid             inputTypeId = input_typeids[i];
179                 Oid             targetTypeId = func_typeids[i];
180
181                 /* no problem if same type */
182                 if (inputTypeId == targetTypeId)
183                         continue;
184
185                 /*
186                  * one of the known-good transparent conversions? then drop
187                  * through...
188                  */
189                 if (IS_BINARY_COMPATIBLE(inputTypeId, targetTypeId))
190                         continue;
191
192                 /* don't know what to do for the output type? then quit... */
193                 if (targetTypeId == InvalidOid)
194                         return false;
195                 /* don't know what to do for the input type? then quit... */
196                 if (inputTypeId == InvalidOid)
197                         return false;
198
199                 /*
200                  * If input is an untyped string constant, assume we can
201                  * convert it to anything except a class type.
202                  */
203                 if (inputTypeId == UNKNOWNOID)
204                 {
205                         if (ISCOMPLEX(targetTypeId))
206                                 return false;
207                         continue;
208                 }
209
210                 /*
211                  * If input is a class type that inherits from target, no problem
212                  */
213                 if (typeInheritsFrom(inputTypeId, targetTypeId))
214                         continue;
215
216                 /*
217                  * Else, try for explicit conversion using functions:
218                  * look for a single-argument function named with the
219                  * target type name and accepting the source type.
220                  */
221                 MemSet(oid_array, 0, FUNC_MAX_ARGS * sizeof(Oid));
222                 oid_array[0] = inputTypeId;
223
224                 ftup = SearchSysCacheTuple(PROCNAME,
225                                                         PointerGetDatum(typeidTypeName(targetTypeId)),
226                                                                    Int32GetDatum(1),
227                                                                    PointerGetDatum(oid_array),
228                                                                    0);
229                 if (!HeapTupleIsValid(ftup))
230                         return false;
231                 /* Make sure the function's result type is as expected, too */
232                 pform = (Form_pg_proc) GETSTRUCT(ftup);
233                 if (pform->prorettype != targetTypeId)
234                         return false;
235         }
236
237         return true;
238 }
239
240 /* coerce_type_typmod()
241  * Force a value to a particular typmod, if meaningful and possible.
242  *
243  * This is applied to values that are going to be stored in a relation
244  * (where we have an atttypmod for the column) as well as values being
245  * explicitly CASTed (where the typmod comes from the target type spec).
246  *
247  * The caller must have already ensured that the value is of the correct
248  * type, typically by applying coerce_type.
249  *
250  * If the target column type possesses a function named for the type
251  * and having parameter signature (columntype, int4), we assume that
252  * the type requires coercion to its own length and that the said
253  * function should be invoked to do that.
254  *
255  * "bpchar" (ie, char(N)) and "numeric" are examples of such types.
256  */
257 Node *
258 coerce_type_typmod(ParseState *pstate, Node *node,
259                                    Oid targetTypeId, int32 atttypmod)
260 {
261         char       *funcname;
262         Oid                     oid_array[FUNC_MAX_ARGS];
263         HeapTuple       ftup;
264
265         /*
266          * We assume that only typmod values greater than 0 indicate a forced
267          * conversion is necessary.
268          */
269         if (atttypmod <= 0 ||
270                 atttypmod == exprTypmod(node))
271                 return node;
272
273         funcname = typeidTypeName(targetTypeId);
274         MemSet(oid_array, 0, FUNC_MAX_ARGS * sizeof(Oid));
275         oid_array[0] = targetTypeId;
276         oid_array[1] = INT4OID;
277
278         /* attempt to find with arguments exactly as specified... */
279         ftup = SearchSysCacheTuple(PROCNAME,
280                                                            PointerGetDatum(funcname),
281                                                            Int32GetDatum(2),
282                                                            PointerGetDatum(oid_array),
283                                                            0);
284
285         if (HeapTupleIsValid(ftup))
286         {
287                 A_Const    *cons = makeNode(A_Const);
288                 FuncCall   *func = makeNode(FuncCall);
289
290                 cons->val.type = T_Integer;
291                 cons->val.val.ival = atttypmod;
292
293                 func->funcname = funcname;
294                 func->args = lappend(lcons(node, NIL), cons);
295                 func->agg_star = false;
296                 func->agg_distinct = false;
297
298                 node = transformExpr(pstate, (Node *) func, EXPR_COLUMN_FIRST);
299         }
300
301         return node;
302 }
303
304
305 /* TypeCategory()
306  * Assign a category to the specified OID.
307  */
308 CATEGORY
309 TypeCategory(Oid inType)
310 {
311         CATEGORY        result;
312
313         switch (inType)
314         {
315                 case (BOOLOID):
316                         result = BOOLEAN_TYPE;
317                         break;
318
319                 case (CHAROID):
320                 case (NAMEOID):
321                 case (BPCHAROID):
322                 case (VARCHAROID):
323                 case (TEXTOID):
324                 case (LZTEXTOID):
325                         result = STRING_TYPE;
326                         break;
327
328                 case (OIDOID):
329                 case (REGPROCOID):
330                 case (INT2OID):
331                 case (INT4OID):
332                 case (INT8OID):
333                 case (FLOAT4OID):
334                 case (FLOAT8OID):
335                 case (NUMERICOID):
336                 case (CASHOID):
337                         result = NUMERIC_TYPE;
338                         break;
339
340                 case (DATEOID):
341                 case (TIMEOID):
342                 case (TIMETZOID):
343                 case (ABSTIMEOID):
344                 case (TIMESTAMPOID):
345                         result = DATETIME_TYPE;
346                         break;
347
348                 case (RELTIMEOID):
349                 case (TINTERVALOID):
350                 case (INTERVALOID):
351                         result = TIMESPAN_TYPE;
352                         break;
353
354                 case (POINTOID):
355                 case (LSEGOID):
356                 case (PATHOID):
357                 case (BOXOID):
358                 case (POLYGONOID):
359                 case (LINEOID):
360                 case (CIRCLEOID):
361                         result = GEOMETRIC_TYPE;
362                         break;
363
364                 case (INETOID):
365                 case (CIDROID):
366                         result = NETWORK_TYPE;
367                         break;
368
369                 case (UNKNOWNOID):
370                 case (InvalidOid):
371                         result = UNKNOWN_TYPE;
372                         break;
373
374                 default:
375                         result = USER_TYPE;
376                         break;
377         }
378         return result;
379 }       /* TypeCategory() */
380
381
382 /* IsPreferredType()
383  * Check if this type is a preferred type.
384  */
385 bool
386 IsPreferredType(CATEGORY category, Oid type)
387 {
388         return type == PreferredType(category, type);
389 }       /* IsPreferredType() */
390
391
392 /* PreferredType()
393  * Return the preferred type OID for the specified category.
394  */
395 static Oid
396 PreferredType(CATEGORY category, Oid type)
397 {
398         Oid                     result;
399
400         switch (category)
401         {
402                 case (BOOLEAN_TYPE):
403                         result = BOOLOID;
404                         break;
405
406                 case (STRING_TYPE):
407                         result = TEXTOID;
408                         break;
409
410                 case (NUMERIC_TYPE):
411                         if (type == OIDOID)
412                                 result = OIDOID;
413                         else if (type == NUMERICOID)
414                                 result = NUMERICOID;
415                         else
416                                 result = FLOAT8OID;
417                         break;
418
419                 case (DATETIME_TYPE):
420                         result = TIMESTAMPOID;
421                         break;
422
423                 case (TIMESPAN_TYPE):
424                         result = INTERVALOID;
425                         break;
426
427                 case (NETWORK_TYPE):
428                         result = INETOID;
429                         break;
430
431                 case (GEOMETRIC_TYPE):
432                 case (USER_TYPE):
433                         result = type;
434                         break;
435
436                 default:
437                         result = UNKNOWNOID;
438                         break;
439         }
440         return result;
441 }       /* PreferredType() */
442
443
444 #ifdef NOT_USED
445 Oid
446 PromoteTypeToNext(Oid inType)
447 {
448         Oid                     result;
449
450         switch (inType)
451         {
452                 case (CHAROID):
453                 case (BPCHAROID):
454                         result = VARCHAROID;
455                         break;
456
457                 case (VARCHAROID):
458                         result = TEXTOID;
459                         break;
460
461                 case (INT2OID):
462                 case (CASHOID):
463                         result = INT4OID;
464                         break;
465
466                 case (INT4OID):
467                 case (INT8OID):
468                 case (FLOAT4OID):
469                         result = FLOAT8OID;
470                         break;
471
472                 case (NUMERICOID):
473                         result = NUMERICOID;
474                         break;
475
476                 case (DATEOID):
477                 case (ABSTIMEOID):
478                         result = TIMESTAMPOID;
479                         break;
480
481                 case (TIMEOID):
482                 case (RELTIMEOID):
483                         result = INTERVALOID;
484                         break;
485
486                 case (BOOLOID):
487                 case (TEXTOID):
488                 case (FLOAT8OID):
489                 case (TIMESTAMPOID):
490                 case (INTERVALOID):
491                 default:
492                         result = inType;
493                         break;
494         }
495         return result;
496 }       /* PromoteTypeToNext() */
497
498
499 Oid
500 DemoteType(Oid inType)
501 {
502         Oid                     result;
503
504         switch (inType)
505         {
506                 case (FLOAT4OID):
507                 case (FLOAT8OID):
508                         result = INT4OID;
509                         break;
510
511                 default:
512                         result = inType;
513                         break;
514         }
515         return result;
516 }       /* DemoteType() */
517
518
519 Oid
520 PromoteLesserType(Oid inType1, Oid inType2, Oid *newType1, Oid *newType2)
521 {
522         Oid                     result;
523
524         if (inType1 == inType2)
525         {
526                 result = PromoteTypeToNext(inType1);
527                 inType1 = result;
528                 *arg2 = result;
529                 return result;
530         }
531
532         kind1 = ClassifyType(inType1);
533         kind2 = ClassifyType(*arg2);
534         if (kind1 != kind2)
535         {
536                 *newType1 = inType1;
537                 *newType2 = inType2;
538                 result = InvalidOid;
539         }
540
541         isBuiltIn1 = IS_BUILTIN_TYPE(inType1);
542         isBuiltIn2 = IS_BUILTIN_TYPE(*arg2);
543
544         if (isBuiltIn1 && isBuiltIn2)
545         {
546                 switch (*arg1)
547                 {
548                         case (CHAROID):
549                                 switch (*arg2)
550                                 {
551                                         case (BPCHAROID):
552                                         case (VARCHAROID):
553                                         case (TEXTOID):
554
555                                         case (INT2OID):
556                                         case (INT4OID):
557                                         case (FLOAT4OID):
558                                         case (FLOAT8OID):
559                                         case (CASHOID):
560
561                                         case (POINTOID):
562                                         case (LSEGOID):
563                                         case (LINEOID):
564                                         case (BOXOID):
565                                         case (PATHOID):
566                                         case (CIRCLEOID):
567                                         case (POLYGONOID):
568
569                                         case (InvalidOid):
570                                         case (UNKNOWNOID):
571                                         case (BOOLOID):
572                                         default:
573                                                 *arg1 = InvalidOid;
574                                                 *arg2 = InvalidOid;
575                                                 result = InvalidOid;
576                                 }
577                 }
578         }
579         else if (isBuiltIn1 && !isBuiltIn2)
580         {
581                 if ((promotedType = PromoteBuiltInType(*arg1)) != *arg1)
582                 {
583                         *arg1 = promotedType;
584                         return promotedType;
585                 }
586                 else if (CanCoerceType(*arg1, *arg2))
587                 {
588                         *arg1 = *arg2;
589                         return *arg2;
590                 }
591         }
592         else if (!isBuiltIn1 && isBuiltIn2)
593         {
594                 if ((promotedType = PromoteBuiltInType(*arg2)) != *arg2)
595                 {
596                         *arg2 = promotedType;
597                         return promotedType;
598                 }
599                 else if (CanCoerceType(*arg2, *arg1))
600                 {
601                         *arg2 = *arg1;
602                         return *arg1;
603                 }
604         }
605
606
607         if (*arg2 == InvalidOid)
608                 return InvalidOid;
609
610         switch (*arg1)
611         {
612                 case (CHAROID):
613                         switch (*arg2)
614                         {
615                                 case (BPCHAROID):
616                                 case (VARCHAROID):
617                 case (BYTEA):
618                                 case (TEXTOID):
619
620                                 case (INT2OID):
621                                 case (INT4OID):
622                                 case (FLOAT4OID):
623                                 case (FLOAT8OID):
624                                 case (CASHOID):
625
626                                 case (POINTOID):
627                                 case (LSEGOID):
628                                 case (LINEOID):
629                                 case (BOXOID):
630                                 case (PATHOID):
631                                 case (CIRCLEOID):
632                                 case (POLYGONOID):
633
634                                 case (InvalidOid):
635                                 case (UNKNOWNOID):
636                                 case (BOOLOID):
637                                 default:
638                                         *arg1 = InvalidOid;
639                                         *arg2 = InvalidOid;
640                                         result = InvalidOid;
641                         }
642         }
643 }
644
645 #endif