Joe Conway <m...@joeconway.com> writes:
> What about just TYPE then?

>     SELECT x::TYPE(some_expression) FROM ...
>     SELECT CAST (x AS TYPE(some_expression)) FROM ...

Yeah, that would work.  Quick-hack proof-of-concept patch attached.
Some usage examples in the regression database:

regression=# select pg_typeof(43::type(q1)) from int8_tbl;
 pg_typeof 
-----------
 bigint
 bigint
 bigint
 bigint
 bigint
(5 rows)

regression=# select pg_typeof(43::type(q1/0.0)) from int8_tbl;
 pg_typeof 
-----------
 numeric
 numeric
 numeric
 numeric
 numeric
(5 rows)

regression=# select pg_typeof(43::type(f1)) from point_tbl;
ERROR:  cannot cast type integer to point
LINE 1: select pg_typeof(43::type(f1)) from point_tbl;
                           ^

The main limitation of this patch is that it won't work for call sites
that pass pstate == NULL to LookupTypeName.  There are a fair number
of them, some of which wouldn't care because they could never invoke
this notation anyway, but for others we'd need to do some work to cons
up a suitable pstate.

                        regards, tom lane

diff --git a/src/backend/parser/parse_type.c b/src/backend/parser/parse_type.c
index 6616639..d5d0f73 100644
*** a/src/backend/parser/parse_type.c
--- b/src/backend/parser/parse_type.c
***************
*** 19,25 ****
--- 19,27 ----
  #include "catalog/pg_type.h"
  #include "lib/stringinfo.h"
  #include "nodes/makefuncs.h"
+ #include "nodes/nodeFuncs.h"
  #include "parser/parser.h"
+ #include "parser/parse_expr.h"
  #include "parser/parse_type.h"
  #include "utils/array.h"
  #include "utils/builtins.h"
*************** static int32 typenameTypeMod(ParseState 
*** 52,58 ****
   * found but is a shell, and there is typmod decoration, an error will be
   * thrown --- this is intentional.
   *
!  * pstate is only used for error location info, and may be NULL.
   */
  Type
  LookupTypeName(ParseState *pstate, const TypeName *typeName,
--- 54,61 ----
   * found but is a shell, and there is typmod decoration, an error will be
   * thrown --- this is intentional.
   *
!  * In most cases pstate is only used for error location info, and may be NULL.
!  * However, the TYPE(expression) syntax is not accepted when pstate is NULL.
   */
  Type
  LookupTypeName(ParseState *pstate, const TypeName *typeName,
*************** LookupTypeName(ParseState *pstate, const
*** 143,148 ****
--- 146,188 ----
  							format_type_be(typoid))));
  		}
  	}
+ 	else if (pstate != NULL &&
+ 			 list_length(typeName->typmods) == 1 &&
+ 			 list_length(typeName->names) == 1 &&
+ 			 strcmp(strVal(linitial(typeName->names)), "type") == 0)
+ 	{
+ 		/* TYPE(expression) notation */
+ 		Node	   *typexpr = (Node *) linitial(typeName->typmods);
+ 
+ 		/* XXX should invent a new EXPR_KIND for this, likely */
+ 		typexpr = transformExpr(pstate, typexpr, EXPR_KIND_SELECT_TARGET);
+ 
+ 		/* We needn't bother assigning collations to the expr */
+ 
+ 		/* We use the expression's type/typmod and then throw the expr away */
+ 		typoid = exprType(typexpr);
+ 
+ 		/* If an array reference, return the array type instead */
+ 		if (typeName->arrayBounds != NIL)
+ 			typoid = get_array_type(typoid);
+ 
+ 		if (!OidIsValid(typoid))
+ 		{
+ 			if (typmod_p)
+ 				*typmod_p = -1;
+ 			return NULL;
+ 		}
+ 
+ 		if (typmod_p)
+ 			*typmod_p = exprTypmod(typexpr);
+ 
+ 		/* Duplicative, but I'm too lazy to refactor this function right now */
+ 		tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typoid));
+ 		if (!HeapTupleIsValid(tup)) /* should not happen */
+ 			elog(ERROR, "cache lookup failed for type %u", typoid);
+ 
+ 		return (Type) tup;
+ 	}
  	else
  	{
  		/* Normal reference to a type name */
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to