8
8
*
9
9
*
10
10
* IDENTIFICATION
11
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.70 2000/02/21 18:47:02 tgl Exp $
11
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.71 2000/02/26 21:11:10 tgl Exp $
12
12
*
13
13
*-------------------------------------------------------------------------
14
14
*/
15
15
16
16
#include "postgres.h"
17
17
18
18
#include "catalog/pg_operator.h"
19
+ #include "catalog/pg_proc.h"
19
20
#include "nodes/makefuncs.h"
20
21
#include "nodes/params.h"
21
22
#include "nodes/relation.h"
29
30
#include "parser/parse_relation.h"
30
31
#include "parser/parse_target.h"
31
32
#include "utils/builtins.h"
33
+ #include "utils/syscache.h"
32
34
33
35
static Node * parser_typecast_constant (Value * expr ,TypeName * typename );
34
36
static Node * parser_typecast_expression (ParseState * pstate ,
@@ -701,6 +703,15 @@ exprTypmod(Node *expr)
701
703
}
702
704
}
703
705
break ;
706
+ case T_Expr :
707
+ {
708
+ int32 coercedTypmod ;
709
+
710
+ /* Be smart about length-coercion functions... */
711
+ if (exprIsLengthCoercion (expr ,& coercedTypmod ))
712
+ return coercedTypmod ;
713
+ }
714
+ break ;
704
715
case T_RelabelType :
705
716
return ((RelabelType * )expr )-> resulttypmod ;
706
717
break ;
@@ -710,6 +721,97 @@ exprTypmod(Node *expr)
710
721
return -1 ;
711
722
}
712
723
724
+ /*
725
+ * exprIsLengthCoercion
726
+ *Detect whether an expression tree is an application of a datatype's
727
+ *typmod-coercion function. Optionally extract the result's typmod.
728
+ *
729
+ * If coercedTypmod is not NULL, the typmod is stored there if the expression
730
+ * is a length-coercion function, else -1 is stored there.
731
+ *
732
+ * We assume that a two-argument function named for a datatype, whose
733
+ * output and first argument types are that datatype, and whose second
734
+ * input is an int32 constant, represents a forced length coercion.
735
+ * XXX It'd be better if the parsetree retained some explicit indication
736
+ * of the coercion, so we didn't need these heuristics.
737
+ */
738
+ bool
739
+ exprIsLengthCoercion (Node * expr ,int32 * coercedTypmod )
740
+ {
741
+ Func * func ;
742
+ Const * second_arg ;
743
+ HeapTuple tup ;
744
+ Form_pg_proc procStruct ;
745
+ Form_pg_type typeStruct ;
746
+
747
+ if (coercedTypmod != NULL )
748
+ * coercedTypmod = -1 ;/* default result on failure */
749
+
750
+ /* Is it a function-call at all? */
751
+ if (expr == NULL ||
752
+ !IsA (expr ,Expr )||
753
+ ((Expr * )expr )-> opType != FUNC_EXPR )
754
+ return false;
755
+ func = (Func * ) (((Expr * )expr )-> oper );
756
+ Assert (IsA (func ,Func ));
757
+
758
+ /*
759
+ * If it's not a two-argument function with the second argument being
760
+ * an int4 constant, it can't have been created from a length coercion.
761
+ */
762
+ if (length (((Expr * )expr )-> args )!= 2 )
763
+ return false;
764
+ second_arg = (Const * )lsecond (((Expr * )expr )-> args );
765
+ if (!IsA (second_arg ,Const )||
766
+ second_arg -> consttype != INT4OID ||
767
+ second_arg -> constisnull )
768
+ return false;
769
+
770
+ /*
771
+ * Lookup the function in pg_proc
772
+ */
773
+ tup = SearchSysCacheTuple (PROCOID ,
774
+ ObjectIdGetDatum (func -> funcid ),
775
+ 0 ,0 ,0 );
776
+ if (!HeapTupleIsValid (tup ))
777
+ elog (ERROR ,"cache lookup for proc %u failed" ,func -> funcid );
778
+ procStruct = (Form_pg_proc )GETSTRUCT (tup );
779
+
780
+ /*
781
+ * It must be a function with two arguments where the first is of
782
+ * the same type as the return value and the second is an int4.
783
+ * Also, just to be sure, check return type agrees with expr node.
784
+ */
785
+ if (procStruct -> pronargs != 2 ||
786
+ procStruct -> prorettype != procStruct -> proargtypes [0 ]||
787
+ procStruct -> proargtypes [1 ]!= INT4OID ||
788
+ procStruct -> prorettype != ((Expr * )expr )-> typeOid )
789
+ return false;
790
+
791
+ /*
792
+ * Furthermore, the name of the function must be the same
793
+ * as the argument/result type's name.
794
+ */
795
+ tup = SearchSysCacheTuple (TYPEOID ,
796
+ ObjectIdGetDatum (procStruct -> prorettype ),
797
+ 0 ,0 ,0 );
798
+ if (!HeapTupleIsValid (tup ))
799
+ elog (ERROR ,"cache lookup for type %u failed" ,
800
+ procStruct -> prorettype );
801
+ typeStruct = (Form_pg_type )GETSTRUCT (tup );
802
+ if (strncmp (NameStr (procStruct -> proname ),
803
+ NameStr (typeStruct -> typname ),
804
+ NAMEDATALEN )!= 0 )
805
+ return false;
806
+
807
+ /*
808
+ * OK, it is indeed a length-coercion function.
809
+ */
810
+ if (coercedTypmod != NULL )
811
+ * coercedTypmod = DatumGetInt32 (second_arg -> constvalue );
812
+ return true;
813
+ }
814
+
713
815
/*
714
816
* Produce an appropriate Const node from a constant value produced
715
817
* by the parser and an explicit type name to cast to.